PKR
PKR

Reputation: 228

Deserialization of JSON array

I'm not sure how to deserialize array containing plain strings.I'm trying to parse the following JSON

 {  
   "state":"RT",
   "testMethod":"electronic", 
   "testElements":[  
      {  
         "testId":[  
            "UT_ITXref",
            "Fed_ITXref"
         ]
      },
      "testStartDate",
      "testEndDate",
      "testDueDate"
   ]
}

I'm getting the following error:

com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of com.test.rules.model.TestElements: no String-argument constructor/factory method to deserialize from String value ('testStartDate')
 at [Source: {"state":"RT","testMethod":"electronic","testElements":[{"testId":["UT_ITXref","Fed_ITXref"]},"testStartDate","testEndDate","testDueDate"}]}; line: 1, column: 247] (through reference chain: com.test.rules.model.TestRules["testElements"]->java.lang.Object[][1])
    at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:270)
    at com.fasterxml.jackson.databind.DeserializationContext.instantiationException(DeserializationContext.java:1456)
    at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1012)
    at com.fasterxml.jackson.databind.deser.ValueInstantiator._createFromStringFallbacks(ValueInstantiator.java:370)
    at com.fasterxml.jackson.databind.deser.std.StdValueInstantiator.createFromString(StdValueInstantiator.java:315)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromString(BeanDeserializerBase.java:1282)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:159)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:150)
    at com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.java:196)
    at com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.java:20)
    at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:499)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeWithErrorWrapping(BeanDeserializer.java:511)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeUsingPropertyBased(BeanDeserializer.java:396)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1198)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:314)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:148)
    at com.fasterxml.jackson.databind.ObjectReader._bindAndClose(ObjectReader.java:1626)
    at com.fasterxml.jackson.databind.ObjectReader.readValue(ObjectReader.java:1220)

Here is what I did , I used @JsonCreator annotation to deserialize

public class TestRules {

    private String state;   
    private String testMethod;  
    private TestElements[] testElements;    

     @JsonCreator
        public TaxRules(
          @JsonProperty("state") String  state,     
          @JsonProperty("testMethod") String testMethod,          
          @JsonProperty("testElements") TestElements[] testElements
          ) {
            this.state = state;         
            this.testMethod = testMethod;          
            this.testElements = testElements;          
        }   

}

 public class TestElements {
    private List<String> testId;
    private List<String> elements;  

    public List<String> getElements() {
            return elements;
        }
        public void setElements(List<String> elements) {
            this.elements = elements;
        }
        public List<String> getTestId() {
            return testId;
        }
        public void setTestId(List<String> testId) {
            this.testId = testId;
        }   

}

Should I write custom deserializer or Is there any way that I can use the jackson API for this. Any suggestions would be appreciated.

Upvotes: 0

Views: 962

Answers (2)

Atreys
Atreys

Reputation: 3761

{
    "state": "RT",
    "testMethod": "electronic",
    "testElements": [
        {
            "testId": [
                "UT_ITXref",    // <-- this object is deserialized just fine
                "Fed_ITXref"
            ]
        },
        "testStartDate",     // <-- this is where the error is happening
        "testEndDate",
        "testDueDate"
    ]
}

Did you intend the json to be interpreted as if it looked like the following?

{
    "state": "RT",
    "testMethod": "electronic",
    "testElements": [
        {
            "testId": [
                "UT_ITXref",
                "Fed_ITXref"
            ]
        },
        {
            testId: [
                "testStartDate"
            ]
        },
        {
            testId: [
                "testEndDate"
            ]
        },
        {
            testId: [
                "testDueDate"
            ]
        }
    ]
}

If so, you'll need to make a custom deserializer to detect whether the element in the array is an object or a string. If it's a string, you'll probably want to construct the TestElement yourself.

Upvotes: 0

Vadim
Vadim

Reputation: 4120

Actually errors tells something.

JSON parser found that for testElements property there is an Array of Objects, but your Json file has mixed content.

first element is an object (I assume it is TestElement class). Then parser creates that object with empty constructor and calls appropriate setters for its properties. but...

second,third and forth elements are String, so error says that parser tries to find constrictor with String as argument.

So, you may try to make that constructor in TestElement class and see will it work or not... Do not forget to keep empty constructor as well.

I cannot guarantee it will work but, at least error says that.

BTW are you sure your Json object is correct? but not something like that?

{  
 "state":"RT",
 "testMethod":"electronic", 
 "testElements":[  
  {  
     "testId":[  
        "UT_ITXref",
        "Fed_ITXref"
     ]
  }],
  "testStartDate":"01-01-2017",
  "testEndDate":"01-02-2017",
  "testDueDate":"01-03-2017"
}

I'm a little confused because StartDate, EndDate, DueDate semantically look more like test attributes, not as elements in testElements array

Upvotes: 1

Related Questions