How to install Open JDK on Mac OS

Use SDK Man: https://sdkman.io/install

$ curl -s "https://get.sdkman.io" | bash

Follow the instructions on the screen.

$ source "$HOME/.sdkman/bin/sdkman-init.sh"

Press ENTER.

$ sdk version
#should respond with sdkman 5.x ...

To install a JDK with it (this is OpenJDK 15):

$ sdk list java
$ sdk install java 15.0.1-open
...
$ sdk default java 15.0.1-open
$ sdk use java 15.0.1-open

You should use OpenJDK because by using Oracle you will have to pay a commercial fee, at least in commercial environments. This will eventually cause companies to abandon Java in worst case.

Java equals and hash code Contract

If two objects are equal, the hash code must be the same.

But the same hash code does not guarantee that two objects are equal.

Code example for a proper implementation:

 @Override
    public final boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof MyClassOrInterface)) {
            //some do prefer #getClass but I don't
            return false;
        }
        MyClassOrInterface that = (MyClassOrInterface) o;
        return Objects.equals(this.hashCode(), that.hashCode()) &&
                Objects.equals(name, that.name) &&
                Objects.equals(sessionId, that.sessionId);
    }

    @Override
    public final int hashCode() {
        return Objects.hash(name, sessionId);
    }

Java – How to verify EQUALS and HASH code contracts

Use this:

<!-- Maven -->
<dependency>
    <groupId>nl.jqno.equalsverifier</groupId>
    <artifactId>equalsverifier</artifactId>
    <version>3.0.3</version>
    <scope>test</scope>
</dependency>

Write your test:

@Test
public void onEqualsTrueTheHashCodeHasToBeTheSame() {
    EqualsVerifier.forClass(Foo.class).verify();
}

How to solve Java List add – throwing java.lang.UnsupportedOperationException

Symptom:

You try to add an object to a list. But you get an Exception:

java.lang.UnsupportedOperationException
	at java.base/java.util.AbstractList.add(AbstractList.java:153)

Cause:

List<SomeEvent> eventList = Arrays.asList(event);
//not working, because the list size is fixed

Solution:

List<SomeEvent> eventList = new ArrayList<>(Arrays.asList(event));
//working, because the list size is NOT fixed

Of course, reading the Javadock of public static <T> List<T> asList(…) would have revealed it in advance:

