Thursday 30 December 2021

Standard RAID levels

I needed to put this information somewhere for easy access.

striping
different parts are on different harddisks, advantage: faster, as accessing several disks at once to gather all, disadvantage: a failure causes the entire data to be unrecoverable.
mirroring
an exact copy over multiple harddisks
parity
parity bits help check that the data is unlikely to have faults, see checksum. Can even be used to in cases to recover from faults.

Different RAID levels

RAID 0
striping, increased performance without parity information, redundancy, or fault tolerance
RAID 1
mirroring, no striping or parity
RAID 2
mostly unused, academic
RAID 3
byte-level striping with a parity disk
RAID 4
block-level striping with a dedicated parity disk
RAID 5
block-level striping with distributed parity
RAID 6
block-level striping with two parity blocks distributed across all member disks
RAID 10
raid 1 and 0 together

The Wikipedia article in the references provides more in depth information.

It is obvious for my use that I am solely interested in RAID 1, the mirroring solution.

My primary reason is the fault tolerance of data. The fact that reads perform better is not a big thing, and the disadvantage of space inefficiency I'll accept.

References

Wikipedia - Standard RAID levels
https://en.wikipedia.org/wiki/Standard_RAID_levels

Thursday 23 December 2021

Assing JsonIgnore on generated files in openapi

I am used to dabbling a bit with .xjb files, in order to get the generated Java files from the XSDs that I want.

I am not soo familiar with how this works when dealing with REST Services, YAML files and openapi.

But I needed it at work, because somehow the FAIL_ON_UNKNOWN_PROPERTIES was set to true, when it shouldn't be.

So a colleague gave me this little solution for in the pom.xml:

<additionalModelTypeAnnotations><![CDATA[ @com.fasterxml.jackson.annotation.JsonIgnoreProperties(ignoreUnknown \u003D true)]]></additionalModelTypeAnnotations>

And I could add this to the "configOptions" of the "configuration" of the "openapi-generator-maven-plugin".

And this worked.

However!

This completely failed to explain why the property was set to true. From what I could gather the generated ObjectMapper provider sets this explicitly to false.

public class JSON implements ContextResolver<ObjectMapper> {
  private ObjectMapper mapper = new ObjectMapper();

  public JSON() {
    this.mapper.setSerializationInclusion(Include.NON_NULL);
    this.mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    this.mapper.configure(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE, false);
    this.mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
    this.mapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
    this.mapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING);
    this.mapper.setDateFormat(new RFC3339DateFormat());
    JsonNullableModule jnm = new JsonNullableModule();
    this.mapper.registerModule(jnm);
    this.mapper.registerModule(new JavaTimeModule());
  }

  public void setDateFormat(DateFormat dateFormat) {
    this.mapper.setDateFormat(dateFormat);
  }

  public ObjectMapper getContext(Class<?> type) {
    return this.mapper;
  }
}

So what was going on?

Luckily a colleague of mine put on his debugging gloves, and started looking into it.

Well, it turns out there was a ContextResolver (like the one above) defined as a @Provider, causing it to be discovered first by the JAX-RS runtime.

Once one is discovered, it will use that one.

And of course it didn't have this setting set to false.

It took a while to find a solution. Neither @Priority nor anything else seemed to have any effect.

In the end, I saw no other option, than to put extra logic in the ContextResolver with the @Provider on it, to not provide an ObjectMapper, if it was any of the objects that concerned my neck of the woods.

Conclusion

CDI is great, and I'm all for it.

The Advantage is that your components in your software are loosely coupled, and this makes things easier.

The Disadvantage, as found out now, is that sometimes things get Injected that you do not expect, and you have a Dickens of a time, finding out where they come from.

References

Openapi Generator Docs - Templating
https://openapi-generator.tech/docs/templating

Thursday 2 December 2021

RESTEASY004590: You must define a @Consumes type on your client method or interface, or supply a default

Just a small note on the above error message.

I was a bit at a loss what I had done wrong.

For example:

@GET
@Path("/{category}")
@Produces("application/json")
public Response getItemDefinition(@PathParam("category") String category, String filterOn);

And I got the following error message:

RESTEASY004590: "You must define a @Consumes type on your client method or interface, or supply a default

It took me a couple of hours to find the problem, but when it hit me, it hit me hard.

Can you spot it?

Solution: I forgot to put in a @QueryParam("filterOn") annotation on the "filterOn" argument. This causes the rest client to interpret the "filterOn" field as being where to put the Body of the response. And for that, it needs a @Consumes annotation, to find out what to put there.

It seems obvious afterwards, but sometimes little mistakes take a lot of time to find.

Thursday 25 November 2021

Replacing many if statements

I recently was asked by a colleague how to get rid of a staggering amount of if statements.

They all seem to have remarkable similarities, as is obvious from the code below.

So I initially thought about changing it to:

Of course it is also possible to create a static Map, that contains Functions. That way, the ValidationMessage instances are only created once. It depends on your needs, really.

In the end, I don't know if the improvement is really that huge.

It's closer together at least, but I feel it could be improved.

Thursday 18 November 2021

Running Mariadb on the Raspberry Pi

This is going to be a small blurb, on what I did to get this working.

Nothing out of the ordinary, really.

$ apt-get install mariadb-server
$ cd /etc/mysql/mariadb.conf.d
$ joe 50-server.cnf
# started vi and replaced 127.0.0.1 with 0.0.0.0
$ service mysql restart

And of course allow the user accounts to access mariadb remotely over the network.

Attention! I'm only doing this locally on a testing server! It's not a great idea to run mariadb connections remotely if you do not have to.

GRANT ALL PRIVILEGES ON *.* TO 'root'@'192.168.100.%' IDENTIFIED BY 'my-new-password' WITH GRANT OPTION;

Thursday 11 November 2021

LetsEncrypt with Webroot

All righty then, time to get working with LetsEncrypt. Again.

So there are several different ways to have LetsEncrypt verify that the domain you wish to have a certificate for is actually yours.

I usually use the webroot version.

But in the past, I found it irksome that I had to let certbot spin up a http server to verify my domain.

What was easier was to have my application server have a part on the filesystem mapped to the Webpages1.

Then certbot could simply use that webroot directory. Which is option 2.

So let's try that.

~]# certbot certonly
Saving debug log to /var/log/letsencrypt/letsencrypt.log

