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

Jackson反序列化JSON为Java POJO时出现NullPointerException问题

问题根因

空指针和解析错位是多个代码错误共同导致的:

  • 反序列化逻辑和实际JSON结构完全不匹配。待解析的JSON层级为根节点 -> properties -> anon -> 路径key(/brief/versicherungsnehmer/vorname等),不存在直接命名为vorname/nachname的子节点。现有反序列化代码直接在当前节点取这两个key,拿到null后调用booleanValue()直接触发空指针。
  • 类职责设计混乱。Properties作为存储数据的POJO,错误继承了JsonDeserializer还自行实现反序列化逻辑;ProfileDeserializer类上的@JsonDeserialize(using = Properties.class)注解写反位置——该注解应该标注在POJO上指定反序列化器,写在反序列化器类上会导致Jackson反序列化逻辑错乱。
  • 输入流被破坏。调试代码is.read()提前从文件输入流读走1个字节,后续Jackson解析时拿到的是残缺的JSON内容,这也是日志中打印出dokumenttyp、sprache等无关节点的核心原因之一,流内容错位后解析逻辑完全跑偏。
  • ObjectMapper重复创建、配置冗余。类初始化时已经创建了全局ObjectMapper,readConfig方法内又重复创建实例、重复注册模块,容易引发配置冲突。
  • unpackNested方法泛型定义完全错误:anon节点的key是字符串路径、value是布尔值,定义为Map<Boolean, Object>后强转嵌套Map取值的逻辑本身就不可能运行成功。
修复步骤
  1. 修正POJO类Properties:去掉错误的继承关系和多余的反序列化、嵌套解析方法,保留纯数据结构:
    import com.fasterxml.jackson.annotation.JsonProperty;
    public class Properties {
        private boolean vorname;
        private boolean nachname;
    
        public void setVorname(boolean vorname) {
            this.vorname = vorname;
        }
        public void setNachname(boolean nachname) {
            this.nachname = nachname;
        }
        public boolean getVorname() {
            return this.vorname;
        }
        public boolean getNachname() {
            return this.nachname;
        }
    }
    
  2. 修正自定义反序列化器ProfileDeserializer:去掉错误注解,按照实际JSON层级逐层读取节点,用安全的取值方式避免空指针:
    import com.fasterxml.jackson.core.JsonParser;
    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.databind.DeserializationContext;
    import com.fasterxml.jackson.databind.JsonNode;
    import com.fasterxml.jackson.databind.JsonDeserializer;
    import java.io.IOException;
    
    public class ProfileDeserializer extends JsonDeserializer<Properties> {
        @Override
        public Properties deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
            JsonNode rootNode = jsonParser.getCodec().readTree(jsonParser);
            Properties property = new Properties();
            // 按实际JSON路径取值,path方法在节点不存在时返回空节点,不会触发空指针
            JsonNode anonNode = rootNode.path("properties").path("anon");
            property.setVorname(anonNode.path("/brief/versicherungsnehmer/vorname").asBoolean(false));
            property.setNachname(anonNode.path("/brief/versicherungsnehmer/nachname").asBoolean(false));
            return property;
        }
    }
    
  3. 修正JSONMuncher逻辑:复用全局ObjectMapper,删掉提前读取输入流的调试代码,用try-with-resources安全管理流:
    import com.fasterxml.jackson.core.JsonFactory;
    import com.fasterxml.jackson.core.JsonGenerator;
    import com.fasterxml.jackson.databind.DeserializationFeature;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.databind.SerializationFeature;
    import com.fasterxml.jackson.annotation.JsonInclude;
    import com.fasterxml.jackson.annotation.PropertyAccessor;
    import com.fasterxml.jackson.annotation.JsonAutoDetect;
    import com.fasterxml.jackson.databind.module.SimpleModule;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    
    public class JSONMuncher {
        private final ObjectMapper objectMapper;
    
        public JSONMuncher() {
            this.objectMapper = createObjectMapper();
        }
    
        public ObjectMapper getObjectMapper() {
            return objectMapper;
        }
    
        private static ObjectMapper createObjectMapper() {
            SimpleModule module = new SimpleModule()
                    .addSerializer(Properties.class, new ProfileSerializer())
                    .addDeserializer(Properties.class, new ProfileDeserializer());
    
            return new ObjectMapper(new JsonFactory()
                    .disable(JsonGenerator.Feature.AUTO_CLOSE_JSON_CONTENT))
                    .registerModule(module)
                    .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
                    .configure(SerializationFeature.AUTO_CLOSE_SOURCE, true)
                    .setSerializationInclusion(JsonInclude.Include.NON_NULL)
                    .setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
        }
    
        public Properties readConfig(String filepath) {
            try (InputStream is = new FileInputStream(filepath)) {
                Properties anon = objectMapper.readValue(is, Properties.class);
                System.out.println(anon.getVorname());
                System.out.println(anon.getNachname());
                return anon;
            } catch (IOException e) {
                System.out.println("Beep Boop Err!!! 🤖");
                e.printStackTrace();
            }
            return null;
        }
    }
    
  4. 额外校验:确认传入readConfig的文件路径是目标JSON文件的路径,避免读到其他业务配置文件引发解析错位。

内容的提问来源于stack exchange,提问作者MagicBytes

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 00:57:32