Showing posts with label method overloading. Show all posts
Showing posts with label method overloading. Show all posts

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, 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

Wednesday, 6 September 2017

Method Overloading in Java - Answer

The output of the program in Method Overloading in Java:
/opt/tools/java/jdk1.8.0_60/bin/java com.mrbear.App
Hello World!
Brian Goetz
Object
Object
So, from the tutorials1:
Note: Overloaded methods should be used sparingly, as they can make code much less readable.
Quoting2 from the JLS3:
When a method is invoked (§15.12), the name of the class, the name of the method, the number of actual arguments and the compile-time types of the arguments are used, at compile time, to determine the signature of the method that will be invoked (§15.12.2).

References

[1] Oracle The Java™ Tutorials - Defining Methods
https://docs.oracle.com/javase/tutorial/java/javaOO/methods.html
[2] StackOverflow - Overloaded method selection based on the parameters real type
https://stackoverflow.com/questions/1572322/overloaded-method-selection-based-on-the-parameters-real-type
[3] The Java Language Specification, Java SE 8 Edition
https://docs.oracle.com/javase/specs/jls/se8/jls8.pdf

Thursday, 31 August 2017

Method Overloading in Java

package com.mrbear;

/**
 * Hello world!
 *
 */

public class App 
{
    public String getHim(String name) 
    {
        return name;
    }

    public String getHim(Object object) 
    {
        return "Object";
    }

    public static void main( String[] args )
    {
        System.out.println( "Hello World!" );
        App app = new App();
        System.out.println( app.getHim("Brian Goetz"));
        System.out.println( app.getHim((Object) "James Gosling"));
        Object object = "Joshua Bloch";
        System.out.println( app.getHim(object));
    }
}
What does the program above print to its screen?

References

Oracle The Java™ Tutorials - Defining Methods
https://docs.oracle.com/javase/tutorial/java/javaOO/methods.html