【问题标题】:Ignore the "Can not deserialize instance of java.util.LinkedHashMap out of START_ARRAY token" error忽略“无法从 START_ARRAY 令牌中反序列化 java.util.LinkedHashMap 实例”错误
【发布时间】:2016-06-05 03:08:27
【问题描述】:

我正在使用来自外部合作伙伴的 API。不幸的是,返回的响应似乎没有固定的结构。理想情况下,API 合同意味着它不会被违反,但这种情况一直在发生。

无论如何,JSON 响应中的一个字段主要是一个地图,但有时,它却是一个列表。

例如,假设以下是我通常得到的响应:

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

但在极少数情况下,我会得到一份清单而不是地图或其他违反合同的行为。

例如:

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

我正在使用 jackson 将此响应映射到 POJO。如果违反合同,我会收到错误消息,

线程“main”中的异常 com.fasterxml.jackson.databind.JsonMappingException:不能 从 START_ARRAY 中反序列化 java.util.LinkedHashMap 的实例 令牌

在这种情况下,即使遵守合同,我也会丢失字段 majorInfo 中的信息。当一个字段不遵守合同时,有什么方法可以忽略它?在这种情况下,我的 POJO 的 majorInfo 成员将被正确设置,但 minorInfo 成员将为空。

我知道@JsonIgnoreProperties(ignoreUnknown = true) 但这会总是忽略minorInfo 字段。我只希望在该字段不遵守合同时忽略它。这可能吗?

我也试过

mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); 

但这也不起作用。

还有其他可能的解决方案吗?可以肯定的是,外部合作伙伴不会为我们更改他们的 API。那么,我们有什么可行的解决方案吗?

谢谢

编辑: 一种解决方案是我对这两种变体都有一个 POJO,并将代码放在 try catch 块中。如果 JSON 响应中只有一个字段违反了合同并且仅以一种特定方式,那么这可能会奏效。我实际上得到的回应是巨大的,这是我在第三场比赛中发现的第三次违规。我无法继续放置 try catch 块,到第三次违规时,我意识到最好的选择就是忽略违规的字段。

【问题讨论】:

  • FAIL_ON_INVALID_SUBTYPE, false 怎么样? (抱歉,目前不在我的机器前)
  • @jmcg 我试过了。还是不行。得到同样的错误。

标签: java json rest jackson


【解决方案1】:

我找到了一个使用以下线程作为参考的解决方案: Jackson: ignoring properties instead of throwing JsonMappingException

我编写了一个自定义反序列化器并用它来忽略错误。

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】:

    您可以编写自己的 java 方法,将输入 json 转换为符合合同的“标准”json,然后在其上使用 Jackson。

    类似的东西:

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

    【讨论】:

    • 如果它是一个空列表,这将起作用。如果列表有元素怎么办?在这种情况下,也许一个花哨的正则表达式会起作用。但是如果它是一个 Integer 或 String 而不是一个列表而不是一个映射呢?
    • 当然,java 方法需要处理所有情况。我只是发布了一个简单的例子来说明这一点。
    • 是的,我明白了。但是我觉得有很多可能的情况(因为我们不知道可能性的数量),这会导致冗长乏味和笨拙的代码。我认为更好的方法是忽略导致错误的属性。如果有办法做到这一点。
    猜你喜欢
    • 2018-12-03
    • 1970-01-01
    • 2014-06-11
    • 2020-09-23
    • 2020-06-16
    • 1970-01-01
    • 1970-01-01
    • 2016-07-30
    • 2015-03-10
    相关资源
    最近更新 更多