Can you build the array as an object before writing it, rather than bothering with all the individual pieces?
ObjectMapper mapper = new ObjectMapper();
ArrayNode array = mapper.createArrayNode();
int i = 0;
while (i < 6) {
array.add(mapper.createArrayNode().add("" + i++).add("" + i++));
}
System.out.println(array);
Results in:
[["0","1"],["2","3"],["4","5"]]
If you're not dealing with several megabytes of data or very tight memory constraints, this might turn out to be more maintainable as well.
Answer from Chris on Stack OverflowCan you build the array as an object before writing it, rather than bothering with all the individual pieces?
ObjectMapper mapper = new ObjectMapper();
ArrayNode array = mapper.createArrayNode();
int i = 0;
while (i < 6) {
array.add(mapper.createArrayNode().add("" + i++).add("" + i++));
}
System.out.println(array);
Results in:
[["0","1"],["2","3"],["4","5"]]
If you're not dealing with several megabytes of data or very tight memory constraints, this might turn out to be more maintainable as well.
JsonGenerator jg = new JsonFactory().createJsonGenerator(System.out);
jg.configure(JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS, true);
jg.writeStartArray();
int i = 0;
while (i < 6)
{
jg.writeStartArray();
jg.writeObject(i++);
jg.writeObject(i++);
jg.writeEndArray();
}
jg.writeEndArray();
jg.flush();
OUTPUT:
[["0","1"],["2","3"],["4","5"]]
Do you need a json like this...?
java - How to use Jackson to deserialise an array of objects - Stack Overflow
java - How to parse a JSON string to an 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.comjava - Serializing array with Jackson - Stack Overflow
First 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.
I 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);
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 got it working by adding a custom serializer:
class Foo {
@JsonSerialize(using = MySerializer.class)
private List<String> fooElements;
}
public class MySerializer extends JsonSerializer<Object> {
@Override
public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider)
throws IOException, JsonProcessingException {
List<String> fooList = (List<String>) value;
if (fooList.isEmpty()) {
return;
}
String fooValue = fooList.get(0);
String[] fooElements = fooValue.split(",");
jgen.writeStartArray();
for (String fooValue : fooElements) {
jgen.writeString(fooValue);
}
jgen.writeEndArray();
}
}
If you are using Jackson, then the following simple example worked for me.
Define the Foo class:
public class Foo {
private List<String> fooElements = Arrays.asList("one", "two", "three");
public Foo() {
}
public List<String> getFooElements() {
return fooElements;
}
}
Then using a standalone Java app:
import java.io.IOException;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
public class JsonExample {
public static void main(String[] args) throws JsonGenerationException, JsonMappingException, IOException {
Foo foo = new Foo();
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writeValueAsString(foo));
}
}
Output:
{"fooElements":["one","two","three"]}
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