2

I have a structure like so:

{
    "name": "user",
    "values":[["0.00207760","18.48000000"],["0.00207740","40.00000000"],["0.00207710","2.26000000"]]
}

I'd like to deserialize into a class like so using the popular Jackson library:

public class Values {

    public String name;

    public Map<BigDecimal, BigDecimal> values = new HashMap<>();

}

Where each entry in the values property becomes a key/value entry in the class' map.

However, if I attempt a simple deserialization with Jackson I get this error:

com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.util.TreeMap<java.lang.Object,java.lang.Object>` out of START_ARRAY token
 at [Source: (String)"{"name": "user","values":[["0.00207760","18.48000000"],["0.00207740","40.00000000"],["0.00207710","2.26000000"]]...
    at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:59)
    at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1442)
    at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1216)
    ...

How can this be accomplished using Jackson?

Thanks!

Eduardo

0

2 Answers 2

2

You expect Map which on JSON side is represented by JSON Object but there is a JSON Array which can be mapped by default to List, Set or array. I suggest to use List<List<BigDecimal>> in POJO and create a method which converts data to Map:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;

import java.io.File;
import java.math.BigDecimal;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class JsonPathApp {

    public static void main(String[] args) throws Exception {
        File jsonFile = new File("./resource/test.json").getAbsoluteFile();

        ObjectMapper mapper = JsonMapper.builder().build();
        Values values = mapper.readValue(jsonFile, Values.class);
        System.out.println(values.getValuesAsMap());
    }
}

class Values {

    private String name;
    private List<List<BigDecimal>> values;

    public Map<BigDecimal, BigDecimal> getValuesAsMap() {
        return values.stream().collect(Collectors.toMap(
                k -> k.get(0),
                v -> v.get(1),
                (u, v) -> {
                    throw new IllegalStateException(String.format("Duplicate key %s", u));
                },
                LinkedHashMap::new));
    }

    // getters, setters, toString
}

Above code prints:

{0.00207760=18.48000000, 0.00207740=40.00000000, 0.00207710=2.26000000}

In other case, you need to implement a custom deserialiser for a Map and register it for this field using @JsonDeserialize annotation.

Sign up to request clarification or add additional context in comments.

Comments

0

List<List> works with the same data type in the inner array. I however got a map that was converted into a nested jsonArray with the value being a jsonObject.

https://riptutorial.com/java/example/18575/deserialize-json-collection-to-collection-of-objects-using-jackson gave me the answer.

JSON:

{
 "history": [
  [
    2,
    {
      "trx_id": "4014ae64ae9c45861ed4f0af30224b6741dcbb46",
      ...
      "operation_id": 0
    }
  ],
  [
    3,
    {
      "trx_id": "a4023a3641ffc112324427523945f641d88c5eae",
      ...
      "operation_id": 0
    }
  ]
 ]
}

3 class answer:

public class HistoryListResponse {
   private List<HistoryMapEntryResponse> history;
}

2ed class:

@JsonFormat(shape = JsonFormat.Shape.ARRAY)
@JsonPropertyOrder({ "key", "trx"})
public class HistoryMapEntryResponse {
  private int key;
  private HistoryTrxResponse trx;
}

And then back to normal json:

public class HistoryTrxResponse {
   private String trx_id;
   ...
   private int operation_id;
}

Still will need a method to convert the list back into a Map, but it is pretty close, and the inner data gets parsed/deserialized.

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.