snack - Json 序列化应用与扩展定制
1、序列化参考
基础操作
User user = new User();
ONode.ofBean(user).toBean(User.class); //可以作为 bean 转换使用
ONode.ofBean(user).toJson();
ONode.ofJson("{}").toBean(User.class);
ONode.ofJson("[{},{}]").toBean((new ArrayList<User>(){}).getClass());
快捷方式
String json = ONode.serialize(user);
User user = ONode.deserialize(json, User.class);
2、定制的载体:Options
Options 提供有序列化特性、时间格式、时区、地区、类加载器、对象编码器、对象解码器、对象工厂等可选定制。其中:
- 对象编码器(ObjectEncoder,ObjectPatternEncoder),负责把 Java 对象转为 ONode 实例
- 对象解码器(ObjectDecoder,ObjectPatternDecoder),负责把 ONode 实例转为 Java 对象
- 对象创建器(ObjectCreator,ObjectPatternCreator),负责创建 Java 类实例。顺道可以处理类型安全问题
更多参考:《Options 主要接口参考》
3、编码器、解码器定制参考
对象编码器和对象解码器,一般成对出现。比如,实现 Class 对象的序列化(其实已经内置了)。
public class CodecDemo {
    public static void main(String[] args) {
        Options options = Options.of();
        //编码:使用类的名字作为数据
        options.addEncoder(Class.class, ((ctx, value, target) ->  {
            return target.setValue(value.getName());
        }));
        //解码:把字符串作为类名加载(成为类)
        options.addDecoder(Class.class, (ctx, node) -> {
            return ctx.getOptions().loadClass(node.getString());
        });
        //测试:序列化
        Map<String,Class<?>> data = new HashMap<>();
        data.put("list", ArrayList.class);
        String json = ONode.serialize(data, options);
        System.out.println(json);  // {"list":"java.util.ArrayList"}
        assert "{\"list\":\"java.util.ArrayList\"}".equals(json);
        //测试:反序列化
        data = ONode.deserialize(json, new TypeRef<Map<String,Class<?>>>() {}, options);
        System.out.println(data.get("list")); // class java.util.ArrayList
        assert ArrayList.class.equals(data.get("list"));
    }
}
4、时间定制参考
时间可以使用 addEncoder 和 addDecoder 定制。还可以使用特性加选项:
| 选项配置 | 描述 | 注备 | 
|---|---|---|
| Options:dateFormat | 时间格式配置 | 需要启用特性 Feature.Write_UseDateFormat才生效 | 
| Options:timeZone | 时区配置 | 同上 | 
示例:
public class DateDemo {
    public static void main(String[] args) {
        Map<String, Object> data = new HashMap<>();
        data.put("time", new Date());
        Options opts = Options.of(Feature.Write_UseDateFormat).dateFormat("yyyy-MM-dd");
        String json = ONode.ofBean(data, opts).toJson();
        
        //检验效果 //out: {"time":"2025-10-16"}
        System.out.println(json);
    }
}
5、特性使用参考
更多参考:《Feature 主要接口参考》。使用特性(Feature)控制细节:
public class FeatureDemo {
    public static void main(String[] args) {
        Options options = Options.of().addFeature(Feature.Write_BigNumbersAsString);
        Map<String, Object> data = new HashMap<>();
        data.put("a", 1);
        data.put("b", 2L);
        data.put("c", 3F);
        data.put("d", 4D);
        //序列化
        String json = ONode.serialize(data, options);
        System.out.println(json); //{"a":1,"b":"2","c":3.0,"d":"4.0"} //b 和 d 变成字符串了
        json = ONode.serialize(data, Feature.Write_NumberType); //也可直接使用特性
        System.out.println(json); //{"a":1,"b":2L,"c":3.0F,"d":4.0D} //带了数字类型(有些框架不支持)
        //反序列化:带数字类型符号的,可以还原数字类型
        Map map = ONode.deserialize(json, Map.class);
        assert map.get("b") instanceof Long;
    }
}
 Solon
 Solon