You can deserialize directly to a list by using the TypeReference wrapper. An example method:
public static <T> T fromJSON(final TypeReference<T> type,
final String jsonPacket) {
T data = null;
try {
data = new ObjectMapper().readValue(jsonPacket, type);
} catch (Exception e) {
// Handle the problem
}
return data;
}
And is used thus:
final String json = "";
Set<POJO> properties = fromJSON(new TypeReference<Set<POJO>>() {}, json);
TypeReference Javadoc
Answer from Perception on Stack OverflowYou can deserialize directly to a list by using the TypeReference wrapper. An example method:
public static <T> T fromJSON(final TypeReference<T> type,
final String jsonPacket) {
T data = null;
try {
data = new ObjectMapper().readValue(jsonPacket, type);
} catch (Exception e) {
// Handle the problem
}
return data;
}
And is used thus:
final String json = "";
Set<POJO> properties = fromJSON(new TypeReference<Set<POJO>>() {}, json);
TypeReference Javadoc
Another way is to use an array as a type, e.g.:
ObjectMapper objectMapper = new ObjectMapper();
MyPojo[] pojos = objectMapper.readValue(json, MyPojo[].class);
This way you avoid all the hassle with the Type object, and if you really need a list you can always convert the array to a list by:
List<MyPojo> pojoList = Arrays.asList(pojos);
IMHO this is much more readable.
And to make it be an actual list (that can be modified, see limitations of Arrays.asList()) then just do the following:
List<MyPojo> mcList = new ArrayList<>(Arrays.asList(pojos));
jackson should provides a method which can deserialize a collection that contains different type items
java - Jackson Json deserialization of an object to a list - Stack Overflow
java - Deserialize list of objects with inner list with Jackson - Stack Overflow
apex - How to deserialize JSON array into list of objects - Salesforce Stack Exchange
Since you are using Jackson I think what you need is JsonDeserializer class (javadoc).
You can implement it like this:
public class ListOrObjectGenericJsonDeserializer<T> extends JsonDeserializer<List<T>> {
private final Class<T> cls;
public ListOrObjectGenericJsonDeserializer() {
final ParameterizedType type = (ParameterizedType) this.getClass().getGenericSuperclass();
this.cls = (Class<T>) type.getActualTypeArguments()[0];
}
@Override
public List<T> deserialize(final JsonParser p, final DeserializationContext ctxt) throws IOException, JsonProcessingException {
final ObjectCodec objectCodec = p.getCodec();
final JsonNode listOrObjectNode = objectCodec.readTree(p);
final List<T> result = new ArrayList<T>();
if (listOrObjectNode.isArray()) {
for (JsonNode node : listOrObjectNode) {
result.add(objectCodec.treeToValue(node, cls));
}
} else {
result.add(objectCodec.treeToValue(listOrObjectNode, cls));
}
return result;
}
}
...
public class ListOrObjectResultItemJsonDeserializer extends ListOrObjectGenericJsonDeserializer<ResultItem> {}
Next you need to annotate your POJO field. Let's say you have classes like Result and ResultItem:
public class Result {
// here you add your custom deserializer so jackson will be able to use it
@JsonDeserialize(using = ListOrObjectResultItemJsonDeserializer.class)
private List<ResultItem> result;
public void setResult(final List<ResultItem> result) {
this.result = result;
}
public List<ResultItem> getResult() {
return result;
}
}
...
public class ResultItem {
private String value;
public String getValue() {
return value;
}
public void setValue(final String value) {
this.value = value;
}
}
Now you can check your deserializer:
// list of values
final String json1 = "{\"result\": [{\"value\": \"test\"}]}";
final Result result1 = new ObjectMapper().readValue(json1, Result.class);
// one value
final String json2 = "{\"result\": {\"value\": \"test\"}}";
final Result result2 = new ObjectMapper().readValue(json2, Result.class);
result1 and result2 contain the same value.
You can achieve what you want with a configuration flag in Jackson's ObjectMapper:
ObjectMapper mapper = Jackson2ObjectMapperBuilder.json()
.featuresToEnable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
.build();
Just set this ObjectMapper instance to your RestTemplate as explained in this answer, and in the class you are deserializing to, always use a collection, i.e. a List:
public class Response {
private List<Result> result;
// getter and setter
}
Let me prefix this by saying I am very new to all this so any help would be so very appreciated - i've been trying to crack this all day and it's been a real struggle. Im making this webapp in ASP.NET core btw. So I've managed to call the twitter api and return back some tweets as JSON depending on a search query. I am then trying to deserialize these into C# objects (using the Tweet class). I then want to pass these objects through as a list to the view for it to render them all out But I just can't seem to get it to work.
I am trying to put desrialize the JSON that comes back into Tweet objects and put them into a ViewModel and then pass the viewmodel to the view. This is what comes back from the API call so I know thats working ok. This is what the Tweet class looks like. The SocialMediaType property is a class in itself, and just has two properties on it which are an Id and name which are given default values as they will always be the same. The error page@JsonDeserialize(contentAs=Bar.class)
List<IBar> bars;
Why don't you just use a TypeReference ?
For instance...
Json file test.json in /your/path/:
[{"s":"blah"},{"s":"baz"}]
Main class in package test:
public class Main {
public static void main(String[] args) {
ObjectMapper mapper = new ObjectMapper();
try {
List<IBar> actuallyFoos = mapper.readValue(
new File("/your/path/test.json"), new TypeReference<List<Foo>>() {
});
for (IBar ibar : actuallyFoos) {
System.out.println(ibar.getClass());
}
}
catch (Throwable t) {
t.printStackTrace();
}
}
static interface IBar {
public String getS();
public void setS(String s);
}
static class Foo implements IBar {
protected String s;
public String getS() {
return s;
}
public void setS(String s) {
this.s = s;
}
}
static class Bar implements IBar {
protected String s;
public String getS() {
return s;
}
public void setS(String s) {
this.s = s;
}
}
}
Output of the main method:
class test.Main$Foo
class test.Main$Foo