I have an object like this to deserialize:
public class RelationsInput { Relation relation1; Relation relation2; }
whereas the class Relation
looks like this:
public class Relation { RelationType relationtype; ... (more fields) }
RelationType
is en enum and is not a value which will be deserialized, while all others are.
Is it possible, that I could “inject” the enum value for the field relationType
with an annotation on the field in the class RelationInput
?
Like the following
public class RelationsInput { @RelationType(RelationType.OWNER) Relation owner; @RelationType(RelationType.TENANT) Relation tenant; }
Does Jackson provide something like this?
Advertisement
Answer
You can try to implement custom deserialiser with com.fasterxml.jackson.databind.deser.ContextualDeserializer
interface. It allows to create deserialiser instance with a context.
See below example:
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.BeanProperty; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.deser.ContextualDeserializer; import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import com.fasterxml.jackson.databind.json.JsonMapper; import lombok.Data; import java.io.File; import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; public class JsonContextualDeserializerApp { public static void main(String[] args) throws IOException { File jsonFile = new File("./resource/test.json").getAbsoluteFile(); ObjectMapper mapper = JsonMapper.builder().build(); RelationsInput info = mapper.readValue(jsonFile, RelationsInput.class); System.out.println(info.toString()); } } @Data class RelationsInput { @JsonDeserialize(using = RelationStdDeserializer.class) @RelationTypeInfo(RelationType.OWNER) private Relation owner; @JsonDeserialize(using = RelationStdDeserializer.class) @RelationTypeInfo(RelationType.TENANT) private Relation tenant; } @Data class Relation { private int id; private RelationType relationtype; } enum RelationType {OWNER, TENANT} @Retention(RetentionPolicy.RUNTIME) @interface RelationTypeInfo { RelationType value(); } class RelationStdDeserializer extends StdDeserializer<Relation> implements ContextualDeserializer { private RelationType propertyRelationType; public RelationStdDeserializer() { this(null); } public RelationStdDeserializer(RelationType relationType) { super(Relation.class); this.propertyRelationType = relationType; } @Override public Relation deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { JsonDeserializer<Object> deser = ctxt.findRootValueDeserializer(ctxt.getTypeFactory().constructType(Relation.class)); Relation instance = (Relation) deser.deserialize(p, ctxt); if (this.propertyRelationType != null) { instance.setRelationtype(this.propertyRelationType); } return instance; } @Override public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) { RelationTypeInfo typeInfo = property.getMember().getAllAnnotations().get(RelationTypeInfo.class); return new RelationStdDeserializer(typeInfo.value()); } }
Above code for a payload:
{ "owner": { "id": 1 }, "tenant": { "id": 2 } }
prints:
RelationsInput(owner=Relation(id=1, relationtype=OWNER), tenant=Relation(id=2, relationtype=TENANT))
See also: