Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jackson dynamic property names

Tags:

java

json

jackson

I would like serialize an object such that one of the fields will be named differently based on the type of the field. For example:

public class Response {     private Status status;     private String error;     private Object data;         [ getters, setters ]     } 

Here, I would like the field data to be serialized to something like data.getClass.getName() instead of always having a field called data which contains a different type depending on the situation.

How might I achieve such a trick using Jackson?

like image 500
Tim Avatar asked Aug 26 '12 21:08

Tim


2 Answers

I had a simpler solution using @JsonAnyGetter annotation, and it worked like a charm.

import java.util.Collections; import java.util.Map;  public class Response {     private Status status;     private String error;      @JsonIgnore     private Object data;      [getters, setters]      @JsonAnyGetter     public Map<String, Object> any() {         //add the custom name here         //use full HashMap if you need more than one property         return Collections.singletonMap(data.getClass().getName(), data);     } } 

No wrapper needed, no custom serializer needed.

like image 169
tlogbon Avatar answered Oct 04 '22 15:10

tlogbon


Using a custom JsonSerializer.

public class Response {   private String status;   private String error;    @JsonProperty("p")   @JsonSerialize(using = CustomSerializer.class)   private Object data;    // ... }  public class CustomSerializer extends JsonSerializer<Object> {   public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {     jgen.writeStartObject();     jgen.writeObjectField(value.getClass().getName(), value);     jgen.writeEndObject();   } } 

And then, suppose you want to serialize the following two objects:

public static void main(String... args) throws Exception {   ObjectMapper mapper = new ObjectMapper();   Response r1 = new Response("Error", "Some error", 20);   System.out.println(mapper.writeValueAsString(r1));   Response r2 = new Response("Error", "Some error", "some string");   System.out.println(mapper.writeValueAsString(r2)); } 

The first one will print:

{"status":"Error","error":"Some error","p":{"java.lang.Integer":20}} 

And the second one:

{"status":"Error","error":"Some error","p":{"java.lang.String":"some string"}} 

I have used the name p for the wrapper object since it will merely serve as a placeholder. If you want to remove it, you'd have to write a custom serializer for the entire class, i.e., a JsonSerializer<Response>.

like image 45
João Silva Avatar answered Oct 04 '22 15:10

João Silva