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

Allow overriding builder's "withPrefix" with new `@JsonDeserialize` property

Open kennethjor opened this issue 5 years ago • 5 comments

It would be nice to be able to configure the builder method name prefix Jackson uses either globally through a configuration on ObjectMapper or through the @JsonDeserialize annotation itself. I'm currently using Lombok to generate my builders for me and to make it work nicely with Jackson I have to write boilerplate code, which is the whole point of lombok.

The Problem

Currently, in order to use Jackson and lombok in tandem, I have to write a model class like this:

@Builder
@JsonDeserialize(builder = Model.ModelBuilder.class)
public class Model {
	
	/** various properties */

	@JsonPOJOBuilder(withPrefix = "")
	public static class ModelBuilder {
	}
}

The issue becomes even worse if using the @SuperBuilder annotation:

@SuperBuilder
@JsonDeserialize(builder = Model.ModelBuilderImpl.class)
public class Model extends AbstractModel {

	/** various properties */

	@JsonPOJOBuilder(withPrefix = "")
	protected static final class ModelBuilderImpl extends Model.ModelBuilder<Model, Model.ModelBuilderImpl> {
	}
}

There's also a blurb about the workaround in Lombok's own documentation.

Related issue: https://github.com/FasterXML/jackson-databind/issues/1997

Global Config

One way to fix it would be to allow this to be configured globally on ObjectMapper like:

objectMapper.configure(DeserializationFeature.POJO_BUILDER_PREFIX, "");

JsonDeserialize Property

Another solution would be to allow it to be set on the @JsonDeserialize annotation itself, like:

@JsonDeserialize(builder = Model.ModelBuilder.class, withBuilderPrefix = "")

Personally, I prefer option 2.

kennethjor avatar Feb 15 '20 17:02 kennethjor

Sounds like a reasonable idea, and I think I know the mechanism it should use (since I prefer not adding one-off configuration methods if at all possible: "config overrides". This could even allow per-class non-annotation-based override, possibly.

I don't know which version this would go in -- 2.11 is not yet out, but not sure I have time to add it there, as I am hoping to wrap it up. But this could probably work out nicely for 2.12.

cowtowncoder avatar Feb 18 '20 18:02 cowtowncoder

FWIW the Lombok team have implemented a @Jacksonized annotation for making Lombok models play nicely with Jackson.

kennethjor avatar Mar 24 '20 05:03 kennethjor

@kennethjor Interesting. Thank you for sharing!

cowtowncoder avatar Mar 24 '20 21:03 cowtowncoder

Ok, with #2800, there now IS a way to, I think, configure builder-"with" prefix, using new AccessNamingStrategy (and provider). And in fact DefaultAccessorNamingStrategy allows configuration, so something like:

    ObjectMapper mapper = JsonMapper.builder()
                .accessorNaming(new DefaultAccessorNamingStrategy.Provider()
                        .withBuilderPrefix("") // no prefix
// or                       .withBuilderPrefix("With") //  would expect 'WithX()' etc
                )
                .build();

or, if you want something more complicated (multiple prefixes, or different naming convention), just implement strategy yourself (and configure with Provider that constructs instances).

cowtowncoder avatar Aug 29 '20 20:08 cowtowncoder

Added a test to verify that case above (no/empty prefix) works as expected.

But I think I will leave this open as addition of an annotation in @JsonDeserialize does seem like a good idea, if it can be pulled off.

cowtowncoder avatar Oct 03 '20 21:10 cowtowncoder