Deserializing JSON flat object using immutable classes with Jackson
jackson, java, json
Solution
Note that Jackson's deserialization processing doesn't necessarily respect the immutability of `final` fields. So, a simple approach would be to just provide no-argument (private) constructors for Jackson to use.
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
import com.fasterxml.jackson.annotation.JsonUnwrapped;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JacksonFoo
{
public static void main(String[] args) throws Exception
{
// {"var1":"some_value", "var2":"some_other_value"}
String jsonInput = "{\"var1\":\"some_value\", \"var2\":\"some_other_value\"}";
ObjectMapper mapper = new ObjectMapper().setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
A a = new A(new Foo("some_value"), "some_other_value");
System.out.println(mapper.writeValueAsString(a));
// output: {"var1":"some_value","var2":"some_other_value"}
A aCopy = mapper.readValue(jsonInput, A.class);
System.out.println(mapper.writeValueAsString(aCopy));
// output: {"var1":"some_value","var2":"some_other_value"}
}
}
class Foo
{
private final String var1;
Foo(String var1) {this.var1 = var1;}
private Foo() {this.var1 = null;}
}
class A
{
@JsonUnwrapped
private final Foo foo;
private final String var2;
A(Foo foo, String var2)
{
this.foo = foo;
this.var2 = var2;
}
private A()
{
this.foo = null;
this.var2 = null;
}
}
If you really don't want to provide such (extra) constructors, then it would be nice if a similar solution could be devised using `@JsonCreator`, but I wasn't able to get such a thing to work. So, I recommend logging an enhancement request at https://github.com/FasterXML/jackson-core/issues, maybe to better support annotating a `@JsonCreator` argument with both `@JsonUnwrapped` and `@JsonProperty`.
Problem
I'm quite new to the Jackson library (version 1.9). I'm using it only since a couple of weeks, and I find it very flexible and time-saving when it's about serializing and deserializing objects in Java. I'm experiencing troubles, though, into deserializing "flat" JSONs to a class which is a composition of another, when both are meant to be immutable. My situation is pretty much the following: ``` class Foo { private final String var1; Foo(String var1) { this.var1 = var1; } // getters omitted } class A { private final Foo foo; private final String var2; A(/* @JsonUnwrapped doesn't work here */ Foo foo, String var2) { this.foo = foo; this.var2 = var2; } @JsonUnwrapped Foo getFoo() { return foo; } String getVar2() { return var2; } } class B extends Foo { private final String var2; B(String var1, String var2) { super(var1); this.var2 = var2; } // getters omitted } ``` And the JSON to deserialize is something like this: ``` { "var1" : "some_value", "var2" : "some_other_value" } ``` The question is: is there an annotation-based way (so, without the need of using a custom deserializer) to tell Jackson to compose the given JSON to a 'A' instance? I've tried using the @JsonUnwrapped attribute for the Foo argument in class 'A' constructor, but it's not supported in multi-argument constructor as it would need a JsonProperty to work (which doesn't make sense, because there is actually no single property for those items). Serialization, instead, works perfectly using this pattern. It would also work with a non-immutable class by using separate setters, but I'd like to know if there's a way to do the same by only using the constructors (or a builder, which would make sense as in reality the fields are much more than the one in the example). The very same method obviously works with class 'B' which inherits from 'Foo'. Thanks in advance.