Showing posts with label constructor. Show all posts
Showing posts with label constructor. Show all posts

Saturday, 27 July 2024

jakarta.json.bind.JsonbException: Cannot create instance of a record: class SomeClass, Multiple constructors found.

So I've been trying to use Java Records as data holders for JSONB serialisation and deserialisation. And it works well, until I encountered the following:

jakarta.json.bind.JsonbException: Cannot create instance of a record: class SomeClass, Multiple constructors found.

It turns out, I can put in an annotation @JsonbCreator on it, as explained in reference [1].

It just takes a bit of work, as I cannot put the annotation on top of a record class, it needs to be put on a constructor. The way this works, is to create a compact constructor in the record.

The compact constructor is usually used to put in some sort of validation in the record class upon instantiation, but here we need it for the annotation @JsonbCreate.

Brian Goetz in the comments of reference [2] indicates that this is the proper way to do it.

Unfortunately, it causes one of those "empty constructors" messages of SonarLint.

Warning:(31, 10) Remove this redundant constructor which is the same as a default one.

I assume SonarLint will fix this eventually.

For completeness, my code:

public record AdminItem(Integer id,
                        String belongsto,
                        Long room,
                        String shopkeeper,
                        String owner,
                        LocalDateTime creation)
{

  @JsonbCreator
  public AdminItem
  {
    // empty constructor, because I need to put the annotation @JsonbCreator somewhere.
  }

  public AdminItem(Item item)
  {
    this(item.getId(), 
        item.getBelongsTo() == null ? null : item.getBelongsTo().getName(),
        item.getRoom() == null ? null : item.getRoom().getId(),
        null,
        item.getOwner() == null ? null : item.getOwner().getName(),
        item.getCreation());
  }

}

References

[1] Carlos Chacin - 💾 Java 14 Records 🐞 with JakartaEE JSON-B
https://carloschac.in/2020/04/20/java-records-jsonb/
[2] StackOverflow - Constructor annotation on java records
https://stackoverflow.com/questions/67168624/constructor-annotation-on-java-records

Monday, 5 February 2018

Useless private constructors

public class NullArgumentException extends ApplicationException {

  private NullArgumentException(String message) 
  {
    super(message);
  }

  private NullArgumentException(String message, Throwable cause) 
  {
    super(message, cause);
  }

  public NullArgumentException(String field) 
  {
    super(String.format("No value for field %s", field));
  }

}

I found the code written above in our code base somewhere. My IntellIJ immediately started complaining about it.

I read through it, and then I started complaining about it too.

It looks like someone thought Constructors in Java are inherited, and wished to prevent people from instantiating the class using those constructors.

I removed the offending constructors and made the code a little cleaner.

Thursday, 22 June 2017

MessageBodyWriter not found!

I got the following (unhelpful) message in my server log, when I changed some of my Java classes that are translated to JSON (and vice versa).
Severe: MessageBodyWriter not found for media type=application/json, type=class java.util.ArrayList, genericType=java.util.List

Turns out that I added a specific constructor to one of my Java classes, effectively removing the unspecified Default Constructor that Java always adds.

This default constructor is however essential to the proper working of JSON-Java mapping.

Thursday, 21 April 2016

Constructors, Javadoc and Inheritance

I recently had the problem that I defined some very good javadoc documentation on a constructor in one of my generic classes that is inherited a lot.

The documentation, however, is never propagated to subclasses, because constructors are not inherited1.

It is too bad that I already have to duplicate Constructors in my subclasses, but now I have to duplicate the documentation as well?

Right now, the best solution I can think of is to add a "@see" link to the appropriate super constructor. Like so:

There is a feature request/bug2 defined to expand the {inheritedDoc} to also work on constructors. But it has not seen any love for a long time.

References

[1] StackOverflow - Why is inheritedDoc not defined on constructors?
http://stackoverflow.com/questions/14848999/why-is-inheriteddoc-not-defined-on-constructors
[2] JDK-4810216 : Allow {@inheritDoc name} for constructors
http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4810216

Thursday, 1 October 2015

Calling super constructors

So, a constructor in a subclass, if it needs to call the constructor in the super class, is required to do this in the first line of the body of the constructor1.