How would you like to authenticate with the ACME CA?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: Spin up a temporary webserver (standalone)
2: Place files in webroot directory (webroot)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
Plugins selected: Authenticator webroot, Installer None
Starting new HTTPS connection (1): acme-v02.api.letsencrypt.org
Please enter in your domain name(s) (comma and/or space separated) (Enter 'c'
to cancel): www.mrbear.org
Cert is due for renewal, auto-renewing...
Renewing an existing certificate for www.mrbear.org
Performing the following challenges:
http-01 challenge for www.mrbear.org
Input the webroot for www.mrbear.org: (Enter 'c' to cancel): /home/jelastic/media
Waiting for verification...
Cleaning up challenges

IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/www.mrbear.org/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/www.mrbear.org/privkey.pem
Your certificate will expire on 2021-11-10. To obtain a new or
tweaked version of this certificate in the future, simply run
certbot again. To non-interactively renew *all* of your
certificates, run "certbot renew"
- If you like Certbot, please consider supporting our work by:

Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le

It will put stuff in /home/jelastic/media/.well-known. Usually in the acme-challenge directory. It'll put some random file in there, for example 366_oWEFaizWeQqOts4KhuTBQcCsFH5dBgG7-jNX32k with a similar string inside, but usually a lot longer.

This file is accessed by the LetsEncrypt server, and if that works, the domain is yours and you get your certificate.

"certbot renew" is preferably easier, as it takes into account the previous configuration settings. Nice for cron jobs.

Also, I found this great script for importing the ssl certificates on the Forums of LetsEncrypt2 for my Java Application Server!

My Payara MicroProfile server uses the following commandline to access the new certificates:

java -server -XX:+UnlockExperimentalVMOptions -javaagent:/java_agent/jelastic-gc-agent.jar=period=300,debug=0 -XX:+UseStringDeduplication -XX:+UseG1GC -Xmaxf0.3 \
-Xminf0.1 -Xmx2048M -Xms32M \
-Djavax.net.ssl.trustStore="/home/jelastic/cacerts.jks" \
-Djavax.net.ssl.keyStore="/home/jelastic/keystore.jks" \
-Djavax.net.ssl.trustStorePassword="changeit" \
-Djavax.net.ssl.keyStorePassword="changeit" \
-jar ./payara-micro-5.2021.1.jar --postbootcommandfile ./postboot --addlibs ../libs/mariadb-java-client-2.5.2.jar --port 8080 --sslport 8743 \
--deploy ../release/mrbear.war \
--deploy ../release/mrbearportal-2.0.9.war \

Please pay special attention to the four "javax.net.ssl.*" properties that take care of the SSL properties.

And that's it!

References

[1] MyBlog - Alternate docroots
http://randomthoughtsonjavaprogramming.blogspot.com/search/label/alternate%20docroot
[2] LetsEncrypt Community Forum - Importing LetsEncrypt into Java and Glassfish
https://community.letsencrypt.org/t/importing-letsencrypt-into-java-and-glassfish/9711/11
Java Keytool Essentials: Working with Java Keystores - Mitchell Anicas
https://www.digitalocean.com/community/tutorials/java-keytool-essentials-working-with-java-keystores

Wednesday 3 November 2021

JFall 2021

After all the stuff with Corona and everything, there's finally going to be a genuine JFall in Ede (again) at the Pathe on Thursday, the fourth of November.

It's the first conference where I can go to "in the flesh" so to speak.

The previous one was a virtual conference, which was fun, but I do look forward to having social interaction face-to-face.

References

NLJUG - JFall 2021
http://jfall.nl/

Thursday 28 October 2021

Kotlin, AssertJ and Overloads

So, I ran into a novell problem recently.

I've got the following Java code, which is a basic POJO following the Java Bean conventions:

  private Integer orderNumber;

  private Integer amount;

  public Integer getOrderNumber() 
  {
    return orderNumber;
  }

  public void setOrderNumber(Integer orderNumber) 
  {
    this.orderNumber = orderNumber;
  }

  public Integer getAmount() 
  {
    return amount;
  }

  public void setAmount(Integer amount) 
  {
    this.amount = amount;
  }

Now, I've got a Kotlin1 class that I use for testing, and I am using AssertJ2 as the library for comparing values.

At first try it looked very easy:

assertThat(get.orderNumber).isNull()
assertThat(get.amount).isNull()

This caused a serious java.lang.NullPointerException: get.orderNumber must not be null.

This is a typical Kotlin message, as Kotlin has Null safety built in. Kotlin is telling me that orderNumber may not be null. In the Java code it all seems fine, it's an Integer and nulls are allowed.

So what went wrong here?

Well, if I check out which assertThat is being used, I end up at:

  public static AbstractIntegerAssert<?> assertThat(int actual) {
    return new IntegerAssert(actual);
  }

And so we see now that it'll automatically be downgraded to a java int. Which Kotlin intercepts as being bad-form when using nulls.

So how to fix this?

I came up with the following little ugly hack:

assertThat(get.orderNumber as Any?).isNull()
assertThat(get.amount as Any?).isNull()

Now, all of a sudden, the method called is:

  public static <T> ObjectAssert<T> assertThat(T actual) {
    return new ObjectAssert(actual);
  }

Which is what I want.

Unfortunately this is neither obvious nor clear.

It's the price we pay for many many overloaded methods. Sometimes the compiler will just pick the wrong one.

However, to be fair, in most cases the Compiler picks the right one. This is just one of those cases, where we have to be specific.

There's some references to tickets on Kotlin in the References.

Addendum

The proper way to fix this problem, is of course, to add an @Nullable to the method in de Java class (if you can). This causes Kotlin to automatically assume it can be "null", and it therefore does not need casting.

P.S. I'm trying out a new code formatter3. It's nice in so far that it does not require additional installs, but it does add spans and styling directly. Pick your poison, I guess.

References

[1] Kotlin Language
https://kotlinlang.org/
[2] AssertJ
https://assertj.github.io/doc/
[3] Source code beautifier / syntax highlighter – convert code snippets to HTML « hilite.me
http://hilite.me/
YouTrack IntelliJ - Argument of Java platform boxed type resolves to primitive parameter method signature from Kotlin
https://youtrack.jetbrains.com/issue/KT-21285
GitHub AssertJ - isNull assertion broken in Kotlin when calling a Java class #1115
https://github.com/assertj/assertj-core/issues/1115

Thursday 21 October 2021

Netlify and Github pages

So, I created a small Angular app (a website basically), self contained (for now), that works nicely. I used it to help me in learning Croatian, so it's basically a word app. There's plenty of them online, but none that I liked.

