Reputation: 30097
Suppose I am writing custom serialization for some class, but would like to process one of its field with default methods.
How to do that?
While serializing we have JsonGenerator#writeObjectField()
.
But what is corresponding method for deserialization?
Regard the code below:
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import java.io.IOException;
import java.util.Objects;
public class TryDelegate {
public static class MyOuterClassSerializer extends JsonSerializer<MyOuterClass> {
@Override
public void serialize(MyOuterClass value, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException {
gen.writeStartObject();
gen.writeObjectField("inner", value.getInner());
gen.writeEndObject();
}
}
public static class MyOuterClassDeserializer extends JsonDeserializer<MyOuterClass> {
@Override
public MyOuterClass deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
MyOuterClass ans = new MyOuterClass();
JsonToken token;
token = p.getCurrentToken();
if( token != JsonToken.START_OBJECT ) {
throw new JsonParseException("Start object expected", p.getCurrentLocation());
}
if( !"inner".equals(p.nextFieldName() ) ) {
throw new JsonParseException("'inner; field expected", p.getCurrentLocation());
}
MyInnerClass inner = null;// how to desrialize inner from here with default processing???
ans.setInner(inner);
token = p.nextToken();
if( token != JsonToken.END_OBJECT ) {
throw new JsonParseException("End object expected", p.getCurrentLocation());
}
return ans;
}
}
public static class MyInnerClass {
private int value;
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
@Override
public String toString() {
return "{\"value\":" + value + "}";
}
}
@JsonDeserialize(using = MyOuterClassDeserializer.class)
@JsonSerialize(using = MyOuterClassSerializer.class)
public static class MyOuterClass {
private MyInnerClass inner;
public MyInnerClass getInner() {
return inner;
}
public void setInner(MyInnerClass inner) {
this.inner = inner;
}
@Override
public String toString() {
return "{\"inner\":" + Objects.toString(inner) + "}";
}
}
public static void main(String[] args) throws IOException {
ObjectMapper mapper = new ObjectMapper();
String string;
MyInnerClass inner = new MyInnerClass();
inner.setValue(12);
MyOuterClass outer = new MyOuterClass();
outer.setInner(inner);
string = mapper.writeValueAsString(outer);
System.out.println(string);
MyOuterClass outer2 = mapper.readValue(string, MyOuterClass.class);
System.out.println(outer2); // inner was not deserialized
}
}
How to implement MyOuterDeserializer
?
Upvotes: 21
Views: 11902
Reputation: 73
Saved my bacon, thanks for this answer.
Basic technique here is to loop through the tokens and check for token of type FIELD_NAME with the name of the object you are looking for. Then advance past the field name (p.nextToken) and give the JsonParser and class type you want to the context. Works!
JsonToken token = p.currentToken();
while (token != null) {
if (p.currentToken().equals(JsonToken.FIELD_NAME) &&
p.getText().equals("targetField")) {
p.nextToken();
TargetType target =
deserializationContext.readValue(p,Targettype.class);
}
}
Upvotes: 0
Reputation: 279880
The DeserializationContext
offers these tools.
After checking the field name for "inner"
, move to the next token, the beginning of the JSON object and use the DeserializationContext
to deserialize the JSON object into a MyInnerClass
object.
if (!"inner".equals(p.nextFieldName())) {
throw new JsonParseException("'inner; field expected", p.getCurrentLocation());
}
p.nextToken(); // consumes the field name token
MyInnerClass inner = ctxt.readValue(p, MyInnerClass.class);
The javadoc states
Convenience method that may be used by composite or container deserializers, for reading one-off values contained (for sequences, it is more efficient to actually fetch deserializer once for the whole collection).
Careful while using the DeserializationContext
. Don't try to recursively deserialize types for which you have have registered custom deserializers.
Upvotes: 10