I would recommend going with a Deserializer as Foo1 might actually be serialized elsewhere and we might only have it's serialized data to convert. And that is what is our goal here.
Create a SimpleModule that deserializes List type
public class ListDeserializer extends StdDeserializer<List> {
public ListDeserializer() {
super(List.class);
}
@Override
public List deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException {
if (p.getCurrentName().equals("result") || p.getCurrentName().equals("attachments")) {
JsonNode node = p.getCodec().readTree(p);
return new ObjectMapper().readValue(node.asText(), List.class);
}
return null;
}
}
The above deserializer only recognizes result and attachments and ignores the rest. So this is a very specific deserializer for List in Foo2 class.
My test Foo1 and Foo2 are as follows
public class Foo1 {
String result = "[\"abcd\", \"xyz\"]";
public String getResult() {
return result;
}
public void setResult(String result) {
this.result = result;
}
}
public class Foo2 {
List result;
public List getResult() {
return result;
}
public void setResult(List result) {
this.result = result;
}
}
I tested the above code as follows
// Module to help deserialize List objects
SimpleModule listModule = new SimpleModule();
listModule.addDeserializer(List.class, new ListDeserializer());
ObjectMapper objectMapper = new ObjectMapper().registerModules(listModule);
Foo2 foo2 = objectMapper.convertValue(new Foo1(), Foo2.class);
System.out.println(foo2.getResult());
And the output is
[abcd, xyz]
Answer from Sunil Dabburi on Stack OverflowI would recommend going with a Deserializer as Foo1 might actually be serialized elsewhere and we might only have it's serialized data to convert. And that is what is our goal here.
Create a SimpleModule that deserializes List type
public class ListDeserializer extends StdDeserializer<List> {
public ListDeserializer() {
super(List.class);
}
@Override
public List deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException {
if (p.getCurrentName().equals("result") || p.getCurrentName().equals("attachments")) {
JsonNode node = p.getCodec().readTree(p);
return new ObjectMapper().readValue(node.asText(), List.class);
}
return null;
}
}
The above deserializer only recognizes result and attachments and ignores the rest. So this is a very specific deserializer for List in Foo2 class.
My test Foo1 and Foo2 are as follows
public class Foo1 {
String result = "[\"abcd\", \"xyz\"]";
public String getResult() {
return result;
}
public void setResult(String result) {
this.result = result;
}
}
public class Foo2 {
List result;
public List getResult() {
return result;
}
public void setResult(List result) {
this.result = result;
}
}
I tested the above code as follows
// Module to help deserialize List objects
SimpleModule listModule = new SimpleModule();
listModule.addDeserializer(List.class, new ListDeserializer());
ObjectMapper objectMapper = new ObjectMapper().registerModules(listModule);
Foo2 foo2 = objectMapper.convertValue(new Foo1(), Foo2.class);
System.out.println(foo2.getResult());
And the output is
[abcd, xyz]
Option 1 : Just annotate the getter method of the Foo1.class
@JsonProperty("comments")
public List getComments() {
List list = new ArrayList();
list.add(comments);
return list;
}
@JsonProperty("attachments")
public List getAttachments() {
List list = new ArrayList();
list.add(attachments);
return list;
}
Foo1 foo1 = new Foo1(Long.valueOf(1),"a","aaa",true,"abc","def");
System.out.println(new ObjectMapper().writeValueAsString(foo1));
Foo2 foo2 = new ObjectMapper().convertValue(foo1, Foo2.class);
System.out.println(new ObjectMapper().writeValueAsString(foo2));
Option 2 : use jackson-custom-serialization
ObjectMapper mapper = new ObjectMapper();
SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(Foo1.class,new ListSerializer());
mapper.registerModule(simpleModule);
public class ListSerializer extends StdSerializer<Foo1> {
public ListSerializer() {
this(null);
}
protected ListSerializer(Class<Blah.Foo1> t) {
super(t);
}
public void serialize(Blah.Foo1 foo1, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeStartObject();
List list = new ArrayList();
list.add(foo1.getComments());
List list1 = new ArrayList();
list1.add(foo1.getAttachments());
jsonGenerator.writeObjectField("id",foo1.getId());
jsonGenerator.writeObjectField("code",foo1.getCode());
jsonGenerator.writeObjectField("name",foo1.getName());
jsonGenerator.writeObjectField("rState",foo1.getrState());
jsonGenerator.writeObjectField("comments",list);
jsonGenerator.writeObjectField("attachments",list1);
jsonGenerator.writeEndObject();
}
}
Foo1 foo1 = new Foo1(Long.valueOf(1),"a","aaa",true,"abc","def");
System.out.println(mapper.writeValueAsString(foo1));
Foo2 foo2 = mapper.convertValue(foo1, Foo2.class);
System.out.println(new ObjectMapper().writeValueAsString(foo2));
Videos
That's depends what the input is.
(Map<String, Object>) ois used for casting conversion, so the runtime type ofomust beMap, otherwiseClassCastExceptionwill be thrown:CopyObject o = new HashMap<>(); Map<String, Object> map = (Map<String, Object>) o; // ok Object o = new ArrayList<>(); Map<String, Object> map = (Map<String, Object>) o; //ClassCastException Object o = new String(); Map<String, Object> map = (Map<String, Object>) o; //ClassCastExceptionObjectMapper().readValue(String content, JavaType valueType):Method to deserialize JSON content from given JSON content String.
which means the input should be a
Stringin valid json format. For example:CopyObject input = "{\"key1\":{},\"key2\":{}}"; Map<String, Object> map = new ObjectMapper().readValue((String) input, new TypeReference<Map<String, Object>>() {}); System.out.println(map.size()); // 2
There is no "better". There are practical differences. But first, both options use type casting, and this raises the question "how are these two considered alternatives at all?"
Casting will only work if some object passes the instanceof Map test (first option), or if o passes the instanceof String test (second option).
In other words, the answer depends on the runtime class of some object.
So either this will fail with a class cast exception:
Copy(Map<String, Object>) o;
Or this will fail with the same exception:
Copy(String) o
Assuming the type checks will pass one way or the other, there are differences to be considered:
- If
some objectis compatible withMap<String, Object>, then casting should be preferred as it offers a performance advantage (consideringobjectMapper.convertValueas the alternative). In fact,readValueisn't even an option as the cast to string will fail. - If
some objectis a String, then you have no choice but to callreadValue, as you need to parse JSON.
As noted above, there's also objectMapper.convertValue, which in a smart way checks first instanceof before performing the conversion through JSON parsing. It's meant to convert objects from one type to another, if the two types have the same fields.