1

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
2
  • What did you try? There is nothing particularly difficult about that JSON to parse. Commented Sep 12, 2018 at 22:21
  • @RoddyoftheFrozenPeas I edited with an error and some code. I agree that it should be a pretty painless operation. Thank you for your help. Commented Sep 12, 2018 at 22:48

1 Answer 1

2

The error message clearly specifies there is no default constructor (which is no argument constructor) in your ChannelData class, create no argument constructor in ChannelData class.

Since you declared public ChannelData(int channel, List<Data> data) ChannelData argument constructor, it is your responsibility to declare no argument constructor

public class ChannelData {
      public ChannelData() { // no arg constructor }
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.