Randgalt / record-builder

Record builder generator for Java records
Apache License 2.0
723 stars 51 forks source link

Null checks fail to render for records having a canonical constructor #146

Closed slinstaedt closed 1 year ago

slinstaedt commented 1 year ago

Thanks for the great tool. While testing some options, I figured something out, what probably is a bug. Using the option "interpretNotNulls" is working as expected, as long as one does not specify the canonical record constructor, even though it may not contain any code. So the following code will not contain any null checks for record component "a", but it will, when a remove the empty canonical constructor.

@RecordBuilder
@RecordBuilder.Options(interpretNotNulls = true)
public record MyDto(@NonNull String a, String b, String c, int x, List<String> strings)
        implements MyDtoBuilder.With {

    public MyDto {}
}

I am using version 35.

Randgalt commented 1 year ago

I just tried this and it generates correctly for me. Please provide an example.

slinstaedt commented 1 year ago

Working example (fails with NullPointerException):

package org.acme.domain.value;

import io.soabase.recordbuilder.core.RecordBuilder;
import jakarta.annotation.Nonnull;

@RecordBuilder
@RecordBuilder.Options(interpretNotNulls = true)
public record MyRecord(@Nonnull String name) {

    public static void main(String[] args) {
        var record = MyRecordBuilder.builder().name(null).build();
        System.out.println(record);
    }
}

Non-working example (outputs "MyRecord[name=null]"):

package org.acme.domain.value;

import io.soabase.recordbuilder.core.RecordBuilder;
import jakarta.annotation.Nonnull;

@RecordBuilder
@RecordBuilder.Options(interpretNotNulls = true)
public record MyRecord(@Nonnull String name) {

    public MyRecord {}

    public static void main(String[] args) {
        var record = MyRecordBuilder.builder().name(null).build();
        System.out.println(record);
    }
}
Randgalt commented 1 year ago

I don't know what's going on here. I tried your example, even imported the Jakarta library to get Nonnull and it works correctly for me.

Please give more details about your environment. Java version, etc.

slinstaedt commented 1 year ago

Okay, one thing I have not told, that I was using your library in both spring-boot and quarkus application running via OpenJDK 19. Maybe both of these frameworks or the JDK version are/is interfering with annotation processing. I will check a vanilla java app (without any other dependencies) later in the afternoon.

slinstaedt commented 1 year ago

Okay, some more insights: After testing some variations of OpenJDK version, spring/quarkus/vanilla and also different "NonNull" annotations I figured out, it's actual the IDE (vscode with it's java language server), that seem to cause the problems. Running the code using maven only will cause the expected outcome.

AFAIR the Java LS is based on Eclipse JDT, which has it's own java compiler implementation. This compiler seems to strip from the record's components at least for annotation processing, if another constructor is added. When using reflection I have perfect access to all (field, method, constructur param) annotations though.

slinstaedt commented 1 year ago

Will close this for that reason.

Randgalt commented 1 year ago

Oh man - that whole Eclipse world is bizarre to me. Why they need to have their own compiler/toolchain is a mystery.