If it does not, Java will insert a call to the default super constructor. If it does not exist, you get a compile time error.

So, what if you need to do things, before the super call takes place?

As the object is in the process of being constructed (that's why it's called a constructor), the object is in a non-valid state. This likely explains why the language designers felt that a call to another constructor should be the first part of the body of a constructor.

Well, apparently the only solution is to do everything you need inside the expressions that take the place of the super constructor arguments.

I was forced to do just that in my MudWebException.

So, there's an easy workaround, but it feels clumsy.

Take care not to access any of the methods or properties of the object that is being constructed, as it is in a non-valid state. As a matter of fact, I think it's a really bad idea to call methods in the object from within your constructor.

References

[1] JLS 8.0 Section 8.8.7. Constructor Body
https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#d5e14100
StackOverflow - Why does this and super have to be the first statement in a constructor?
http://stackoverflow.com/questions/1168345/why-does-this-and-super-have-to-be-the-first-statement-in-a-constructor

Monday, 12 December 2011

Implicit Default Constructor - good or bad?

Everyone who knows Java, knows that if you do not define a constructor in a class, the default constructor is implicitly created by the compiler.[1]

Is this a good thing or a bad thing?

Good thing:

  • we need a constructor to instantiate an object, and if we forget to make one we can simply use the default constructor.

Bad thing:
  • creating a new constructor with arguments, automatically will make the compiler NOT create the implicit default constructor, perhaps causing breakage in your program/application.

So, should we do the following?

package mrbear;

public class Main
{

    /**
     * Explicit Default Constructor. Required.
     * Defined here to prevent problems when
     * new constructor(s) with different arguments is/are added.
     */

    public Main()
    {
    }

}

I know for a fact, for example, that Hibernate requires entities to have some sort of default constructor, so Hibernate can create objects using reflection. [2]

You'd see something in the log like:

10:54:15,575 INFO [PojoInstantiator] no default (no-argument) constructor for class: mrbear.Main (class must be instantiated by Interceptor)

References

[1] Providing Constructors for Your Classes
http://docs.oracle.com/javase/tutorial/java/javaOO/constructors.html
[2] Hibernate : Chapter 4. Persistent Classes
http://docs.jboss.org/hibernate/core/3.3/reference/en/html/persistent-classes.html

Wednesday, 5 October 2011

Constructor in Anonymous Inner Class

Recently, I've been playing with JMockit, and I've come across certain language constructs in java that confused me.

It appears they were related to creating a different body for a constructor in the inner anonymous class. Which is hard to do, as the name of the Anonymous Inner Class is unknown.

package mrbean.anonymous;

public class Anonymous 
{

  private int i = 5;

  public int getI() 
  {
    System.out.println(this + " getI");
    return i;
  }

  public void setI(int i) 
  {
    System.out.println(this + " setI");
    this.i = i;
  }

  public Anonymous() 
  {
    System.out.println(this + " Constructor");
  }

  public void doStuff() 
  {
    System.out.println(this + " doStuff");
    System.out.println("i=" + new Anonymous() {
      {
        System.out.println(this + " Anonymous Constructor");
        setI(10);
      }
    }.getI());
  }

  /**
   * Main method to start the program.
   * @param args arguments
   */

  public static void main(String[] args) 
  {
    System.out.println("main: Start program.");
    Anonymous first = new Anonymous();
    System.out.println("main: i=" + first.getI());
    first.doStuff();
    System.out.println("main: End program.");
  }

}

This provided me with the following output:

main: Start program.
mrbear.anonymous.Anonymous@7d8a992f Constructor
mrbear.anonymous.Anonymous@7d8a992f getI
main: i=5
mrbear.anonymous.Anonymous@7d8a992f doStuff
mrbear.anonymous.Anonymous$1@23fc4bec Constructor
mrbear.anonymous.Anonymous$1@23fc4bec Anonymous Constructor
mrbear.anonymous.Anonymous$1@23fc4bec setI
mrbear.anonymous.Anonymous$1@23fc4bec getI
i=10
main: End program.

Especially in the creation of Expectations and Verifications in test methods in JMockit, it's quite common.