Cannot deserialize instance of `java.lang.String` out of START_OBJECT token
Asked Answered
O

1

9

I am getting the below error message, can someone please help or suggest how best to debug this.

Cannot deserialize instance of java.lang.String out of START_OBJECT token at [Source: (PushbackInputStream); line: 1, column: 37610] (through reference chain: com.model.ProductList["products"]->java.util.ArrayList[23]->com.model.Product["price"]->com.Price["now"])

I am trying to deserialise a Products object from a REst API call. The code has been working fine until I added code to deserialise a Price sub-class. This looks as follows,

"price": {
        "was": "",
        "then1": "",
        "then2": "",
        "now": "59.00",
        "uom": "",
        "currency": "GBP"
      },

My Price pojo looks as follows,

public class Price {

     @JsonProperty("was")
     String was;
     @JsonProperty("then1")
     String then1;
     @JsonProperty("then2")
     String then2;
     @JsonProperty("now")
     String now;
     @JsonProperty("uom")
     String uom;
     @JsonProperty("currency")
     String currency;

     public Price() {
         //blank constructor for JSON
     }

     @Override
     public String toString() {
         return "Price{" +
                 "was='" + was + '\'' +
                 ", then1='" + then1 + '\'' +
                 ", then2='" + then2 + '\'' +
                 ", now='" + now + '\'' +
                 ", uom='" + uom + '\'' +
                 ", currency='" + currency + '\'' +
                 '}';
     }
}

I have written a Junit test to try and simulate the error but it works in my test,

    @Test
    public void shouldConvertJsonProductListIntoPrice() {
        ObjectMapper objectMapper = new ObjectMapper();
        String content3 = "{\"products\": [{\"productId\": \"3525085\",\"title\": \"hush Tasha Vest Dress\", " +
                "\"price\": {\"was\": \"\",\"then1\": \"\",\"then2\": \"\",\"now\": \"59.00\",\"uom\": \"\",\"currency\": \"GBP\"}, " +
                "\"colorSwatches\": [{\"basicColor\": \"Red\",\"skuId\": \"237494589\"},{\"basicColor\": \"Blue\",\"skuId\": \"237494562\"}] " +
                "}]}";
        JavaType valueType = objectMapper.constructType(ProductList.class);
        ProductList readValue;
        try {
            readValue = objectMapper.readValue(content3, valueType);
            assertEquals("3525085", readValue.getProductList().get(0).productId);
            assertEquals("hush Tasha Vest Dress", readValue.getProductList().get(0).title);
            assertEquals("", readValue.getProductList().get(0).price.then1);
            assertEquals("59.00", readValue.getProductList().get(0).price.now);
            assertEquals("Blue", readValue.getProductList().get(0).colorSwatches[1].basicColor);
            assertEquals("237494562", readValue.getProductList().get(0).colorSwatches[1].skuId);
        } catch (Exception e) {
            e.printStackTrace();
            fail();
        }
    }

If I comment out the "now" field then my RestAPI call works perfectly and I dont see the exception. So it seems that there is a problem with the "now" field and here I notice that its trying to convert "59.00" into a String. Could this be a problem for the Fasterxml converter ? do I need to help it maybe ?

The Product class is as follows (although this is much reduced list of fields that I am receiving off the API call).

public class Product {

     @JsonProperty("productId")
     String productId;

     @JsonProperty("title")
     String title;

     @JsonProperty("colorSwatches")
     ColorSwatch [] colorSwatches;

     @JsonProperty("price")
     Price price;

     public Product(){
         // blank required for Jackson
     }

     public Product(String productId, String title, ColorSwatch[] colorSwatches, Price price){
         this.productId = productId;
         this.title = title;
         this.colorSwatches = colorSwatches;
         this.price = price;
  }
Okoka answered 6/1, 2019 at 14:25 Comment(11)
Why are you parsing and constructing JSON Manually? Why not let Spring/Jackson do this for you?Jamajamaal
Hi Todd, the error I reported above is coming from Spring/Jackson. I wrote the Unit Test to try and see if I could reproduce the error but I wasnt able to. Unless I have misunderstood you. Have I added code which I should be leaving to Spring/Jackson to do for me ?Okoka
I tried using your code and it works well! Show us your product class as well if you can.Nittygritty
thanks ScanQR - how did you test it ? I seem to get it when call the full RestAPI and the Spring/Jackson processes are handling the unmarshalling.Okoka
Your test case doesn't represent what you are doing. Your test case should test Products object which contains with Price object. Then you will get a real test case.Sackbut
@JonathanJohx I've updated the question now by replacing the UnitTest of Price with one for Product and this works fine.Okoka
@Nittygritty I've included the details for ProductOkoka
@Okoka I think you need to test it from ProductList class which you have. Please try to replicate the same values that you are doing. And can you add code where you can you are calling to the deserializer?thank youSackbut
@JonathanJohx I've updated the test for ProductList as you suggested, that was a good call. And the test still passes ! I am not quite sure how I can add debug code into the deserialiser part - that bit of the application seems to be hidden from me - the specific line I am executing in the Controller is shown below ResponseEntity<ProductList> restRes = restTemplate.exchange("jl-nonprod-syst.apigee.net/v1/categories/600001506/…", HttpMethod.GET, entity, ProductList.class);Okoka
@JonathanJohx As I mentioned in the question this works fine when I comment out the "now" field on my Price object.Okoka
Generally this kind of exception means that JSON does not fit POJO classes. Lets try a trick, instead of class Price in Product use Map. For example: Map<String, Object> price and try to deserialise. In case it will success add a String representation of that Map to a question.Aitchbone
L
17

The error states it expects a VALUE (VALUE_STRING preferably), whereas it gets a START_OBJECT, so your issue is probably coming from a json of the form

"price": {
    "was": "",
    "then1": "",
    "then2": "",
    "now":  {
        ...
    }
    "uom": "",
    "currency": "GBP"
},

Instead of the "now": "some value" form expected by the code.

Lilybelle answered 7/1, 2019 at 16:58 Comment(6)
wow well done I think that might be it. I just searched the record set and found at record 25 of 50 an entry similar to how you've described,Okoka
{ "productId": "3341058", "type": "product", "title": "Jolie Moi Bonded Lace Prom Dress", "code": "69251713", "averageRating": 0, "reviews": 0, "price": { "was": "85.00", "then1": "68.00", "then2": "", "now": { "from": "59.00", "to": "68.00" }, "uom": "", "currency": "GBP" },Okoka
its a pity I cant format the record as nicely as you have in your example. Tomorrow I will check it in my app but I am pretty sure thats it.Okoka
If that is the case then do you know how I should reprensent the data type - it looks like it can either be sent as a String or an Object Type - how should I define that in my pojo ?Okoka
thank you your tip has helped me to fix my problem. I changed the "now" field in my Price pojo from String to Object and re-ran my project and it now works. I will need to develop some way now of deserialising this Object for either a String or a field which can contain two sub-fields "from" and "to" as shown above. I have marked this question as answered.Okoka
You are welcome. For deserializing a node that can be either a String or an Object, you could give a look to @JsonSerialize giving a custom JsonDeserializerLucite

© 2022 - 2024 — McMap. All rights reserved.