Home > Software design >  Using Jackson Mixins to selectively ignore only provided properties
Using Jackson Mixins to selectively ignore only provided properties

Time:01-26

I have the following situation:

public class A {
    private String someProperty;
    private String anotherProperty;

    public A() {}

    // getter/setter

An ObjectMapper configuration as follows (enabled by default, but worth noting to get the point of the question across):

objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true);

and an input JSON that looks as follows:

{
  "someProperty": "someValue",
  "anotherProperty":"anotherValue",
  "unwantedProperty":"unwantedValue"
}

When deserializing this JSON using objectMapper.readValue(bytes, A.class), as expected, it gives me an exception:

com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "unwantedProperty"

Now, what I want to do, is the following:

  1. Only deserialize properties that are explicitly provided by A.class
  2. Use a MixIn to ignore all unwanted, known properties. So for example, I know that unwantedProperty is part of the JSON, but I don't need it, so I want to ignore it.
  3. Still raise an UnrecognizedPropertyException if a new, unknown property suddenly appears in my JSON.

The reason that I wish to use something like a MixIn class for this is that in reality, the input JSON has several dozens of fields. I would prefer not to clutter my A.class with dozens and dozens of unused properties with @JsonIgnore on them, so that it only contains the fields that I really want. If a new property unexpectedly does come along, I want to be forced to have a look at it.

I thought that I could allow this behaviour by using a MixIn as follows:

public abstract class AMixIn {
    @JsonIgnore private String unwantedProperty;

together with:

objectMapper.addMixIn(A.class, AMixIn.class);

but this seemingly has no effect. I've also tried creating getters in AMixIn and giving those @JsonIgnore, but this also has no result.

Am I using MixIns incorrectly here? Is what I'm trying to do even possible (as described in the 3 points above)? Or, is there a better way to do this?

I've tried searching, but my use case is a bit esoteric, so I haven't had much luck.

CodePudding user response:

Answer to question 1:
You can instruct Jackson to ignore unknown properties. I tend to configure the ObjectMapper to ignore them, here is some sample code:

private ObjectMapper mapper;
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();

// This matches the Fuse Mapper configuration.
builder.featuresToDisable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
mapper = builder.build();

You can also annotate the class to ignore unknown properties. Here is some sample code:

@jsonignoreproperties(ignoreunknown = true)
public class A
{
   ...

Note about question 2:
In order for the use-mixin-to-ignore-fields-in-json strategy to work, the fields to be ignored must exist in the class. In your case, this means that class A must have a field "unwantedProperty" for the mixin to work correctly.

Direction to solve questions 2 and 3
You cannot use the MixIn feature of Jackson to solve either question 2 or question 3. Instead, you will need to write a custom deserializer. I suggest that you also use a custom Jackson annotation that configures a list of ignored-unrecognized-fields and have your custom deserializer only throw the exception for unrecognized fields that are not part of the ignored-unrecognized-fields list.

CodePudding user response:

Well, shows how well I can search; as always, Jackson provides some way of doing whatever needs doing. In case it might help someone else:

There exists the @JsonIgnoreProperties annotation which, in addition to the ignoreUnknown property (that I already knew), supports a list of properties (via value()) to ignore during de-/serialization (which I did not know).

This is not quite the same as the intended solution above, but having these properties inside of @JsonIgnoreProperties({ ... }) in the class header instead of the class body is a good enough compromise for me.

So, the solution would be:

@JsonIgnoreProperties({"unwantedProperty"})
public class A {
    // same as above...
}

Still, if there is a MixIn solution which can completely decouple these things, I'd still like to see it. I'll accept my own answer if nothing comes up in a few days.

  • Related