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

能否使用Jackson基于Java类生成类型树而非值树?

解决方案

Jackson可以实现该需求,这里提供两种可行方案:

方案1:直接基于类的类型元数据构建类型树(推荐)

你不需要实例化类对象,直接通过Jackson提供的Bean内省能力读取类的字段类型信息,按需生成对应类型的JsonNode即可,完全规避null值的影响:

package org.example.jackson.typetree;

import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.junit.jupiter.api.Test;

import java.util.List;

public class TypeTreeTest {
    static class SomeClass{
        public Integer integer;
        public String string;
    }

    @Test
    void buildTypeTree() {
        ObjectMapper objectMapper = new ObjectMapper();
        // 内省目标类的元信息
        JavaType javaType = objectMapper.getTypeFactory().constructType(SomeClass.class);
        List<BeanPropertyDefinition> properties = objectMapper.getSerializationConfig()
                .introspect(javaType)
                .findProperties();

        // 手动构建类型对应的JsonNode树
        ObjectNode rootNode = objectMapper.createObjectNode();
        for (BeanPropertyDefinition prop : properties) {
            Class<?> rawType = prop.getRawPrimaryType();
            if (rawType == Integer.class || rawType == int.class) {
                rootNode.put(prop.getName(), 0); // 生成IntNode
            } else if (rawType == String.class) {
                rootNode.put(prop.getName(), ""); // 生成TextNode
            }
            // 其他类型可按需扩展
        }

        // 验证节点类型
        rootNode.fields().forEachRemaining(child -> {
            if(child.getValue().isIntegralNumber() || child.getValue().isTextual()){
                System.out.println("Nice!");
            }else if(child.getValue().isNull()){
                System.out.println("Booooh...!");
            }
        });
    }
}

该方案完全基于类型元数据生成节点,不受字段实际值影响,也不需要反射实例化类,性能和稳定性更高。

方案2:自定义Null值序列化器

如果你一定要走valueToTree的序列化流程,可以为不同Java类型注册对应的Null序列化器,在字段值为null时输出对应类型的默认值:

package org.example.jackson.typetree;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class CustomNullSerializeTest {
    static class SomeClass{
        public Integer integer;
        public String string;
    }

    @Test
    void extractTypeTree() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        ObjectMapper objectMapper = new ObjectMapper();
        SimpleModule module = new SimpleModule();
        // 为Integer类型注册null序列化器,输出0
        module.addSerializer(Integer.class, new JsonSerializer<Integer>() {
            @Override
            public void serialize(Integer value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
                gen.writeNumber(value == null ? 0 : value);
            }
        });
        // 为String类型注册null序列化器,输出空字符串
        module.addSerializer(String.class, new JsonSerializer<String>() {
            @Override
            public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
                gen.writeString(value == null ? "" : value);
            }
        });
        objectMapper.registerModule(module);

        final Constructor<?> constructor = SomeClass.class.getDeclaredConstructor();
        final Object o =  constructor.newInstance((Object[]) null);
        final var jsonNode = objectMapper.valueToTree(o);
        final var fields = jsonNode.fields();
        while(fields.hasNext()){
            final var child = fields.next();
            if(child.getValue().isIntegralNumber() || child.getValue().isTextual()){
                System.out.println("Nice!");
            }else if(child.getValue().isNull()){
                System.out.println("Booooh...!");
            }
        }
    }
}

运行上述两种方案的代码,都会输出两次Nice!,符合预期。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 04:18:02