import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import java.io.IOException;
import java.util.Map;
public final class Jackson {
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true);
public static void main(String[] args) throws IOException {
Dto source = makeDto("Master", 31337);
Dto dst = makeDto("Slave", 0xDEADBEEF);
//1. read value of field "fieldName" from json source
//2. clones destination object, sets up field "fieldName" and returns it
//3. in case of no field either on "src" or "dst" - throws an exception
Object result = restoreValue(dst, "details", OBJECT_MAPPER.writeValueAsString(source));
System.out.println(result);
}
private static Object restoreValue(Object targetObject, String fieldName, String sourceObjectAsJson) throws IOException {
String targetObjectAsJson = OBJECT_MAPPER.writeValueAsString(targetObject);
Map sourceAsMap = OBJECT_MAPPER.readValue(sourceObjectAsJson, Map.class);
Map targetAsMap = OBJECT_MAPPER.readValue(targetObjectAsJson, Map.class);
targetAsMap.put(fieldName, sourceAsMap.get(fieldName));
String updatedTargetAsJson = OBJECT_MAPPER.writeValueAsString(targetAsMap);
return OBJECT_MAPPER.readValue(updatedTargetAsJson, targetObject.getClass());
}
private static Dto makeDto(String name, int magic) {
Dto dto = new Dto();
dto.setName(name);
CustomDetails details = new CustomDetails();
details.setMagic(magic);
dto.setDetails(details);
return dto;
}
private static final class Dto {
private String name;
@JsonSerialize(using = CustomDetails.CustomDetailsSerializer.class)
@JsonDeserialize(using = CustomDetails.CustomDetailsDeserializer.class)
private CustomDetails details;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public CustomDetails getDetails() {
return details;
}
public void setDetails(CustomDetails details) {
this.details = details;
}
@Override
public String toString() {
return "Dto{" +
"name='" + name + '\'' +
", details=" + details +
'}';
}
}
private static final class CustomDetails {
private int magic;
public int getMagic() {
return magic;
}
public void setMagic(int magic) {
this.magic = magic;
}
@Override
public String toString() {
return "CustomDetails{" +
"magic=" + magic +
'}';
}
public static final class CustomDetailsSerializer extends StdSerializer<CustomDetails> {
public CustomDetailsSerializer() {
this(null);
}
public CustomDetailsSerializer(Class<CustomDetails> t) {
super(t);
}
@Override
public void serialize(CustomDetails details, JsonGenerator jg, SerializerProvider serializerProvider) throws IOException {
jg.writeStartObject();
jg.writeNumberField("_custom_property_magic", details.magic);
jg.writeEndObject();
}
}
private static final class CustomDetailsDeserializer extends StdDeserializer<CustomDetails> {
public CustomDetailsDeserializer() {
this(null);
}
public CustomDetailsDeserializer(Class<CustomDetails> t) {
super(t);
}
@Override
public CustomDetails deserialize(JsonParser jp, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
JsonNode node = jp.getCodec().readTree(jp);
int magic = (Integer) node.get("_custom_property_magic").numberValue();
CustomDetails
customDetails = new CustomDetails();
customDetails.setMagic(magic);
return customDetails;
}
}
}
}
Dto{name='Slave', details=CustomDetails{magic=31337}}