I finally got it:
ObjectMapper objectMapper = new ObjectMapper();
TypeFactory typeFactory = objectMapper.getTypeFactory();
List<SomeClass> someClassList = objectMapper.readValue(jsonString, typeFactory.constructCollectionType(List.class, SomeClass.class));
Answer from mmutilva on Stack OverflowI finally got it:
ObjectMapper objectMapper = new ObjectMapper();
TypeFactory typeFactory = objectMapper.getTypeFactory();
List<SomeClass> someClassList = objectMapper.readValue(jsonString, typeFactory.constructCollectionType(List.class, SomeClass.class));
The other answer is correct, but for completeness, here are other ways:
List<SomeClass> list = mapper.readValue(jsonString, new TypeReference<List<SomeClass>>() { });
SomeClass[] array = mapper.readValue(jsonString, SomeClass[].class);
java - How to use Jackson to deserialise an array of objects - Stack Overflow
java jackson parse json array - Stack Overflow
java - Retrieve a value from json array using jackson - Stack Overflow
How to parse Json array with 2 or more different types using Jackson?
http://www.baeldung.com/jackson-inheritance
You'll need to have those types inherit from one base class though.
Also; that is really bad JSON.
More on reddit.comFirst create a mapper :
import com.fasterxml.jackson.databind.ObjectMapper;// in play 2.3
ObjectMapper mapper = new ObjectMapper();
As Array:
MyClass[] myObjects = mapper.readValue(json, MyClass[].class);
As List:
List<MyClass> myObjects = mapper.readValue(jsonInput, new TypeReference<List<MyClass>>(){});
Another way to specify the List type:
List<MyClass> myObjects = mapper.readValue(jsonInput, mapper.getTypeFactory().constructCollectionType(List.class, MyClass.class));
From Eugene Tskhovrebov
List<MyClass> myObjects = Arrays.asList(mapper.readValue(json, MyClass[].class))
This solution seems to be the best for me.
The core issue is that you receive an array of arrays where you expect and array of objects. Changing mapper.readValue(response.getBody(), KlineResponse.class) to mapper.readValue(response.getBody(), Object[].class) confirms it.
You have a couple of options on how to proceed:
- Change from Jackson to standard JSON parsing, as suggested by @cricket_007 on his answer
- Instead of mapping it to an object try to access the JSON differently. See @jschnasse's answer for an example.
- Change the format of text you parse, if you can
- If you can't change the format of the input then you can either
- Create a constructor and annotate it with @JsonCreator, like instructed here
- Parse the input as Object array and feed the parsed array into a constructor of your own
You don't need any java classes. There are no JSON objects to deserialize, only arrays.
In the second case, Jackson is expecting { "klineList": [] }
In the first, [{ "klineList": [] }, { "klineList": [] }]
And a Kline object is only parsable as {"4": 0.0, "8": 0 } (replace zeros with any value of same type)... So really unclear why you expected that to work given that data... The annotations are not the index of the lists.
Plus, your lists have both strings and integers, so you can only deserialize as TypeReference<List<List<Object>>>, then iterate that to parse ints, floats, or strings
I might recommend you use a standard json parser, not an objectmapper
Following line should do the trick
int id = (int)((Map)mainMap2.get(0)).get("id");
Modification of your code may be as follows:
text = builder.toString();
ObjectMapper mapper = new ObjectMapper();
Map<String, Object> map = mapper.readValue(text, new TypeReference<Map<String, Object>>() {
});
List mainMap2 = (List) map.get("weather");
//for (Object item : mainMap2) {
// System.out.println("itemResult" + item.toString());
//}
int id = (int)((Map)mainMap2.get(0)).get("id");
System.out.println(id);
In jackson, JSON objects are converted into LinkedHashMap<String, Object>, so you simply need to cast your Object item into a Map<String, Object>, then get the value corresponding to the key id.
Something like this:
Integer id = null;
for (Object item : mainMap2) {
Map<String, Object> mapItem = (Map<String, Object>) item;
id = (Integer) mapItem.get("id");
if (id != null) {
// We have found an Id so we print it and exit from the for loop
System.out.printf("Id=%d%n", id);
break;
}
}
Output:
Id=800
Hi guys, I've been searching online and stackoverflow but can't seem to find an answer to this. Basically the API i'm calling returns a json array as the root object. The two objects inside this array are different types. I have defined two Java classes to represent these two types and I'm wanting to read the json and convert them into my java object with jackson. Seems like there isn't a way to do this??
simple example of my objects:
class Type1 {
String name
}
class Type2 {
long age
}The json coming from the api looks like this:
[
{
"name" : "mickey"
},
{
"age" : 100
}
]How can I tell jackson to read in this "tree" but convert it to some object that is holding these two?
EDIT Here is a reply I made to another comment:
Ok, it seems like nobody is understanding what I'm saying. For one, I don't have control of the api I'm calling. I get what I get and have to deal with it.
What that api returns is a json ARRAY as the ROOT object. There are two objects in that array. Those two objects are NOT the same types.
IF that array was holding objects of the same type, i could do this:
MyObjects[] myobjs = new Objectmapper().readValue("some json array here", MyObjects[].class);But like I said, i can't do this. Because the array is not holding objects of the same type. It would be more akin to a tuple like in python.
http://www.baeldung.com/jackson-inheritance
You'll need to have those types inherit from one base class though.
Also; that is really bad JSON.
Use a custom deserializer. See f.e. this link.
In your case the custom deserializer will look at the JsonNode and the properties it contains and instantiate the proper type.
I have json like this:
{
"users":{
"1234":{
"firstname":"Joe",
"lastname":"Smith"
},
"9876":{
"firstname":"Bob",
"lastname":"Anderson"
}
},
"jobs":[
{
"id":"abc",
"location":"store"
},
{
"id":"def",
"location":"factory"
}
]}
I'm parsing this using Jackson and so I have been parsing responses using: readvalue(json, MyCustomClass.class)
Where MyCustomClass looks like
public class MyCustomClass{
@JsonProperty("jobs")
ArrayList<Job> jobs;
@JsonProperty("users")
ArrayList<UserMap> usersMap;
}Now the jobs parse perfectly into Jobs objects but I can't get the users to parse since they have dynamic keys. I read about JsonAnyGetter/Setter and I tried making the UserMap object map that maps a string -> User like:
public class UserMap {
private HashMap<String,User> usersMap;
@JsonAnySetter
public void add(String key, User user){
usersMap.put(key, user);
}
@JsonAnyGetter
public Map<String, User> getUsersMap(){
return usersMap;
}
}but that doesn't work. I think I can do it with a TypeReference wrapper but I only can think of a way to do that if that maps were the only type I was getting back. Since I am getting different types back (users and jobs) is it possible to do this?