bowbahdoe / magic-bean

A very basic library which will generate getters and setters.
Other
84 stars 10 forks source link

Error for (multiple) Field Annotations in Pojo #24

Open funkrusher opened 3 days ago

funkrusher commented 3 days ago

When a Pojo has multiple Bean-Annotations on a field, magic-bean crashes during code-generation. Following example:

@MagicBean
public final class UpdateProductRequest {

    @Schema(required = false, nullable = false)
    @NotNull
    @Size(max = 255)
    String typeId;
}

Following error during code-generation:

/home/funkrusher/dev/checkouts/fk-framework-quarkus-jooq/_modules/fk_product/build/generated/sources/annotationProcessor/java/main/org/fk/product/dto/UpdateProductRequestBeanOps.java:54: Fehler: <ID> erwartet
    public java.lang.@jakarta.validation.constraints.NotNull,@jakarta.validation.constraints.Size(max=255) String getTypeId() {

The generated Getter looks as follow, and is invalid:

    /**
     * Get the current value for typeId.
     */
    public java.lang.@jakarta.validation.constraints.NotNull,@jakarta.validation.constraints.Size(max=255) String getTypeId() {
        return self().typeId;
    }

Expected Result:

bowbahdoe commented 3 days ago

This is actually a bug in the JDK, believe it or not.

https://bugs.openjdk.org/browse/JDK-8281238?jql=text%20~%20%22toString%20of%20annotation%22

I get the types for code generation from TypeMirror#toString() that is documented to be valid to use in source code.

    /**
     * Returns an informative string representation of this type. If
     * possible, the string should be of a form suitable for
     * representing this type in source code. Any names embedded in
     * the result are qualified if possible.
     *
     * @return a string representation of this type
     */

So that issue should be re-opened / re-reported so that it works with multiple annotations. There is technically a path where I reimplement that method but its a mountain of work.

Separately, the reason those annotations appear in the getters is because they are "type use" annotations.

Target(value={METHOD,FIELD,ANNOTATION_TYPE,CONSTRUCTOR,PARAMETER,TYPE_USE})
 @Retention(value=RUNTIME)
 @Repeatable(value=NotNull.List.class)
 @Documented
 @Constraint(validatedBy={})
public @interface NotNull {}

A TYPE_USE annotation Java considers to be part of something's type. Like List<@NonNull String> - the type of the elements is @NonNull String, not just String. As a result, when I generate the getters the annotations follow.

So I don't think its conceptually possible to not have them in the getters and setters (as formulated). The bigger issue is that it doesn't compile. I'll open a bug report on JBS

funkrusher commented 3 days ago

@bowbahdoe

ah yes, that explains it.

The "NotNull" and "Size" Annotations are both "type use" annotations, so as you said they can (should) be part of the Setter/Getter.

bowbahdoe commented 3 days ago

@funkrusher I submitted the bug report...and now we wait.

I am a bit embarrassed I didn't notice that sooner.

I made this minimum reproducer that i'll attach to the bug report. type-mirror-bug.zip