Specifically, I am dealing with a JSON string representing an Array containing numbers and other arrays of numbers - these strings are of the form String string = "[0, [1, 2], [3, 4]]". It represents data of the form [ channelID, [price, amount], [price, amount] ... [price, amount]]; The repeating data can be varying lengths.
My end goal is to turn this string into an object of the form ChannelObject { channel: 0, data: [PriceObject { price: 1, amount: 2 }, PriceObject { price: 3, amount: 4 }] }.
Jackson's native objectMapper throws errors while trying to read the value of an un-encapsulated JSON array to a class, and the only solution I have found is by giving the ObjectMapper parser the string { "data": %s }, substituting in the original JSON, and using class with property @JsonProperty ArrayNode data, but I'm afraid this is an inefficient approach as far as performance.
Is writing a deserializer for "naked" JSON arrays the smartest approach? Is there an easier solution I am missing?
Responses are much appreciated.
Additional info:
ObjectMapper doesn't work.
public static void main(String args[]) {
String input = "[17847,[5391.9,0,-1]";
ObjectMapper mapper = new ObjectMapper();
List<ChannelData> list = mapper.readValue(input, ChannelData[].class);
}
public class ChannelData {
private int channel;
private List<Data> data;
public ChannelData(int channel, List<Data> data) {
this.channel = channel;
this.data = data;
}
public int getChannel() {
return channel;
}
public void setChannel(int channel) {
this.channel = channel;
}
public List<Data> getData() {
return data;
}
public void setData(List<Data> data) {
this.data = data;
}
}
public class Data {
private BigDecimal price;
private int count;
private BigDecimal amount;
public Data() {
}
public Data(BigDecimal price, int count, BigDecimal amount) {
this.price = price;
this.count = count;
this.amount = amount;
}
public BigDecimal getPrice() {
return price;
}
public void setPrice(BigDecimal price) {
this.price = price;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public BigDecimal getAmount() {
return amount;
}
public void setAmount(BigDecimal amount) {
this.amount = amount;
}
}
Error:
Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `co.myproject.Application$ChannelData` (no Creators, like default construct, exist): no int/Int-argument constructor/factory method to deserialize from Number value (17847)
at [Source: (String)"[17847,[5391.9,0,-1]]"; line: 1, column: 2] (through reference chain: java.lang.Object[][0])
at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67)
at com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1451)
at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1027)
at com.fasterxml.jackson.databind.deser.ValueInstantiator.createFromInt(ValueInstantiator.java:262)
at com.fasterxml.jackson.databind.deser.std.StdValueInstantiator.createFromInt(StdValueInstantiator.java:356)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromNumber(BeanDeserializerBase.java:1324)
at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:173)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:161)
at com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.java:195)
at com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.java:21)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4013)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3004)
at co.myproject.Application.run(Application.java:27)
at co.myproject.Application.main(Application.java:39)
Process finished with exit code 1