You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

保留JSON中的$schema元数据时解决Jackson ObjectMapper的MismatchedInputException异常问题

保留JSON中的$schema元数据时解决Jackson ObjectMapper的MismatchedInputException异常问题

嗨,这个问题我之前也碰到过!你配置的@JsonIgnoreProperties(ignoreUnknown = true)和FAIL_ON_UNKNOWN_PROPERTIES = false之所以没用,核心原因是Jackson处理EnumMap的逻辑和普通Java对象不一样:

当你反序列化EnumMap<TestCaseEnum, MailingRequest>时,Jackson会把JSON里的每一个键都尝试转换成TestCaseEnum枚举的有效值,而$schema显然不在你的枚举选项里,所以它会直接抛出MismatchedInputException——这个时候Jackson并不是把$schema当成MailingRequest的未知属性,而是当成EnumMap的键来解析,所以那些忽略未知属性的配置根本不会生效。

下面给你两种实用的解决方案:

方案一:先用HashMap接收,再转成EnumMap

这种方法最简单直接,先用HashMap容纳所有JSON键值对,再手动把属于枚举的键值对提取到EnumMap中,非枚举键(比如$schema)可以直接忽略:

ObjectMapper objectMapper = new ObjectMapper();

// 第一步:把JSON反序列化成HashMap,容纳所有键值对
HashMap<String, Object> tempMap = objectMapper.readValue(
    MailingRequestFactory.class.getResource("/test-data.json"),
    new TypeReference<HashMap<String, Object>>() {}
);

// 第二步:提取枚举相关的键值对到EnumMap
EnumMap<TestCaseEnum, MailingRequest> mailingRequestCache = new EnumMap<>(TestCaseEnum.class);
for (Map.Entry<String, Object> entry : tempMap.entrySet()) {
    try {
        // 尝试把键转成枚举值
        TestCaseEnum enumKey = TestCaseEnum.valueOf(entry.getKey());
        // 把对应的值转成MailingRequest对象
        MailingRequest request = objectMapper.convertValue(entry.getValue(), MailingRequest.class);
        mailingRequestCache.put(enumKey, request);
    } catch (IllegalArgumentException e) {
        // 碰到非枚举键(比如$schema)时直接忽略,也可以在这里做其他处理
        System.out.println("自动忽略非枚举键:" + entry.getKey());
    }
}

方案二:自定义EnumMap反序列化器

如果不想每次都手动转换,可以写一个自定义的反序列化器,让Jackson自动忽略非枚举键:

第一步:实现自定义反序列化器

public class IgnoringEnumMapDeserializer<K extends Enum<K>, V> extends StdDeserializer<EnumMap<K, V>> {
    private final Class<K> enumClass;
    private final Class<V> valueClass;

    public IgnoringEnumMapDeserializer(Class<K> enumClass, Class<V> valueClass) {
        super(EnumMap.class);
        this.enumClass = enumClass;
        this.valueClass = valueClass;
    }

    @Override
    public EnumMap<K, V> deserialize(JsonParser parser, DeserializationContext context) throws IOException {
        EnumMap<K, V> enumMap = new EnumMap<>(enumClass);
        JsonNode rootNode = parser.getCodec().readTree(parser);

        // 遍历所有JSON键值对
        for (Iterator<Map.Entry<String, JsonNode>> iterator = rootNode.fields(); iterator.hasNext(); ) {
            Map.Entry<String, JsonNode> entry = iterator.next();
            String keyStr = entry.getKey();
            try {
                // 尝试转换为枚举键
                K enumKey = Enum.valueOf(enumClass, keyStr);
                // 转换值为目标对象
                V value = parser.getCodec().treeToValue(entry.getValue(), valueClass);
                enumMap.put(enumKey, value);
            } catch (IllegalArgumentException e) {
                // 忽略无法转换为枚举的键
                continue;
            }
        }
        return enumMap;
    }
}

第二步:注册反序列化器并使用

ObjectMapper objectMapper = new ObjectMapper();
SimpleModule customModule = new SimpleModule();

// 注册针对你的EnumMap类型的反序列化器
customModule.addDeserializer(
    new TypeReference<EnumMap<TestCaseEnum, MailingRequest>>() {},
    new IgnoringEnumMapDeserializer<>(TestCaseEnum.class, MailingRequest.class)
);

objectMapper.registerModule(customModule);

// 现在可以直接反序列化了,$schema会被自动忽略
EnumMap<TestCaseEnum, MailingRequest> mailingRequestCache = objectMapper.readValue(
    MailingRequestFactory.class.getResource("/test-data.json"),
    new TypeReference<EnumMap<TestCaseEnum, MailingRequest>>() {}
);

两种方案都能解决问题,第一种适合快速实现,第二种适合需要多次使用的场景,你可以根据自己的需求选择~

备注:内容来源于stack exchange,提问作者grappler

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 09:13:06