1

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
}
Community
  • 1
  • 1
m4rtin
  • 2,445
  • 22
  • 34

2 Answers2

2

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.

Michał Ziober
  • 37,175
  • 18
  • 99
  • 146
  • Dammit ! +1 because your answer does exactly what you describe and introduced me to Jackson's MixIn but it also made me realized I got the serialization/deserialization process mixed up >< I edited my question, if you know any way of doing such as it answers my real need, I'll gladly accept your answer. – m4rtin Sep 05 '14 at 11:21
  • Now I really do not understand what are you trying to do. You want to hide this property in serialization process and at the same time `Jackson` should be able to deserialize it. Is it true? I want to help, but you have to give me the example how your `POJO` and `JSON` look like and you have to show me how you are serializing it (with JSON output) and deserializing it. Good example will be better than 1000 words. – Michał Ziober Sep 05 '14 at 19:57
  • Yes that is exactly what I'm trying to do, sorry my question wasn't clear enough in the first place. I edited it to reflect your example. Let's agree on the fact that the *deserialization* process means going from a JSON string to a Foo instance and the *serialization* one from a Foo instance to a JSON string. – m4rtin Sep 07 '14 at 12:53
0

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;
    }
}
Frank Pavageau
  • 11,477
  • 1
  • 43
  • 53