/**
 * Returns a fixed-size list backed by the specified array.

;-D

Calculation Errors and Mistakes in Java – How to calculate correctly

This is a real world example on which money was lost by client. This was not explicable, but I managed to analyze and reconstruct the problem.

The Code you are about to see is NOT the production code, but my own reconstruction of it, with a means to show the problem.

 @Test
    public void testWrong() {

        // GIVEN
        final Integer price = -595;
        final Integer someUnit = 90;

        // WHEN
        int multiplicationResult = price * someUnit;
        // = -53550


        Integer resultAmount = multiplicationResult / 100;
        // = -535
        // …Division failed,
        // decimal places ignored...

        // THEN
        assertTrue(resultAmount == -535);
        // Wrong. Correct: -536.
    }

The specification on which the primitives and float are defined do not allow a correct calculation (mistake 1).

Although primitives cause the most trouble in calculation programming for many people, this example would have worked, if the return type of „multiplicationResult“ would be a double (mistake 2).

But experience shows that even these basics are quite often the main reason for calculation mistakes in Java, so I always recommend a certain way of calculating to avoid them, which I will show below.

@Test
public void testCorrect() {

        // GIVEN
        final Integer price = -595;
        final Integer someUnit = 90;
        // WHEN
        BigDecimal priceBD = new BigDecimal(price);
        BigDecimal someUnitBD = new BigDecimal(someUnit);
        BigDecimal hundred = new BigDecimal(100);

        BigDecimal multiplicationResult = priceBD.multiply(someUnitBD); // = -53550

        // = -535.5 - looks great.
        BigDecimal resultAmountBD = multiplicationResult.divide(hundred);


        final int noDecimalPlaces = 0;
        // rounding mode is vital to get a correct result
        final RoundingMode roundingMode = RoundingMode.HALF_UP;

        // do not forget to define the decimal places...0
        BigDecimal result = resultAmountBD.setScale(noDecimalPlaces, roundingMode);

        // THEN
        assertThat(result.toBigInteger().intValue(), equalTo(-536)); // Correct!

    }

The Big Decimal is calculated by using a String representation. Calculation is done piece by piece. Thus, the specification of float and primitives in general cannot interfere and cause calculation mistakes through number spaces, computing practices of the CPU etc..

Standard IEEE 754 defines Exception Handling and number spaces. It defines, how float and double is processed. Floating Points are meant to approach a certain precision, but without being 100% accurate. It is equivalent to Math/Analysis lambda, which is marking a barrier to come close to, which is never really reached (infinite lambda for instance).

In Summary:

  • Division, multiplication must be done by using a wrapper like BigDecimal.
  • Decimal Places have to be defined
  • Rounding modes have to be defined
  • In case that multiple systems are calculating together (e.g. bank or any other financial institution or software), a contract has to be agreed on. The contract must state how many decimal places are to be used (retail does often use 3 decimal places but only shows 2 on the displays in the shelves). Also the rounding mode plays a vital role in calculation.
  • Never use primitives, even if you are sure that in ‚your specific case‘ it is sufficient
  • Also experienced programmers make these mistakes, which is why I am posting this in my Blog.

Why Spring Webflux is better than HttpClient – HowTo in Java

A lot of Boilerplate Code can be avoided.

AND: it is reactive, non-blocking.

Example (really, an example) – the ‚old way‘:

        HttpPost request = new HttpPost("http://www.someurl.de");
        request.setHeader(HttpHeaders.ACCEPT, ContentType.APPLICATION_JSON.getMimeType());
        request.setHeader(HttpHeaders.CONTENT_TYPE, 
                                              ContentType.APPLICATION_JSON.getMimeType());

        String json = someJsonConverter.toJson(someRequestDto);
        HttpEntity stringEntity = new StringEntity(json, ContentType.APPLICATION_JSON);
        request.setEntity(stringEntity);

        try {
            CloseableHttpResponse response2 = httpclient.execute(request);

            if (HttpStatus.SC_CREATED != response2.getStatusLine().getStatusCode()) {
                //TODO eventually handle http statuus additionally
                return returnHandleAndDoNotThrow();
            }
            SomeResponseDto responseDto = (SomeResponseDto) 
                someJsonConverter.toDto(EntityUtils.toString(response.getEntity()), 
                                                               SomerResponseDto.class);
            return Optional.ofNullable(responseDto);
        } catch (IOException e) {
            return Optional.empty();;
        }

The new way:

        Function<UriBuilder, URI> function = uriBuilder ->  
                                                  uriBuilder.path("/somePath").build();
        return client.post()
                .uri(function)
                .accept(MediaType.APPLICATION_JSON)
                .contentType(MediaType.APPLICATION_JSON)
                .body(Mono.just(someDtoInstance), SomeDto.class)
                .exchange()
                .block()
                .bodyToFlux(someResponseDto.class);
//any errors, status codes are handled by a filter which you can define as follows:

Howto:

I am using Spring Boot for this, so I do have a Config class.

import ...
import org.springframework.context.annotation.Bean;
import reactor.core.publisher.Mono;
import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.context.annotation.Configuration;


@Configuration
public class WebClientConfig {

    //Create the Bean for Autowiring
    @Bean
    public WebClient webClient() {
        return WebClient.builder().filter(someStatusHandlingFilter()).build();
    }
    
    //Handle status codes
    public static ExchangeFilterFunction someStatusHandlingFilter() {
        return ExchangeFilterFunction.ofResponseProcessor(clientResponse -> {
            if ((clientResponse.statusCode().is4xxServerError() 
                || clientResponse.statusCode().is5xxClientError())) {
                return clientResponse                        
                        .bodyToMono(SomeException.class)
                        .flatMap(errorBody -> {
                            return Mono.error(someExceptionToLog);
                        });
            } else {
                return Mono.just(clientResponse);
            }
        });
    }
}

Maven:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-integration</artifactId>
            <version>your latest version goes here</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
            <version>your latest version goes here</version>
        </dependency>