I wanted to access the app from my phone, which means it needs to be hosted somewhere.

Nginx on Raspberry Pi

Initially I installed Nginx on my Raspberry Pi at home

Started it using the usual /lib/systemd/system/nginx.service.

Configurations as usual in /etc/nginx.

I uploaded the Angular files in /var/www/html and that worked fine.

The IP adress is http://192.168.2.4/, only accessible locally from my own network, of course.

But, of course I wanted it available for travelling as well (and didn't want to expose my Raspberry Pi to the Terrors of the Internet).

There's plenty of ways to make the Angular website available.

Github Pages

I could have hosted the Angular files in a repository on Github.pages1 and then accessed them from there. That would work.

But I didn't feel like doing that2.

It would mean making a repository with the name of the project or my account name and putting all the build Angular files there.

Netlify

I choose to go with Netlify. They have a free tier and play well with Github.

As soon as I commit new changes to my Angular project in github3, Netlify picks up those changes, builds the Angular project and deploys it to the website4.

I was very impressed!

It's a good example of Continuous Delivery5.

So, the steps were basically as follows:

  • sign up at Netlify with your github account
  • create a new site from Git
  • pick a repository
  • specify site and build settings and all that.

Some notes

Automatically a hostname is generated for you, something like belnazzar-troublesome3.netlify.app. If that is not to your liking you can change the hostname of the site (just the first part) or even get a authentic hostname alltogether. (But I didn't need that.)

I did have the outputpath originally set to dist/polygo in my Angular app, and I changed that to "dist". Otherwise everyone has to go to "polygo.netlify.app/polygo" all the time.

Then there's the fact that Angular wants to do its own routing, but it cannot do that if you do not end up at de index.html page. For instance if you go directly to https://polygo.netlify.app/wordgame instead of https://polygo.netlify.app/.

Luckily the folks at Netlify have taken this into account6.

I created an src/_redirects file for redirecting everything to /index.html, so Angular can take over the routing.

I changed angular.json by adding src/_redirects on the assets array.

And bingo, it worked!

What's next?

Well, it suffices for my needs right now, but as I have the REST resources just committed in the Github Repository, expanding on the data is a bit of a hassle. I need to commit data changes to the repo, and Netlify redeploys.

It would be nice to be able to use a database.

I found some information on it at [7] on using Netlify Functions in combination with FaunaDB, but that'll have to wait for another time.

References

[1] Github Pages
https://pages.github.com/
[2] Netlify.com - Github Pages vs Netlify
https://www.netlify.com/github-pages-vs-netlify/
[3] Polygo on Github
https://github.com/maartenl/polygo
[4] Polygo at Netilfy
https://polygo.netlify.app/wordgame
[5] Jetbrains - Continuous Integration vs. Delivery vs. Deployment
https://www.jetbrains.com/teamcity/ci-cd-guide/continuous-integration-vs-delivery-vs-deployment/
[6] Netlify Docs - Angular on Netlify
https://docs.netlify.com/configure-builds/common-configurations/angular/
[7] Building Serverless CRUD apps with Netlify Functions and FaunaDB
https://www.netlify.com/blog/2018/07/09/building-serverless-crud-apps-with-netlify-functions-faunadb/

Thursday 14 October 2021

My Printer's Gone!

I was missing my printer. Turns out I could just add it in the Printer Settings in Linux.

I don't know why it was suddenly missing, though.

Perhaps it happened during an upgrade of Fedora Core.

I know I installed all the required drivers some time ago.

Oh well. I thought it was something serious. It's nice to be disappointed.

References

MyBlog - Installing Printer Driver in Fedora for Epson ET-3750
https://randomthoughtsonjavaprogramming.blogspot.com/2021/03/installing-printer-driver-in-fedora-for.html

Thursday 7 October 2021

Running Payara Micro on Java 11 via GraalVM on Docker on Jelastic

Boy, that title was a mouth full.

Now if you want more information on Docker, you can check out reference [3]. Or if you're looking for Java 11 GraalVM Dockerimages suitable for Jelastic, you can check out [1] and [2].

This blog is more about the contents of the Dockerimage than Docker itself.

GraalVM

Well, I've been using Jelastic for a while now, and it suited my needs, until it didn't.

They provide GraalVM out of the box, but not the Java 11 version yet.

I was using a Payara Server image for Jelastic, and I had good results just installing GraalVM on the Image afterwards and run Payara using that, but I was looking for something a little more lean.

Sooo, in short, I used the GraalVM image used by Jelastic as a baseline in my Docker image (jelastic/javaengine:graalvm-21.0.0.2).

Then it was just install the JDK11 version of GraalVM and create my Image.

Less troublesome than I thought it would be.

Payara Micro

So Payara Micro is awesome. The way this differs from Microprofile, is that Microprofile contains only Microprofile and the Payara Micro basically seems to be a small Payara server run from the command line. It is based off the Payara Embedded Web release. See [4].

So there's basically two things:

  1. you run it from the command line using java and the payara-micro-5.2020.7.jar
  2. you provide a postboot file containing the settings

Example

Let's try an example.

The example basically runs a Payara Micro instance, with some wars deployed and a JDBC library for connecting to a database.

All configuration of the database connection is done using the afore mentioned postboot file.

Some notes on the postboot file.

  • I am not interested in Hazelcast, so I turned this off. The main result should be faster startup.
  • I added eclipselink.target-database to the jdbc string, otherwise the JDBC driver will identify itself as MariaDB driver, and it is unknown. You can immediately tell by the following error message in the log:

    Not able to detect platform for vendor name [MariaDB[10.4.20-MariaDB, 10]]. Defaulting to [org.eclipse.persistence.platform.database.DatabasePlatform]. The database dialect used may not match with the database you are using. Please explicitly provide a platform using property "eclipselink.target-database".

  • I also added a config property to it. Microprofile (which is included) has support for Configuration. And it's great!

Secure Socket Layer

There's a simple self signed SSL Certificate included in the Payara Micro, which works fine, unless, like me, you wish to use a genuine SSL Certificate.

The idea here is to expand on the command line (see above in run.sh) with SSL options, for example as follows:

  • -Djavax.net.ssl.trustStore="/home/jelastic/cacerts.jks"
  • -Djavax.net.ssl.keyStore="/home/jelastic/keystore.jks"
  • -Djavax.net.ssl.trustStorePassword="changeit"
  • -Djavax.net.ssl.keyStorePassword="changeit"

References

[1] Dockerhub - my jelastic graal with jdk 11 docker image
https://hub.docker.com/r/maartenl22/jelasticgraaljdk11
[2] Github - Docker file
https://github.com/maartenl/jelasticgraaljdk11
[3] MyBlog - Docker
https://randomthoughtsonjavaprogramming.blogspot.com/2021/06/docker.html
[4] Payara Micro Documentation
https://docs.payara.fish/community/docs/documentation/payara-micro/payara-micro.html
Releases - graalvm/graalvm-ce-builds
https://github.com/graalvm/graalvm-ce-builds/releases
How to install GraalVM on Linux with alternatives
https://gist.github.com/ricardozanini/fa65e485251913e1467837b1c5a8ed28
GraalVM - GraalVM Community Images
https://www.graalvm.org/docs/getting-started/container-images/
Github - graalvm-ce
https://github.com/orgs/graalvm/packages/container/package/graalvm-ce

Saturday 2 October 2021

JDK17: The next Long Term Support Java

Due as a production release on September 14, Java Development Kit (JDK) 17 will be a long-term-support (LTS) release, with extended support from Oracle expected for several years.

Now I just have to wait for all my libs and tools to be compatible.

References

Oracle Press Release: Oracle Releases Java 17
https://www.oracle.com/news/announcement/oracle-releases-java-17-2021-09-14/
Oracle Blogs - Java - The arrival of Java 17!
https://blogs.oracle.com/java/post/announcing-java17
TechGeekNext - JDK 17 Arrived - What's new features released in Java 17
https://www.techgeeknext.com/java/java17-features
InfoWorld - JDK 17: The new features in Java 17
https://www.infoworld.com/article/3606833/jdk-17-the-new-features-in-java-17.html

Monday 6 September 2021

Finding out where your class comes from

Sometimes it happens that we're stuck in ClassPath hell. Which means that there's two conflicting dependencies, both putting the same class (but different!) on the classpath, and it's random which one will be first.

There's a way to find out.

References

GitHub - my Gists
https://gist.github.com/maartenl/00663f1d1dbaf4dd0792e864a9074e65

Thursday 5 August 2021

Angular in Strict Mode

So I wanted to use the new "strict" settings when compiling my Angular apps.

This is a small blog on the issues I ran into.

Luckily, similar issues can be found when you move over to Kotlin from Java.

I've posted links in the References below of blog posts that delve deeper into the strict setting.

Solutions

  1. initialize variables
  2. add | undefined or | null and add if-then checks everywhere
  3. use ?. syntax (mostly in templates)

Problems

Check everything, because suddenly we have values everywhere (perhaps due to point 1 above) and checks for existing values now always turn true.

Where a null value was previously sent appropriately to the rest service, suddenly it has an initial value of '', and now the parsing of the JSON fails.

References

InDepthDev - Bulletproof Angular. Angular strict mode explained
https://indepth.dev/posts/1402/bulletproof-angular
THE ART OF SIMPLICITY - Angular 10–Strict mode
https://bartwullems.blogspot.com/2020/09/angular-10strict-mode.html
Guide for Type-safe Angular
https://medium.com/lacolaco-blog/guide-for-type-safe-angular-6e9562499d93
MW Experts - Strict rules for new Angular project
https://medium.com/most-wanted-experts/strict-rules-for-new-angular-project-7cbd32f37163

Friday 23 July 2021

Kotlin : the "by" keyword in Interface/Class Delegation

I'm writing it down here, because I looked at it and didn't understand what was going on.

The "by" keyword in Kotlin is used for two things:

  1. Interface/Class delegation1
  2. Delegated properties2

Delegation is a good alternative to inheritance (thought this last statement really requires explanation, or a blogpost on it's own,... or, dare I say, a study on when to use inheritance and when to use delegation and when to use the good old composition).

With the "by" keyword it is possible to use delegation, without adding to the amount of boilerplate that this entails and without having to use inheritance.

Let us give an example using Stubs in testing.

Stubs

So, it seems it's possible to create a simple stub for a test, by using an interface and an implementation and overriding a method (for stubbing). Naturally, the method is not "overridden", but using delegation it is simply implemented in the test, and all other methods are redirected to the stub (which is the delegation class).

So, the syntax1 looks like this:

val/var <propertyname>: <Type> by <expression>

So, for example if you wish to use a delegation (instead of inheritance) in your stub for an OrderService interface.

You create a OrderServiceStub, which makes an empty implementation of all the methods in de OrderService.

And then you can create an anonymous class, indicating which method you wish to change to benefit the test.

It looks like this:

Notice that the anonymous inner class does not inherit from OrderServiceStub (in Kotlin classes are final by default, and we'd like to keep it that way).

The way this can be done without boilerplace in Kotlin is as follows:

So in the second test we're creating an anonymous class, which implements the interface automatically by delegating to the Stub. The only thing we need to change is the method we're interested in.

The next blogpost, we will be diving deeper into Delegated Properties, which looks a little more complicated but is based on the same ideas.

References

[1] Kotlin Language Reference - Delegation
https://kotlinlang.org/docs/delegation.html
[2] Kotlin Language Reference - Delegated properties
https://kotlinlang.org/docs/delegated-properties.html
[3] StackOverflow - What does 'by' keyword do in Kotlin?
https://stackoverflow.com/questions/38250022/what-does-by-keyword-do-in-kotlin

Thursday 24 June 2021

Hibernate's @FetchProfile

I came across some hibernate annotations in the source code at work, to be more specific "@FetchProfile". I hadn't seen that one before, so I went onto the Internet.

In my case it was used for Batch jobs, in which all associations were always fetched, and needed to be changed to "EAGER", during the session.

References

A Java geek — Hibernate hard facts - Part 6
https://blog.frankel.ch/hibernate-hard-facts/6/
JBoss Docs Hibernate - 20.1.7. Fetch profiles
https://docs.jboss.org/hibernate/core/3.5/reference/en/html/performance.html#performance-fetching-profiles
JBoss Docs Hibernate Annotations - 2.4.12. Fetch profiles
https://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/#d0e3524

Wednesday 16 June 2021

Docker

$ sudo systemctl start docker

Configuration

I am on a low bandwith thing, so needed to add max-concurrent-uploads to the /etc/docket/daemon.json, otherwise I got connection timeouts. (default is 5)

{
  "experimental": false,
  "max-concurrent-uploads": 1,
  "data-root": "/mnt/docker" }

I've since moved the docker data directory ("data-root") to a separate mount ("/mnt/docker"), as it takes up a deal of space.

See reference 1.

Basics

docker pull dockerimageurl
downloads a particular image, probably from Docker Hub
docker images
can show you all the images the docker has at its disposal
docker container create
creates a new container based on an image
docker run --rm -i -t -p portext:portint dockerimageurl
start running a new container (-d is detached, -p is portmap, -i keep STDIN open even if not attached , -t allocates a pseudo-TTY, --rm removes container on exit ), basically does all of the previous steps if necessary

Administration

docker inspect dockerimageurl
shows low level information on the running container
docker exec <container-id> cat /data.txt
run a single command on the container, can be run as long as the master process (pid 1) is running
docker ls [-a]
seems to be exactly the same as ps
docker ps [-a]
list docker containers (-a for aboth started and stopped)
docker attach <the-container-id>
stttach to a running docker container with the ID from docker ps. Convenient if you've run it "detatched".
docker stop <the-container-id>
stop docker container with the ID from docker ps
docker rm <the-container-id>
remove docker container
docker rmi <the-image-id>
removes an image

Examples

Simply running an image can be done with:

docker run --rm -i -t -p 80:8080 -p 443:8181 --name jelasticgraaljdk17 jelastic/javaengine:graalvm-21.0.0.2

"--name" is a nice option to prevent docker from assigning meaningless auto-generated names to your containers.

It will help tremendously if we could look at how an original image was made. This is possible with the history command.

docker history jelastic/javaengine:graalvm-21.0.0.2

Add --no-trunc to show entire command lines.

For example in the example, it will show the following:

IMAGECREATEDCREATED BYSIZE
72627645230f12 days ago24.4MB
<missing> 12 days ago /bin/sh -c #(nop) WORKDIR /etc/init.d 0B
<missing> 12 days ago /bin/sh -c #(nop) LABEL actions=webAccess a… 0B
<missing> 12 days ago /bin/sh -c #(nop) EXPOSE 21 22 25 80 8080 0B

Added 443 8743 to the exposed ports in my new image.

Creating your own image

docker build
build a new container image based on a Dockerfile. (-t is tag)
docker commit c16378f943fe rhel-httpd:latest
docker login -u YOUR-USER-NAME
logging into the Docker hub
docker tag c16378f943fe YOUR-USER-NAME/name
tag your image appropriately before pushing it to the repo
docker push imagename:tag
pushes an image to a remote Docker repository. If you do not provide a tag, it will automatically become "latest".

Examples

cd ../graalvm
docker build -t maartenl22/jelasticgraaljdk11:latest -t maartenl22/jelasticgraaljdk11:v0.1 .
cd ../karchan
docker build -t maartenl22/karchan:latest -t maartenl22/karchan:v2.0.8 .

Check that this worked by running:

docker run --name graalvm --rm -i -t -p 8080:8080 -p 8743:8743 maartenl22/jelasticgraaljdk11:latest
docker run --name karchan --rm -i -t -p 8080:8080 -p 8743:8743 maartenl22/karchan:latest

Pushing your image to Docker Hub

Examples

docker build -t maartenl22/jelasticgraaljdk11 .
docker build -t maartenl22/karchan .
docker image ls

First do this, just to make sure:

docker logout
docker login
docker push maartenl22/jelasticgraaljdk11
docker push maartenl22/karchan

You should see both jelasticgraaljdk11 and registry-host:5000/maartenl22/jelasticgraaljdk11 listed.

You should see both karchan and registry-host:5000/maartenl22/karchan listed.

docker run --name karchan -cap-add=NET_ADMIN --rm -i -t -p 8080:8080 -p 8743:8743 jelasticgraaljdk11:latest

The -cap-add=NET_ADMIN is necessary to see the iptables configuration.

cd /home/jelastic
java -jar payara-micro-5.2021.1.jar --port 80 --sslport 443 jakartaee-8-project.war

Portainer

Portainer is a docker image containing a simple server that interfaces with the Docker deamon. With it you can get a good view of what Docker is running and what containers and images are available and all that.

Also attaching a terminal via de website is possible. Very nice.

docker volume create portainer_dataa
docker run -d -p 8000:8000 -p 9000:9000 --name=portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_dataa:/data portainer/portainer-ce

When starting it for the first time, and surfing to localhost:9000, you can add an administrator user.

It works great to get a good overview about what's going on.

Hello, world.

References

[1] GuguWeb - HOW TO MOVE DOCKER DATA DIRECTORY TO ANOTHER LOCATION ON UBUNTU
https://www.guguweb.com/2019/02/07/how-to-move-docker-data-directory-to-another-location-on-ubuntu/
Jelastic - Build software stack container image for private PaaS
https://jelastic.com/blog/build-software-stack-container-image-private-paas/
Jelastic - Building custom containers
https://docs.jelastic.com/building-custom-container/
Docker - Custom container deployment
https://docs.jelastic.com/custom-containers-deployment/
Docker - Installing fedora
https://docs.docker.com/engine/install/fedora/
Docker - Reference manuals
https://docs.docker.com/reference/
Portainer
https://www.portainer.io/
Youtube - Intro to Docker [with Java Examples]
https://youtu.be/FzwIs2jMESM
Dockerhub - my jelastic graal with jdk 11 docker image
https://hub.docker.com/r/maartenl22/jelasticgraaljdk11
Github - Docker file
https://github.com/maartenl/jelasticgraaljdk11

Thursday 3 June 2021

Aristotle's Wheel Paradox - To Infinity and Beyond

I love Paradoxes, and I recently accidentally stumbled upon a new one (which is actually really old, so, actually only new for me) on the youtubes.

References

Wikipedia - Artistle's wheel paradox
https://en.wikipedia.org/wiki/Aristotle%27s_wheel_paradox
Youtube - Aristotle's Wheel Paradox - To Infinity and Beyond
https://youtu.be/mrVg9GM5h7Q

Thursday 27 May 2021

Java Comparison for Beginners

So, we all know about boxing and unboxing in Java, and the fact that we have "int" which is a primitive, and we have "Integer" which is an Object.

So, when comparing "int", we can use ==. When comparing "Integer" it's better to use .equals().

It may seem like it works, but this is only for small values that are cached in the JVM. Do not rely on that!

See the following example:

So, what happens when using different comparisons? let's explain the test below:

It works fine! Exactly as we would expect.

In short, according to the JLS1, first unboxing takes place, in order to be able to compare two primitives.

Then a widening primitive conversion2 takes place, in this case the int will be converted up to type long.

Now the comparison can take place.

References

[1] JLS Java 16 - 15.20. Relational Operators
https://docs.oracle.com/javase/specs/jls/se16/html/jls-15.html#jls-15.20
[2] JLS Java 16 - 5.6. Numeric Contexts
https://docs.oracle.com/javase/specs/jls/se16/html/jls-5.html#jls-5.6

Thursday 20 May 2021

Java Inheritance for Beginners

Just a little exercise, to get things in perspective.

Besides, I thought I was being clever, but made a rookie mistake and it just didn't work1.

Something similar can be found in Java Puzzlers2.

During compile time a decision is made which method is to be called (§15.12)3. During compile time it is as yet unknown which type/subtype it will be. The compiler tries to be as specific as possible, but in this case, it will just be Animal in the second testcase.

References

[1] Stackoverflow - Overloaded method selection based on the parameter's real type
https://stackoverflow.com/questions/1572322/overloaded-method-selection-based-on-the-parameters-real-type
[2] Java Puzzlers - Traps, Pitfalls, and Corner Cases - By Joshua Bloch and Neal Gafter
http://www.javapuzzlers.com/
[3] JLS 16 - 15.12. Method Invocation Expressions
https://docs.oracle.com/javase/specs/jls/se16/html/jls-15.html#jls-15.12

Thursday 13 May 2021

Method determination ignored variable arity and implicit auto boxing/unboxing

Recently encountered a tweet by Simon Ritter. With a response by Brian Goetz.

Simon ritter:

TIL that determining method applicability initially ignores variable arity and implicit auto boxing/unboxing.

This code prints "long, long", which surprised me.

See section 15.12.2. of the Java Language Spec.

Brian Goetz:

The three-phase overload selection algorithm was added at the time autoboxing and varargs was added; if we had not done so, adding autoboxing/varargs would have been source-incompatible as it would have changed existing overload selection decisions.

The unfortunate consequences of trying to be backwards compatible.

References

[1] Java Language Spec 11 - 15.12. Method Invocation Expressions
https://docs.oracle.com/javase/specs/jls/se11/html/jls-15.html#jls-15.12

Thursday 6 May 2021

USB-C Hubs for MacBooks - Review

So I had the opportunity to checkout no less than three USB-C HUBS for my MacBook Pro.

Belkin Thunderbolt 3 Dock-Pro

An expensive beast at 259 euros, but works like a charm.

Also comes with an Ethernet port, can charge the MacBook Pro at the same time (without using the white charging block I got with my MacBook).

The thunderbolt cable provided with the Belkin is long and very good.

The thunderbolt cable provided with the Belkin for connecting between the MacBook Pro to the Belkin is the one you should use. Other cables likely won't work.

May take some time getting ready when first turned on.

First time use may have issues with the Ethernet, but the company has a fix for that on their website1.

Satechi USB-C MultiPort V2

Not that expensive at 80 euros.

The USB-C cable for conecting to the MacBook Pro is really short.

It requires the white charging block.

However, I'm continually having problems with external monitors. The MacBook reports that I'm still using the monitor from work (with 1920x1080) when working at home (with 2560x1440).

Quite likely, this problem is because I'm waking up the macBook from hibernate, and it doesn't query the external monitor when it wakes up?

I've posted some EDID settings below.

The only thing that seemed to work was to restart my Mac, and immediately close the lid. Somehow that causes the MacBook to reevaluate what external monitors it has, and get the proper EDID settings.

Vitamo 8-in-1 USB-C Hub Adapter

At 37 euros by far the cheapest, and it shows.

It requires the white charging block.

It suffers from the same problems with External Monitors as the Satechi.

The Ethernet port, while initially working perfectly, seems to have suffered from some mishaps as I've had no connection twice in a row now.

The HDMI port, whilst working fine originally, now has a tendency to cause the external monitor to lose the connection occasionally.

Remove the cable and reinsterting it seems to fix the problem.

Conclusion

The Belkin is fantastic, but expensive.

The Satechi seems fine.

The Vitamo is cheap, but you get what you pay for.

I do find these simple USB-C hub to be very low-quality plastic thingies, and they tend to "dangle" next to the MacBook.

I read on the Internet (make of that what you will) that all these lower-cost USB-C hubs tend to use the same cheap chipset.

EDID

Problems with external monitors seem to be effecting quite a large number of people when dealing with MacBooks.

I can apparently export the EDID settings using an app called SwitchResX.

The EDID settings of the Dell 1424H from work:

https://gist.github.com/maartenl/e39efad1899d80371306311b24c2573e

The EDID settings of the HP 27G from home:

https://gist.github.com/maartenl/4b317b337deb7b26cbbf27e70a300d00

Checking things

In order to check things, like, what resolution is my Mac running, you can use Spotlight Search for look for "About This Mac". Thie app can show the used Displays in the tab Displays (second tab).

Of course you can always check your monitor settings themselves.

Some magic happens in the "Displays" configuration settings on the MacBook, when you press "Command" function. When pressed the "Gather windows" button changes into "Detect Displays". When pressed and clicking on "Scaled" shows many more monitor resolutions than normal.

References

[1] Belkin - Troubleshooting ethernet connectivity on the Belkin F4U095
https://www.belkin.com/us/support-article?articleNum=304840
StackExchange - How do I get my monitor to run at the correct resolution reliably?
https://apple.stackexchange.com/questions/374982/how-do-i-get-my-monitor-to-run-at-the-correct-resolution-reliably
StackExchange - Incorrect external monitor resolution detected, true resolution not available
https://apple.stackexchange.com/questions/344608/incorrect-external-monitor-resolution-detected-true-resolution-not-available

Thursday 29 April 2021

Jelastic CLI

Just some notes of mine on how to install Jelastic command line tools and how to connect to your Jelastic provider1 2.

A little disappointed that installing the command line tools doesn't let me know that it "succeeded". It just returns my command prompt, with no indication what it did.

I thought it had quit unexpectedly.

The first call to the API will require authentication.

As I have enabled two-factor authentication, it's best if I create a personal access token3.

Success!

The absolute main reason to use it, I think, is the ability to move my static IP address of a Jelastic Node to another Node4, creating seamless upgrades.

I've tried it, and it's awesome.

I don't even have to explain how it works here. It's simple and the guide is fine.

References

[1] Payara platform and Jelastic PAAS
[2] Jelastic - Jelastic CLI Overview
https://docs.jelastic.com/cli/
[3] Jelastic - Personal Access Tokens
https://docs.jelastic.com/personal-access-tokens/
[4] Jelastic - CLI Tutorial: Public IPs (External Addresses) Swap
https://docs.jelastic.com/cli-ip-swap/

Thursday 22 April 2021

Alternate Docroots

I have a pressing need to allow files to be accessed that are static.

Unfortunately, there's a web application sitting on my root context ("/").

So I need to define alternate docroots1.

Unfortunately, this seems to be a specific Glassfish or Payara configuration.

As it is bad form, to put this in my code base (who knows where my wars will end up someday), it's better if I put it in the domain.xml file.

That way it's application server dependent, instead of war dependent.

However, I have found the following2:

virtual server's alternate docroots are considered only if a request does not map to any of the web modules deployed on that virtual server. A web module's alternate docroots are considered only once a request has been mapped to that web module.

Which means that an alternative docroot on the virtual server is basically unusable if you have a webapplication situated at your context root "/".

As an example consider the following:

Microprofile Config

Now, I don't much like putting pathnames in my web modules. So I was wondering if it's possible to change that by using Microprofile Config.

And it is3!

It will look something like this:

Other application servers

Other application servers have similar options (of which I know nothing).

In WildFly or the EAP4, it is possible to add another file handler and another location to the undertow subsystem in standalone.xml.

References

[1] A programmer's blog - Map an external directory into Glassfish
http://harkiran-howtos.blogspot.com/2009/08/map-external-directory-into-glassfish.html
[2] Sun GlassFish Enterprise Server v3 Prelude Developer's Guide - Alternate Document Roots
https://docs.oracle.com/cd/E19776-01/820-4496/geqpl/index.html
[3] Payara Community Documentation - Types of variable references
https://docs.payara.fish/community/docs/5.2020.7/documentation/payara-server/server-configuration/var-substitution/types-of-variables.html
[4] StackOverflow - How to configure Wildfly to serve static content (like images)?
https://stackoverflow.com/questions/22684037/how-to-configure-wildfly-to-serve-static-content-like-images

Thursday 15 April 2021

Learning Kotlin

Well, trying to get to grips with Kotlin, and actually write something with it.

And I have a two day Kotlin course to attend.

I also managed to pick up Programming Kotlin by Venkat Subramanian.

It also helps that I have been pair programming with a Colleague who is already well versed in the language.

References

Blog - My First Kotlin Reference
https://randomthoughtsonjavaprogramming.blogspot.com/2020/06/kotlin.html
Programming Kotlin
enkat Subramanian

Thursday 8 April 2021

Getting a Native Query Typed in JPA

Recently I tried using a native query to return a result.

This worked fine, except that I had to cast the resulting list to the appropriate list. (which is ugly).

Like so:

List<Room> rooms = (List<Room>) getEntityManager().createNativeQuery(AdminRoom.GET_SEARCH_QUERY)
        .setParameter(1, "%" + description + "%")
        .setMaxResults(pageSize)
        .setFirstResult(offset)
        .getResultList();

I thought I could use the same thing I use daily in my createNamedQuery calls, namely add the appropriate class behind it.

Like so:

List<Room> rooms = (List<Room>) getEntityManager().createNativeQuery(AdminRoom.GET_SEARCH_QUERY, Room.class)...

Unfortunately, the return value of the createNativeQuery method is "Query" which is totally untyped, contrary to "TypedQuery", which I would have liked.

Of course, people have already found this out when I looked it up1.

The API seems to be a little wonky in that area.

References

[1] StackOverflow - entityManager.createNativeQuery does not return a typed result
https://stackoverflow.com/questions/54109546/entitymanager-createnativequery-does-not-return-a-typed-result

Thursday 1 April 2021

StreamingOutput : streaming large json responses in REST API

So I had to move a large number of database objects into a JSON response, and I was looking for a neat way to do it.

Originally, I already had the idea of having the database generate JSON responses for me. You can find more information on this here1.

But then I thought it would make sense to, instead of loading all those json strings from the database in memory, streaming them to the JSON generator in my REST Service.

It looked quite easy.

Database streaming

Now, I found out that instead of getResultList(), I could use getResultStream(). Unfortunately, the default implementation of getResultStream() just delegates to getResultList(), which doesn't help at all2.

Also, there seems to be a number of other pitfalls to fall into as well2, 3. So, my first attempt displayed here just might be flawed, or might be flawed if you're using something other than MariaDB.

My attempt at a scrolling cursor, instead of just dumping the entire thing in our lap.

Streaming as a REST Service

So I found some information on how to do this at [4].

@GET
@Produces(
{
  "application/json"
})
public Response findAll(@Context UriInfo info)
{
  StreamingOutput stream = StreamerHelper.getStream(getEntityManager(), AdminItem.GET_QUERY);   return Response.ok(stream).build();
}

I think I could use the Fetch way5 on the client side, but in my case it's not needed.

References

[1] Using SQL to generate JSON output
http://randomthoughtsonjavaprogramming.blogspot.com/2020/01/using-sql-to-generate-json-output.html
[2] JPA 2.2’s new getResultStream() method and how you should NOT use it
https://thorben-janssen.com/jpa-2-2s-new-stream-method-and-how-you-should-not-use-it/
[3] Vlad Mihalcea - Hibernate performance tuning tips
https://vladmihalcea.com/hibernate-performance-tuning-tips/
[4] Response streaming between JAX-RS and Web-Components (Part 1)
https://schoeffm.github.io/posts/response-streaming-between-jaxrs-and-webcomponents-part1/
[5] Response streaming between JAX-RS and Web-Components (Part 2)
https://schoeffm.github.io/posts/response-streaming-between-jaxrs-and-webcomponents-part2/

Friday 26 March 2021

Changing Git Remote Urls

I recently switched network settings, and now my IPs have changed, and my remotes no longer match.

A quick google1 for the right syntax is all I needed.

mrbear@labtop mygitrepository % git remote -v
origin ssh://mrbear@10.0.0.1:/home/mrbear/mygitrepository (fetch)
origin ssh://mrbear@10.0.0.1:/home/mrbear/mygitrepository (push)

So my setup changed ips from 10.0.0.0 network to 192.168.2.0 network.

% git remote set-url origin ssh://mrbear@192.168.2.1:/home/mrbear/mygitrepository
mrbear@labtop mygitrepository % git remote -v
origin ssh://mrbear@192.168.2.1:/home/mrbear/mygitrepository (fetch)
origin ssh://mrbear@192.168.2.1:/home/mrbear/mygitrepository (push)

Verification is always a good thing.

% git pull
mrbear@192.168.2.1's password:
remote: Enumerating objects: 19, done.
remote: Counting objects: 100% (19/19), done.
remote: Compressing objects: 100% (16/16), done.
remote: Total 16 (delta 8), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (16/16), 93.48 KiB | 3.89 MiB/s, done.
From ssh://192.168.2.1:/home/mrbear/mygitrepository
7f41ba8..e7de4cf master -> origin/master
Updating 7f41ba8..e7de4cf
Fast-forward

References

[1] Managing remote repositories
https://docs.github.com/en/github/getting-started-with-github/managing-remote-repositories

Thursday 4 March 2021

Installing Printer Driver in Fedora for Epson ET-3750

Just some information in case I need to reinstall the drivers sometime in the future.

The following is in my log:

[ 650.114340] usb 2-1.8: new high-speed USB device number 5 using ehci-pci
[ 650.196888] usb 2-1.8: New USB device found, idVendor=04b8, idProduct=1130, bcdDevice= 1.00
[ 650.196896] usb 2-1.8: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[ 650.196900] usb 2-1.8: Product: ET-3750 Series
[ 650.196903] usb 2-1.8: Manufacturer: EPSON
[ 650.196907] usb 2-1.8: SerialNumber: 583445553036353185
[ 650.245866] usblp 2-1.8:1.1: usblp0: USB Bidirectional printer dev 5 if 1 alt 0 proto 2 vid 0x04B8 pid 0x1130
[ 650.245915] usbcore: registered new interface driver usblp

I found some information at [1].

[root@mrbear Downloads]# dnf install lsb

Lsb is required, or it starts complaining when trying to install the rpm packages.

rpm -i epson-inkjet-printer-escpr2-1.1.25-1lsb3.2.x86_64.rpm
rpm -i epson-printer-utility-1.1.1-1lsb3.2.x86_64.rpm

Via LPADMIN

# lpadmin -p [PRINTER_NAME] -v [DEVICE_URI] -P [PPD_FILE] -E
# lpadmin -p et3750 -v "usb://EPSON/ET-3750%20Series?serial=583445553036353185&interface=1" -P /opt/epson-stuff-this-and-that-en.ppd.gz -E

Via Webbrowser

This works if you have attached the printer via USB cable.

You can access CUPS via a webbrowser at http://localhost:631.

As administrator ask for "Add printer".

The list shows EPSON ET-3750 Series (EPSON ET-3750 Series).

Name: EPSON_ET-3750_Series
Description: EPSON ET-3750 Series
Location:
Connection: usb://EPSON/ET-3750%20Series?serial=583445553036353185&interface=1
Sharing: Do Not Share This Printer
Make: Epson
Model: (lsb/usr/epson-inkjet-printer-escpr2/Epson/Epson-ET-3750_Series-epson-inkjet-printer-escpr2.ppd.gz)
Epson ET-3750 Series - epson-inkjet-printer-escpr2 1.1.25-1lsb3.2 (Seiko Epson Corporation LSB 3.2) (en, nl, fr, de, it, ja, pt, es, ko, ru, zh_TW, zh_CN)
Or Provide a PPD File:

References

[1] Epson - Epson ET-3750
https://epson.com/Support/Printers/All-In-Ones/ET-Series/Epson-ET-3750/s/SPT_C11CG20201?review-filter=Linux

Thursday 11 February 2021

Using SQL Developer to visualise Geometry data

I was looking to see if shapes were incorporated inside other shapes.

I could have let the database check this, but sometimes it is very insightful to have a visual representation.

It turns out, SQL Developer facilitates this.

If you select a geometry field in your table, and right click and select [Display geometry shape], you'll get a nice little window indicating the shape.

Sometimes this is greyed out. The solution for this is to click on [Edit] in the menu above, and select [Map View]. This will "initialize" stuff, and then it's no longer greyed out.

Map View

The map view is very convenient, if you wish to show multiple shapes and how they interact.

To get started, select under "View", "Map view" and you are presented with a new subwindow.

Pressting the "New" button in the Map View window, you can just enter a query that returns a geometry, give it a name, proper colouring, and you're good to go.

In the example above, there's two queries, one for a point and one for a shape. The Map View displays them both, and you can even deactive one or the other in the table on the right.

Very convenient in my work, I say.

References

[1] ThatJeffSmith - Visualize Spatial Data with SQL Developer
https://www.thatjeffsmith.com/archive/2011/12/visualize-spatial-data-with-sql-developer/

Wednesday 3 February 2021

Using CDI to extend functionality

I recently wanted to change the behaviour of the framework.

Now, usually this means having to change code in the framework, but as this is something I'd rather not do, I found a way around this.

The framework, just as the code I write, uses CDI.

So it was a simple case of telling CDI to inject my Bean, instead of the Framework Bean.

And it worked right out of the box.

I was pretty surprised.

References

Contexts & Dependency Injection for Java
http://cdi-spec.org/

Monday 18 January 2021

Using Optional to prevent NullPointers In TrainWrecks

I don't usually post or comment on StackOverflow, but I thought I'd give it a stab.

I was thinking of using Optional.ofNullable to be able to "map" my way out of a sequence of NullPointers more or less cleanly, but I failed to get something nice.

I really like the solution give in the Answer, it's not something that would naturally occur to me.

References

StackOverflow - Using Optional to prevent NullPointers In TrainWrecks
https://stackoverflow.com/questions/65631864/using-optional-to-prevent-nullpointers-in-trainwrecks

Friday 8 January 2021

Branch Prediction

I accidentally came across the following question1 (and consequent answer) on StackOverflow, and it is awesome!

I knew these things existed, but never put two and two together.

Unfortunately, of course, if you have to sort the array prior to the work to gain the speed, you're unlikely to speed up the process "in total".

References

[1] StackOverflow - Why is processing a sorted array faster than processing an unsorted array?
https://stackoverflow.com/questions/11227809/why-is-processing-a-sorted-array-faster-than-processing-an-unsorted-array
Wikipedia - Branch predictor
https://en.wikipedia.org/wiki/Branch_predictor