Ignore the “Can not deserialize instance of java.util.LinkedHashMap out of START_ARRAY token” error

匿名 (未验证) 提交于 2019-12-03 02:33:02

问题:

I am using an API from an external partner. Unfortunately, the returned response does not seem to have a fixed structure. Ideally, an API contract means it won't be violated but this keeps happening.

Anyways, so what is happening is a field in the JSON response is mostly a map but sometimes, out of the blue it is a list.

For example, suppose that following is the response I usually get:

{   "majorInfo" : {     "a" : "b"   },   "minorInfo" : {     "c" : "d"   } } 

But on rare occasion I'd get a list instead of a map or some other violation of the contract.

For example:

{   "majorInfo" : {     "a" : "b"   },   "minorInfo" : [] } 

I am using jackson to map this response to a POJO. In cases, when the contract is violated, I get the error,

Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.util.LinkedHashMap out of START_ARRAY token

In this case, I lose the information in the field majorInfo as well even though that adhered to the contract. Is there any way that I can ignore a field when it does not adhere to the contract? In this case, majorInfo member of my POJO would be correctly set but minorInfo member would be null.

I know about @JsonIgnoreProperties(ignoreUnknown = true) but that would always ignore the minorInfo field. I would only like it to be ignored when the field does not adhere to the contract. Is that possible?

I also tried

mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);  

but this did not work either.

Is any other solution possible? The external partner is not going to change their API for us that is for sure. So, any workable solution from our end?

Thank you

Edit: One solution is I have a POJO for both variants and put the code in a try catch block. That may have worked if the JSON response had just one field that violated the contract and only in one particular way. The response I'm actually getting is huge and this is the third violation I have caught on a third field. I can't keep putting try catch blocks and by the third violation I've realized the best bet is to just ignore the fields violating it.

回答1:

I found a solution using the following thread as reference: Jackson: ignoring properties instead of throwing JsonMappingException

I wrote a custom deserializer and used it to ignore errors.

public class CustomListingDeserializer extends JsonDeserializer<Map<String, Listing>>{      public CustomListingDeserializer() {         // TODO Auto-generated constructor stub     }      @Override     public Map<String, Listing> deserialize(JsonParser arg0, DeserializationContext arg1)             throws IOException, JsonProcessingException {          ObjectMapper mapper = new ObjectMapper();         JsonNode node = arg0.readValueAsTree();          try         {             return mapper.readValue(node.toString(), new TypeReference<Map<String,Listing>>(){});          }         catch (JsonMappingException e)         {             System.out.println("Issue in deserializing : " + e.getMessage() + "for :" + node.toString());         }         catch (Exception e)         {             throw e;         }         // TODO Auto-generated method stub         return null;     }  } 


回答2:

You can write your own java method for transforming an input json to a "standard" json that adheres to the contract, and then use Jackson on it.

something along the lines of:

private String transform(String input) {     String result = input;      if (result.contains("\"minorInfo\" : []"))     {         result = result.replace("\"minorInfo\" : []", "");     }      return result; } 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!