I have to serialize JSON from a list of Objects. The resulting JSON has to look like this:
{
\"status\": \"success\",
\"models\": [
{
There's no built-in way to do this. You'll have to write your own JsonSerializer. Something like
class ModelSerializer extends JsonSerializer<List<Model>> {
@Override
public void serialize(List<Model> value, JsonGenerator jgen,
SerializerProvider provider) throws IOException {
jgen.writeStartArray();
for (Model model : value) {
jgen.writeStartObject();
jgen.writeObjectField("model", model);
jgen.writeEndObject();
}
jgen.writeEndArray();
}
}
and then annotate the models field so that it uses it
@JsonSerialize(using = ModelSerializer.class)
private List<Model> models;
This would serialize as
{
"status": "success",
"models": [
{
"model": {
"id": 1,
"color": "red"
}
},
{
"model": {
"id": 2,
"color": "green"
}
}
]
}
If you're both serializing and deserializing this, you'll need a custom deserializer as well.
Another approach is using StdConverter class. Here is a working (abbreviated) example:
// MyParentObject.java
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
public class MyParentObject {
@JsonSerialize(converter = ChildListToString.class)
@JsonDeserialize(converter = StringToChildList.class)
@JsonProperty
public List<AChildObject> myChildren;
}
// ChildListToString.java
import com.fasterxml.jackson.databind.util.StdConverter;
import java.util.List;
import java.util.stream.Collectors;
public class ChildListToString extends StdConverter<List<AChildObject>, String> {
@Override
public String convert(List<IntakeModuleUrn> value) {
// this is just as effective as using Jackson "write array"
// Try-Catch omitted for brevity
StringBuilder builder = new StringBuilder("[");
value.stream().map(value -> new ObjectMapper().writeValue(value)).forEach(urnStr -> {
if(builder.length() > 1) {
builder.append(", ");
}
builder.append("\"").append(urnStr).append("\"");
});
builder.append("]");
return builder.toString();
}
}
// StringToChildList.java
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.util.StdConverter;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
public class StringToChildList extends StdConverter<String, List<AChildObject>> {
@Override
public List<AChildObject> convert(String value) {
// try - catch omitted here for brevity
List<String> strings = new ObjectMapper().readValue(value, new TypeReference<List<String>>() {});
return strings.stream()
.map(string -> {
return new ObjectMapper().readValue(string, AChildObject.class)
}).collect(Collectors.toList());
}
}
I like this because it gives you control of serialization and deserialization separately.
This is an oldish question, But there is an arguably more idiomatic way of implementing this (I'm using jackson-databind:2.8.8):
Define a ModelSerializer (That extends StdSerializer as recommended by Jackson) that prints your model how you like and use the @JsonSerialize(contentUsing = ...) over your collection type:
class ModelSerializer extends StdSerializer<Model> {
public ModelSerializer(){this(null);}
public ModelSerializer(Class<Model> t){super(t);} // sets `handledType` to the provided class
@Override
public void serialize(List<Model> value, JsonGenerator jgen,
SerializerProvider provider) throws IOException,
JsonProcessingException {
jgen.writeStartObject();
jgen.writeObjectField("model", value);
jgen.writeEndObject();
}
}
Meanwhile, in another file:
class SomethingWithModels {
// ...
@JsonSerialize(contentUsing = ModelSerializer.class)
private Collection<Model> models;
// ...
}
Now you aren't bound to just Lists of models but may apply this to Collections, Sets, Native []s and even the values of Maps.