I need help with parsing, I've tried to create a different kind of model classes, but no use, please help me out here. the json looks like this:
[
[
1518909300000,
"0.08815700",
"0.08828700",
"0.08780000",
"0.08792900",
"1727.93100000",
1518910199999,
"152.11480375",
5118,
"897.71600000",
"79.04635703",
"0"
],
[
1518910200000,
"0.08788400",
"0.08824200",
"0.08766200",
"0.08810000",
"1789.81300000",
1518911099999,
"157.20177729",
6201,
"898.89500000",
"78.95697080",
"0"
]
]
and I'm trying to parse it using data class:
#JsonIgnoreProperties(ignoreUnknown = true)
public class KlineResponse {
public List<Kline> getKlineList() {
return klineList;
}
public List<Kline> klineList;
public class Kline {
#JsonProperty("4")
Double close;
#JsonProperty("8")
Integer tradesNumber;
public Double getClose() {
return close;
}
public void setClose(Double close) {
this.close = close;
}
public Integer getTradesNumber() {
return tradesNumber;
}
public void setTradesNumber(Integer tradesNumber) {
this.tradesNumber = tradesNumber;
}
}
}
and this line
mapper.readValue(response.getBody(), new TypeReference<List<KlineResponse>>(){})
or
mapper.readValue(response.getBody(), KlineResponse.class)
but each time the error:
Can not deserialize instance of pt.settings.model.KlineResponse out of START_ARRAY token,
please help
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
Use JsonNode together with JPointer. Avoid to create a POJO and work directly on the data via JsonNode.
ObjectMapper mapper = new ObjectMapper();
JsonNode matrix = mapper.readValue(in, JsonNode.class);
matrix.forEach(array -> {
System.out.println("Next Values:");
System.out.println(array.at("/4").asDouble());
System.out.println(array.at("/8").asInt());
});
Prints
Next Values:
0.087929
5118.0
Next Values:
0.0881
6201.0
Related
I'm trying to deserialize a nested array from a JSON response. It's the first time I've ever gotten an array of arrays and I'm not quite sure how to structure my class to handle it.
{
"prices": [
[
1641670404234,
0.01582586939240936
],
[
1641674037525,
0.015999047707867396
],
[
1641677655158,
0.016072905257982606
]
...
],
}
If the brackets were { instead of [
{
"prices": {
{
1641670404234,
0.01582586939240936
},
{
1641674037525,
0.015999047707867396
},
{
1641677655158,
0.016072905257982606
}
}
...
}
I could use
#SerializedName("prices")
private List<Price> prices;
public class Price {
private long date;
private BigDecimal price;
}
However since it is [ instead, I am quite unsure how to structure it.
I've tried adding another List wrapper to it but that throws an error
#SerializedName("prices")
private List<List<Price>> prices;
IllegalStateException: Expected BEGIN_OBJECT but was NUMBER at line 1 column 26 path $.prices[0][0]
I've also tried wrapping it with a JSONArray
#SerializedName("prices")
private List<JSONArray<Price>> prices;
but that's not quite right
I've tried searching other SO answers but I could not find any examples where it's two consecutive [ [ brackets.
They are all { [ or [ {.
What's the correct way to do it?
The proper way to solve this is to write a custom TypeAdapter for your Price class. This has the advantage that you can keep your model classes as is (with a List<Price> prices field), and have them represent more closely the actual data. If instead you parsed the JSON data as List<List<BigDecimal>> or similar, then you would have to manually validate that the JSON data is wellformed and have to convert the List<BigDecimal> to a Price object yourself.
Here is how a TypeAdapter implementation for your Price class could look like:
class PriceTypeAdapter extends TypeAdapter<Price> {
#Override
public void write(JsonWriter out, Price value) throws IOException {
out.beginArray();
out.value(value.date);
out.value(value.price);
out.endArray();
}
#Override
public Price read(JsonReader in) throws IOException {
in.beginArray();
Price priceObj = new Price();
priceObj.date = in.nextLong();
// nextString() automatically converts JSON numbers to String, if necessary
// This is similar to how Gson's default adapter for BigDecimal works
priceObj.price = new BigDecimal(in.nextString());
in.endArray();
return priceObj;
}
}
Note: Alternatively to reading the BigDecimal manually as shown here, you could create this type adapter inside a TypeAdapterFactory and get the default Gson adapter for BigDecimal. This allows reusing Gson's built-in adapters inside your own type adapter, but here for BigDecimal that overhead is probably not worth it.
You can then either register your adapter on a GsonBuilder instance or you can place an #JsonAdapter annotation on your Price class, which references the adapter. In case you use the GsonBuilder approach, you might want to create a null-safe variant of your adapter by calling nullSafe() on it (or you implement null handling in the adapter manually).
Assuming this is the correct JSON:
{
"prices": [
[
1641670404234,
0.01582586939240936
],
[
1641674037525,
0.015999047707867396
],
[
1641677655158,
0.016072905257982606
]
]
}
Then you can use this model to deserialize data to:
JAVA:
public class PricesModel {
public ArrayList<ArrayList<Double>> prices;
}
KOTLIN:
data class PricesModel (
#SerializedName("prices" ) var prices : ArrayList<ArrayList<Double>> = arrayListOf()
)
Handy JSON converters to Java and Kotlin.
I have an Abstract class with many concrete implementations:
public abstract Ticket {
private Long id;
private Currency fine;
...
}
public class SpeedingTicket extends Ticket {
public Currency getFine(){
// Expensive!
...
}
}
public class ParkingTicket extends Ticket {
public Currency getFine(){
// Eh, not so bad
...
}
}
When the concrete classes are serialized into JSON, it is wrapped with the classes simple name (speedingTickets or parkingTickets):
"_embedded": {
"speedingTickets" :
[{
"id":1,
"fine": "$190",
...,
},
{
"id":2,
"fine": "$100",
...,
}]
}
or
"_embedded": {
"parkingTickets" :[{
"id":100,
"fine": "$15",
...,
}]
}
Since I do not know, at runtime, which Ticket implementation I am receiving back, how can I parse the JSON out using the JSON Response API given the array is wrapped with the concrete implementations simple name?
I have a hack where I take the String value of the JSON and do String operations (substring, indexOf, etc) on it to return only what's in between the braces ("[...]"). I know there's a better way to do this...
After some research, I think I'll try the following tomorrow to see if it works:
JsonNode rootNode = mapper.readTree(jsonResponse);
String classImpl = Iterables.get(rootNode.get("_embedded").fields(), 0).textValue()
I can then say List<Ticket> tickets = response.readAsList(jsonResponse, "_embedded",classImpl) which should allow me to parse the JSON into a List
If you're using Jackson (as your tag suggests), you want to use Polymorphic Deserialization - which is exactly the problem of knowing how to deserialize to the correct subtype.
For example:
#JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.PROPERTY, property="#class")
class { }
What this essentially does is include the class name in your JSON, so the deserializer has enough information to properly choose the subclass to instantiate. Something like this:
"_embedded": {
"parkingTickets" :[{
"_type": "ParkingTicket.class",
"id":100,
"fine": "$15",
...,
}]
}
You can just check the type by checking the variable the response contains.
JSONObject jsonObj = new JSONObject(response);
if(jsonObj.has("speedingTickets")){
// parse speedingTickets
}else if(jsonObj.has("parkingTickets")){
// parse parkingtickets
}
A JSON object is an unordered set of key/value pairs. A JSON array is an ordered collection of values. The values themselves could be objects or arrays.
In java it is easy to parse json with org.json library https://github.com/stleary/JSON-java
Short example how to parse json array:
String str = "{ \"number\": [3, 4, 5, 6] }";
JSONObject obj = new JSONObject(str);
JSONArray arr = obj.getJSONArray("number");
for (int i = 0; i < arr.length(); i++)
System.out.println(arr.getInt(i));
I am looking for a generic way to deserialise with Jackson a JSON such as:
{
"hello": "baby",
"eyes": "[blue,green]"
}
To a POJO such as
public class Whatever {
#Setter private String hello;
#Setter private List<Color> eyes;
}
With Color being an enum.
When I try naively like below:
ObjectMapper mapper = new ObjectMapper();
mapper.convertValue(properties, objectClass);
I get the error
Can not deserialize instance of java.util.ArrayList out of VALUE_STRING token
Obviously this is because Jackson can only deserialise arrays from JSON arrays, not their string representation.
I tried to activate ACCEPT_SINGLE_VALUE_AS_ARRAY but it would consider the value of the property "eyes" to be an array with a single String element "[blue,green]" (which fails to convert to the enumeration Color)
Any hint would be very much appreciated.
The problem isn't that ACCEPT_SINGLE_VALUE_AS_ARRAY is causing the "eyes" property to be interpreted as an array with a single element, that option allows Jackson to coerce types so that
{
"hello": "baby",
"eyes": "[blue,green]"
}
would be interpreted the same as
[{
"hello": "baby",
"eyes": "[blue,green]"
}]
This way single elements can be used with Java's Collections more information can be found at
http://fasterxml.github.io/jackson-databind/javadoc/2.0.0/com/fasterxml/jackson/databind/DeserializationFeature.html#ACCEPT_SINGLE_VALUE_AS_ARRAY
As far as your problem goes, the best option would be to have the JSON submitted with color as a JSON array like:
{
"hello": "baby",
"eyes": [
"blue",
"green",
]
}
Otherwise you may need to have your Whatever class have the #JsonSetter annotation on a setEyes method with String parameter where you parse the String to manually create the list of Color yourself.
#JsonSetter
public void setEyes(final String eyes) {
// Parse string and set field here
}
My question is pretty much identical to this one, except that I'm using Java/Jackson instead of C#:
In C# how can I deserialize this json when one field might be a string or an array of strings?
My input JSON can be this:
{ "foo": "a string" }
or this:
{ "foo": ["array", "of", "strings" ] }
My class looks like this:
class MyClass {
public List<String> foo;
}
If the input contains a single string, I want it to become the first entry in the list.
How can I deserialize foo using Jackson? I could write a custom deserializer, which I've done before, but I thought there might be an easier way.
There is a feature called ACCEPT_SINGLE_VALUE_AS_ARRAY which is turned off by default but you can turn it on:
objectMapper = new ObjectMapper()
.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
You can also turn it on per case:
class SomeClass {
#JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
private List<String> items;
// ...
}
Just like in this question, I want to deserialize JSON with a root element using #JsonRootName. But in my case, the value of the root field is an array with exactly one object instead of just an object.
So instead of this
{
"user":
{
"name":"Sam Smith",
"age":1
}
}
I have this
{
"user":[
{
"name":"Sam Smith",
"age":1
}
]}
I cannot simply use
#JsonRootNode(value="user")
public class User {
public String name;
public Integer age;
}
because that would produce a JsonMappingException: Can not deserialize instance of User out of START_ARRAY token.
Is there a way to tell jackson to ignore the array and just look at the object?