Jackson: how to prevent field serialization (while keeping deserialization)

拟墨画扇 提交于 2019-12-24 11:28:48

问题


I'd like to go further on what this question was about, I've been roaming SO for a solid hour now without finding anything.

Basically, what I'm trying to do is having a property properly instanciated through Jackson internal reflection algorithm during deserialization but having this same property not serialized when it comes to serialization.

I know about @JsonIgnore and @JsonIgnoreProperties but apparently I can't seem to use them right : either my property is correctly deserialized when I feed Jackson a proper map of properties but it also appears in the serialized results, either (when using @JsonIgnore) it is not serialized (which is wanted) but also not deserialized (not wanted).

Example :

public class Foo {

    /* This is the property I want to be instanciated by Jackson upon deserialization
     * but not serialized upon serialization
     */
    private final Object bar = null;

    public Object getBar() {
        return bar;
    }
}

To make things worse, as you can see, the property is final (this is why I'm keen on using Jackson reflection ability upon Foo instanciation through deserialization). I've read on potential solution about annotating the setter and the getter differently but I'd like to keep this property final if possible. If not possible, I'd settle for a non-final property.

I would appreciate answers not suggesting custom serializer/deserializer, my code base is currently free of such and if the solution could be of minimal impact, that would be perfect. Again, I'm no Jackson expert so if what I'm asking is not possible I'll obviously accept alternative answers.

I've also read this thread on github but none of the suggested ways of implementation have actually been implemented at the moment.

Thanks


EDIT : to make things clearer

public class Foo {

    private final String bar = null;

    public String getBar() {
        return bar;
    }

    @Override
    public String toString() {
        return bar;
    }
}


public void testMethod() throws IOException {
        String json = "{\"bar\":\"Value\"}";
        ObjectMapper mapper = new ObjectMapper();
        Foo foo = mapper.readValue(json, Foo.class);
        System.out.println(foo); // should have a bar property set to "Value"
        System.out.println(mapper.writeValueAsString(foo)); // should return an empty JSON object
}

回答1:


I am not sure whether it is elegant solution but you can use MixIn feature. You have to create new interface which could look like below:

interface FooMixIn {

    @JsonIgnore
    String getBar();
}

Assume that your POJO looks like this:

class Foo {

    private final String bar = null;

    public String getBar() {
        return bar;
    }

    @Override
    public String toString() {
        return bar;
    }
}

Now you have to tell Jackson that you want to ignore this property:

String json = "{\"bar\":\"Value\"}";
System.out.println(json);
ObjectMapper deserializeMapper = new ObjectMapper();
deserializeMapper.addMixInAnnotations(Foo.class, FooMixIn.class);
System.out.println(deserializeMapper.readValue(json, Foo.class));

Above example prints:

{"bar":"Value"}
null

Without deserializeMapper.addMixInAnnotations(Foo.class, FooMixIn.class); line above program prints:

{"bar":"Value"}
Value

EDIT 1


If you want to achieve result like you showed you have to create two ObjectMappers and customize them. See below example:

String json = "{\"bar\":\"Value\"}";
ObjectMapper deserializerMapper = new ObjectMapper();
Foo foo = deserializerMapper.readValue(json, Foo.class);
System.out.println("Foo object: " + foo);

ObjectMapper serializerMapper = new ObjectMapper();
serializerMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
serializerMapper.addMixInAnnotations(Foo.class, FooMixIn.class);
System.out.println("JSON: " + serializerMapper.writeValueAsString(foo));

For serialization you have to use one instance and for deserialization you have to use another instance.




回答2:


Starting with Jackson 2.6, a property can be marked as read- or write-only. It's simpler than hacking the annotations on both accessors (for non-final fields) and keeps all the information in one place. It's important to note that a final field is considered writable by default by Jackson.

However, it's not enough for a final field to allow deserialization, because you can't have a setter on that field: it needs to be set via the constructor, either directly or using a builder or another type that can be deserialized by Jackson. When using the constructor with the properties as parameters, you need to specify which parameter corresponds to which property, using @JsonProperty:

public class Foo {
    @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
    private final String bar;

    public Foo(@JsonProperty("bar") String bar) {
        this.bar = bar;
    }

    public String getBar() {
        return prop;
    }
}


来源:https://stackoverflow.com/questions/25675011/jackson-how-to-prevent-field-serialization-while-keeping-deserialization

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!