1

I am trying to consume a REST Service using RestTemplate. I am having trouble deserializing the JSON response. I am using a custom Deserializer and my JSON has 3 nodes, but it looks like only one is reaching the deserializer. Below are more details.

Below is the response JSON:

{
    "Hello": {
        "Hi": "Name1",
        "Call": "PhoneNumber1"
    },
    "Hello": {
        "Hi": "Name2",
        "Call": "PhoneNumber2"
    },
    "Hello": {
        "Hi": "Name3",
        "Call": "PhoneNumber3"
    }
}

I am using a custom deserializer on the Response Class for attribute Hello using @JsonDeserializer.

When i do a readTree like below:

JsonNode node = jp.getCodec().readTree(jp);

it reaches the deserialize method, it looks like it is having only one node instead of 3 like below. Sometimes it has the first node and sometimes the last. What could be going wrong here?

Thanks in advance for looking at this question and helping out!

ANSWER: As others mentioned, this JSON is invalid and hence Jackson is not able to deserialize it. I had to get the response as a String and then deserialize manually.

mandy
  • 735
  • 1
  • 9
  • 24

2 Answers2

1

That is most likely because that is invalid JSON, you can't have three nodes with the same name.

Or strictly speaking it's not an error but only one of the items named "Hello" will be accounted for as stated in this answer, which is bad since json does not guarantee the order of the items in an object only the order of items in lists.

If you have the possibility to change the response, I would go with creating an array of objects instead.

{ "Hello": [ { "Hi": "Name1", "Call": "PhoneNumber1" }, { "Hi": "Name2", "Call": "PhoneNumber2" }, { "Hi": "Name3", "Call": "PhoneNumber3" } ] } Then you would get a JsonNode that is an array of JsonNodes which you can iterate over.

Community
  • 1
  • 1
Daniel Figueroa
  • 10,348
  • 5
  • 44
  • 66
  • i am consuming a service which exists in production today and is being used in other places. Can i convert the JSON to array after receiving the response? – mandy Jun 21 '16 at 23:10
  • Maybe this answer can help you: http://stackoverflow.com/questions/27710471/java-json-with-duplicate-keys-to-map-using-jackson, make sure to read the comments there as well :) – Daniel Figueroa Jun 21 '16 at 23:46
  • Thanks @Daniel, i will try Guava and update it here. – mandy Jun 21 '16 at 23:54
1

JsonNode is a superclass without specific content behavior. In your example you should get an ObjectNode but as your properties all have the same name only one "Hello" property will remain. readTree() is a generic method which do auto cast to your needed return type if possible.

If you really need this you have to move your JSON to an array structure:

// you will get one ArrayNode containing multiple ObjectNode
[
  {
    "Hello": {
      "Hi": "Name1",
      "Call": "PhoneNumber1"
    }
  },
  {
    "Hello": {
      "Hi": "Name2",
      "Call": "PhoneNumber2"
    }
  },
  {
    "Hello": {
      "Hi": "Name3",
      "Call": "PhoneNumber3"
    }
  }
]

or

// you will get one ObjectNode containing one property with an ArrayNode
{
  "Hello": [
    {
      "Hi": "Name1",
      "Call": "PhoneNumber1"
    },
    {
      "Hi": "Name2",
      "Call": "PhoneNumber2"
    },
    {
      "Hi": "Name3",
      "Call": "PhoneNumber3"
    }
  ]
}
Arne Burmeister
  • 20,046
  • 8
  • 53
  • 94
  • i am consuming a service which exists in production today and is being used in other places. Can i convert the JSON to array after receiving the response? – mandy Jun 21 '16 at 23:10
  • Sorry, this will never work with Jackson imho as ObjectNode is considered to have unique keys. – Arne Burmeister Jun 22 '16 at 06:13
  • The only way to do so would be a full custom deserializer without using tree methods but instead parsing using `getCurrentToken()`, `get...Value()` and `nextToken()`. An parse that to a list or multi map type. Will be a lot of work but could work at the end. – Arne Burmeister Jun 23 '16 at 22:13
  • what you mentioned is true. But instead of getting tokens, i ended up using a regex to collect each node in the response string and then use ObjectMapper on each of the collected node which is a valid JSON to deserailize that to a POJO. – mandy Jun 28 '16 at 17:56