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 List
s of models but may apply this to Collection
s, Set
s, Native []
s and even the values of Map
s.