What is correct type reference for converting the json into java object using jackson
«The conversion code is approximately this» — Sorry, that is not acceptable. Nobody is going to look at code that does not reflect what you are actually using. The question is off topic in its current form.
@RC, that is why I created a Map and the key of the Map is String. «HYR» should be picked up as the key, shouldn’t it?
3 Answers 3
This JSON is invalid in your case. See the part
There is a » that should not be there, so valid part would be like:
In your case, you are require a value of HYR to be an array, but it is of String value (due to quotation). Removing quotation will indeed make valid JSON array.
Thanks @Antoniossss, unluckily I might not be able to change the API response as it is not owned by my team. Is there a work around with the current API response (i.e. with the extra «»)
There is none as this is INVALID json. Report the bug. For a workaround you could blindly remove first and last quotation mark, but this will invalidate valid string values. Or remove first and last quotation mark if value starts from «< or "["
There are extra » in json at the start and end of Array «[ ]» . You need to remove them.
try < String jsonStr = "<\"HYR\":[<\"LastUpdatedBy\":\"Bug 101510: VMukkanagoudar\",\"IATACountryCode\":\"US\",\"MetroCodeBool\":false,\"AirportName\":\"Sawyer County\",\"Latitude\":46,\"CityName\":\"Hayward\",\"MajorAirportBool\":false,\"Longitude\":-91,\"StatusCode\":\"A\",\"DisplayNameLocal\":\"Hayward, WI (HYR-Sawyer County)\",\"DisplayNameInternational\":\"Hayward, WI, United States (HYR-Sawyer County)\",\"UpdateDate\":\"2009-03-06 20:44:00.0\",\"AirportCode\":\"HYR\",\"AirportID\":5396808,\"RegionName\":\"Wisconsin\",\"IdenticalMetroCodeBool\":false,\"ExternalName\":\"HYR\",\"CountryCode\":\"USA\">]>"; if (jsonStr != null) < ObjectMapper mapper = new ObjectMapper(); TypeReference>> typeRef = new TypeReference>>() <>; HashMap> configMap = mapper.readValue(jsonStr, typeRef); ArrayList configList = configMap.get("HYR"); > > catch (IOException e) < e.printStackTrace(); >>
using (with your Config with a proper toString ):
public static void main(String[] args) throws IOException < String jsonStr = "<\"HYR\":\"[<\\\"LastUpdatedBy\\\":\\\"Bug 101510: VMukkanagoudar\\\",\\\"IATACountryCode\\\":\\\"US\\\",\\\"MetroCodeBool\\\":false,\\\"AirportName\\\":\\\"Sawyer County\\\",\\\"Latitude\\\":46,\\\"CityName\\\":\\\"Hayward\\\",\\\"MajorAirportBool\\\":false,\\\"Longitude\\\":-91,\\\"StatusCode\\\":\\\"A\\\",\\\"DisplayNameLocal\\\":\\\"Hayward, WI (HYR-Sawyer County)\\\",\\\"DisplayNameInternational\\\":\\\"Hayward, WI, United States (HYR-Sawyer County)\\\",\\\"UpdateDate\\\":\\\"2009-03-06 20:44:00.0\\\",\\\"AirportCode\\\":\\\"HYR\\\",\\\"AirportID\\\":5396808,\\\"RegionName\\\":\\\"Wisconsin\\\",\\\"IdenticalMetroCodeBool\\\":false,\\\"ExternalName\\\":\\\"HYR\\\",\\\"CountryCode\\\":\\\"USA\\\">]\">"; ObjectMapper mapper = new ObjectMapper(); // step one: deserialize the map HashMap configMap = mapper.readValue(jsonStr, new TypeReference() <>); // step two, deserialize the value for HYR final String hyr = configMap.get("HYR"); List configs = mapper.readValue(hyr, new TypeReference() <>); System.out.println(configs); >
Works here (jackson-2.3.2) and outputs:
[Foo.Config(airportCode=HYR, airportId=5396808, metroCodeBool=false, majorAirportBool=false, identicalMetroCodeBool=false, statusCode=A)]
Jackson JSON List with Object Type
How can I add «model» for each object without having to write a silly wrapper class with a property «model»? My classes look like this:
public class Response < private String status; private Listmodels; // getters / setters > public class Model < private Integer id; private String color; // getters / setters >
Your JSON is not valid; object member names must be quoted (hint: «» is a valid JSON Object member name)
3 Answers 3
There’s no built-in way to do this. You’ll have to write your own JsonSerializer . Something like
class ModelSerializer extends JsonSerializer> < @Override public void serialize(Listvalue, 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 models;
If you’re both serializing and deserializing this, you’ll need a custom deserializer as well.
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 < public ModelSerializer()public ModelSerializer(Class t) // sets `handledType` to the provided class @Override public void serialize(List 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 Collectionmodels; // . >
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.
this code won’t compile. First, you have a parameter named value, but are writing ‘model’. Also, at least in my jackson, the signature of serialize appears to get a single model, not a list.
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 ListmyChildren; >
// ChildListToString.java import com.fasterxml.jackson.databind.util.StdConverter; import java.util.List; import java.util.stream.Collectors; public class ChildListToString extends StdConverter, String> < @Override public String convert(Listvalue) < // 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> < @Override public Listconvert(String value) < // try - catch omitted here for brevity Liststrings = new ObjectMapper().readValue(value, new TypeReference() <>); 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.