jackson-databind icon indicating copy to clipboard operation
jackson-databind copied to clipboard

Support specifying method for instantiating builders in JsonDeserialize

Open kaweston opened this issue 5 years ago • 11 comments

I request adding a parameter such as builderMethod to JsonDeserialize (e.g. @JsonDeserialize(builderMethod = "builder") ) to facilitate a way of specifying a method to instantiate a builder instance.

Example use case When using the Lombok SuperBuilder annotation it results in the creation two builder inner classes, one public and the other private which subclasses the public; it is the private class that must be instantiated. Currently when using the SuperBuilder annotation it is necessary to declare the private inner class (which will be completed during the annotation processing stage) to set its access modifier to package private so that Jackson can instantiated it.

An example original source file and the annotation processed result follows:

Original file

@JsonDeserialize(builder = LegalDocument.LegalDocumentBuilderImpl.class)
@Getter
@SuperBuilder(toBuilder = true)
public final class LegalDocument {

    private final String code;
    private final String fileName;
    private final String description;

   // This should not be necessary
    static final class LegalDocumentBuilderImpl
            extends LegalDocument.LegalDocumentBuilder<
            LegalDocument, LegalDocumentBuilderImpl> {
    }

}

After annotation processing

@JsonDeserialize(
    builder = LegalDocument.LegalDocumentBuilderImpl.class
)
public final class LegalDocument {
    private final String code;
    private final String fileName;
    private final String description;

    @Generated
    protected LegalDocument(LegalDocument.LegalDocumentBuilder<?, ?> b) {
        this.code = b.code;
        this.fileName = b.fileName;
        this.description = b.description;
    }

    // I would like to be able reference this method in the JsonDerserialize annotation
    @Generated
    public static LegalDocument.LegalDocumentBuilder<?, ?> builder() {
        return new LegalDocument.LegalDocumentBuilderImpl();
    }

    @Generated
    public LegalDocument.LegalDocumentBuilder<?, ?> toBuilder() {
        return (new LegalDocument.LegalDocumentBuilderImpl()).$fillValuesFrom(this);
    }

    @Generated
    public String getCode() {
        return this.code;
    }

    @Generated
    public String getFileName() {
        return this.fileName;
    }

    @Generated
    public String getDescription() {
        return this.description;
    }

    @Generated
    public abstract static class LegalDocumentBuilder<C extends LegalDocument, B extends LegalDocument.LegalDocumentBuilder<C, B>> {
        @Generated
        private String code;
        @Generated
        private String fileName;
        @Generated
        private String description;

        public LegalDocumentBuilder() {
        }

        @Generated
        protected B $fillValuesFrom(C instance) {
            $fillValuesFromInstanceIntoBuilder(instance, this);
            return this.self();
        }

        @Generated
        private static void $fillValuesFromInstanceIntoBuilder(LegalDocument instance, LegalDocument.LegalDocumentBuilder<?, ?> b) {
            b.code(instance.code);
            b.fileName(instance.fileName);
            b.description(instance.description);
        }

        @Generated
        protected abstract B self();

        @Generated
        public abstract C build();

        @Generated
        public B code(String code) {
            this.code = code;
            return this.self();
        }

        @Generated
        public B fileName(String fileName) {
            this.fileName = fileName;
            return this.self();
        }

        @Generated
        public B description(String description) {
            this.description = description;
            return this.self();
        }

        @Generated
        public String toString() {
            return "LegalDocument.LegalDocumentBuilder(code=" + this.code + ", fileName=" + this.fileName + ", description=" + this.description + ")";
        }
    }

    static final class LegalDocumentBuilderImpl extends LegalDocument.LegalDocumentBuilder<LegalDocument, LegalDocument.LegalDocumentBuilderImpl> {
        @Generated
        private LegalDocumentBuilderImpl() {
        }

        @Generated
        protected LegalDocument.LegalDocumentBuilderImpl self() {
            return this;
        }

        @Generated
        public LegalDocument build() {
            return new LegalDocument(this);
        }
    }
}

kaweston avatar Jun 14 '19 10:06 kaweston