1

Given the JSON string I need to convert it to my POJO named TransactionInfo

JSON String

{
  "transactionId": "EFODKKXHE003",
  "isSettled": false,
  "transactionProperties": [
    {
      "key1": "Value1"
    },
    {
      "key2": "Value2"
    },
    {
      "key3": "Value3"
    }
  ]
}

POJO

class TransactionInfo {
   String transactionId;
   Boolean isSettled;
   Map<String,String> transactionProperties;
}

Additional Note (From comment)

After the deserialization, I want to access different keys in the transactionProperties map. If it's converted into a List<Map<String,String>> then it becomes complex. FYI, the keys are guaranteed to be unique so in the end, I want one single flat map. Another point, I don't need to serialize TransactionInfo back to JSON.

What I tried

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.readValue(jsonString, TransactionInfo.class);

But I am getting an exception like below:


Cannot deserialize value of type java.util.LinkedHashMap<java.lang.String,java.lang.Object> from Array value (token JsonToken.START_ARRAY)

Can anyone guide me on how to do that properly? Any help is much appreciated.


Edit

I have already gone through the following post(s) but none of them seems to match my use case

6
  • 1
    [...] represents list/array of elements. So instead of Map<String,String> transactionProperties; you want List<Map<String,String>> transactionProperties; Commented Jul 30, 2022 at 18:41
  • Thanks, @Pshemo. After the deserialization, I want to access different keys in the transactionProperties map. If it's converted into a List<Map<String,String>> then it becomes complex. FYI, the keys are guaranteed to be unique so at the end I want one single flat map. Any idea how to make it better? Commented Jul 30, 2022 at 18:50
  • 1
    "keys are guaranteed to be unique so at the end I want one single flat map" consider adding that information to the question since it looks like crucial requirement. Commented Jul 30, 2022 at 18:54
  • Thanks for your feedback. Added this information to the question. @Pshemo Commented Jul 30, 2022 at 18:57
  • 1
    Also please clarify what should be result of serialization TransactionInfo back to JSON. Should that flat-map be split back to list of objects with single keys or to single object with many unique keys. If it is split back to array of objects then will their order matter? Commented Jul 30, 2022 at 18:57

2 Answers 2

1

the keys are guaranteed to be unique so in the end, I want one single flat map. Another point, I don't need to serialize TransactionInfo back to JSON.

Since all keys are unique, and you don't care about serialization of this POJO back into JSON, you can transform the list of maps into a map inside a constructor.

public class TransactionInfo {
    String transactionId;
    Boolean isSettled;
    Map<String, String> transactionProperties;

    public TransactionInfo(String transactionId, Boolean isSettled, Map<String, String> transactionProperties) {
        this.transactionId = transactionId;
        this.isSettled = isSettled;
        this.transactionProperties = transactionProperties;
    }

    public TransactionInfo(
        @JsonProperty("transactionId") String transactionId,
        @JsonProperty("isSettled") Boolean isSettled,
        @JsonProperty("transactionProperties") List<Map<String, String>> transactionPropertiesList) {
        
        this.transactionId = transactionId;
        this.isSettled = isSettled;
        this.transactionProperties = transactionPropertiesList.stream()
            .flatMap(map -> map.entrySet().stream())
            .collect(Collectors.toMap(
                Map.Entry::getKey,
                Map.Entry::getValue
            ));
    }
}

Code-snippet from the main():

String json = """
            {
               "transactionId": "EFODKKXHE003",
               "isSettled": false,
               "transactionProperties": [
                 {
                   "key1": "Value1"
                 },
                 {
                   "key2": "Value2"
                 },
                 {
                   "key3": "Value3"
                 }
               ]
             }""";

ObjectMapper mapper = new ObjectMapper();
TransactionInfo transactionInfo = mapper.readValue(json, TransactionInfo.class);
System.out.println(transactionInfo);

Output:

TransactionInfo{transactionId='EFODKKXHE003', isSettled=false, transactionProperties={key1=Value1, key2=Value2, key3=Value3}}
Sign up to request clarification or add additional context in comments.

9 Comments

Thanks for your answer. It solves the problem to some extent but how can I pass the parameters to the constructor like above before the deserialization takes place? The answer assumes that I do have the List<Map<String, String>> already.
@1000111 You mean how to instantiate TransactionInfo in normal situations by passing a Map? You can preserve a normal all-args constructor, it would not interfere with JSON-deserialization (see update). I've just verified it on my machine.
No, I didn't mean that. Okay, let me rephrase my query. Can you please show how to use your solution given theJSON string (using ObjectMapper)?
@1000111 You can use it like ObjectMapper om = new ObjectMapper(); TransactionInfo transactionInfo = om.readValue(jsonString, TransactionInfo.class);
@1000111 Then, it's better to change the serialization to JSON to keep the constructor simple. You can open a separate question and provide the code from the Controller in which this endpoint resides. Feel free to notify me by posting the link here.
|
0

One option is to change the type of the transactionProperties field to List<ObjectNode> then iterate over the list and for each element use it's fields() method to retrieve its members

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.