zoukankan      html  css  js  c++  java
  • Jackson ObjectMapper JSON序列化工具使用笔记,由浅入深

    Apache Dubbo 官方放弃了FastJson

    Jackson目前是世界上最好的Java JSON库。

    基本用法,ObjectNode, ArrayNode等 ValueNode

    生成一个 jsonobject结构
    ObjectNode protocol = new ObjectNode(JsonNodeFactory.instance);
    //或者 ObjectNode protocol = JsonNodeFactory.instance.objectNode();
    
    protocol.put("batchSize", 20480);
    protocol.putArray("columns").add("id").add("name");
    
    把数组、List作为一个带名称的 jsonarray 结构
    List<xxx> costs = ...
    ObjectNode x = JsonNodeFactory.instance.objectNode().putPOJO("costs", costs);
    
    字符串反序列化为List、数组
    //slankka提示1: 数据是List的
    objectMapper.readValue(str, new TypeReference<List<Item>>() {});
    
    序列化任意对象、数组
    objectMapper.writeValueAsString(object);
    

    JsonNode 操作

    修改JsonNode

    注意:需要强转ObjectNode

    没必要因为个别字段不一致就专门定义一个POJO,太繁琐。

    本身做Controller就是为了生成JSON,而JSON就是Javascript Object Notation

    例如service 字段转成 codec里面的value值,根据fromId 生成一个新newRef值。

    Map<String, String> codec ...
    Map<Long, String> laborRefNames ...
    JsonNode jsonNodes = new ObjectMapper().valueToTree(iterableVals);
    jsonNodes.forEach(x -> ((ObjectNode) x)
             .put("service", codec.get(x.get("service").asText()))
             .put("newRef", laborRefNames.get(x.get("fromId").asLong())));
    
    从JsonNode中获取JsonArray,再反序列化成对象
    //slankka提示2:从JsonNode中获取一个JsonArray (JsonNode类型)
    //slankka提示3:MetricsPack是一个ArrayList子类,与前文的TypeReference不同,这里是一个技巧。
    metrics = objectMapper.treeToValue(jsonNode.get("metrics"), MetricsPack.class);
    
    字符串反序列化为JsonNode,并不直接转换成对象

    做接口设计的时候,比较好用,不关心具体的数据类差异,只关心数值字段

    JsonNode jsonNode = objectMapper.readTree(str_input);
    
    interface DataExtractor {
      Object handle(JsonNode jsonNode);
    }
    
    DataExtractor instance;
    instance.handle(jsonNode);
    
    从JsonNode中获取数值
    //十分灵活,需要字符串就是字符串,需要转成int就是int。(前提是数据类型比较符合,Javascript本身就是灵活的)
    int instanceId = jsonNode.get("instanceId").asInt();
    String text = jsonNode.get("instanceId").asText();
    
    //Slankka提示4:一定要调用 asInt, asLong, asText,否则获取得到的是JsonNode, 他有toString,容易被误用。
    Timestamp timestamp = Timestamp.from(Instant.ofEpochMilli(jsonNode.get("createTime").asLong()));
    Optional.ofNullable(jsonNode.get("room")).map(JsonNode::asText).orElse(null)
    
    使用JsonPath语法获取数值

    使用JsonPath更为简洁,可以替代上述jsonNode.get()语法

     slankka.setTopicName(jsonNode.at("/additional/topicName").asText());
     slankka.setReplica((short) jsonNode.at("/additional/replica").asInt());
     slankka.setUserId(jsonNode.at("/additional/userId").asInt());
     slankka.setClusterId((short) jsonNode.at("/additional/clusterId").asInt());
     slankka.setPartitionNum(jsonNode.at("/additional/partitionNum").asInt());
    

    高级用法

    使用泛型 + ArrayList子类 + 某种设计模式(模板模式?)
    //抽象盒子
    public abstract class PrototypeBox<T extends AbstractApp> extends ArrayList<T> {
       String whatBoxCanDo() {
            for (AbstractApp app : this) {
                app.whatAppCanDo();
            }
       };
    }
    
    //抽象物体单元
    public abstract class AbstractApp {
        protect String platform;
        protect Integer platId;
    
        public abstract String whichIsDifferent();
    
        public ObjectNode mayBeYouWantToSerialize() {
             ObjectNode _dataNode = new ObjectNode(JsonNodeFactory.instance);
             _dataNode.put("Question", "我们哪里不一样?" +  whichIsDifferent() );
             return _dataNode;
        }
    
        void whatAppCanDo() {
            mayBeYouWantToSerialize();
        };
    }
    
    //派生物体A
    public class IosApp extends AbstractApp {
        public static class Pack extends PrototypeBox<IosApp> {
        }
    }
    
    //派生物体B
    public class AndroidApp extends AbstractApp {
        public static class Pack extends PrototypeBox<AndroidApp> {
        }
    }
    
    //场景1
    IosApp.Pack anApps = null;
    try {
        anApps = objectMapper.treeToValue(at, IosApp.Pack.class);
    } catch (JsonProcessingException e) {
        e.printStackTrace();
    }
    //场景2
    AndroidApp.Pack anApps = null;
    try {
        anApps = objectMapper.treeToValue(at, AndroidApp.Pack.class);
    } catch (JsonProcessingException e) {
        e.printStackTrace();
    }
    
    //Slankka提示5:处理方式,由上到下,由外及内。
    anApps.whatBoxCanDo();
    

    这个例子最复杂,总而言之,其实就是两种对象数组(List),他们不一样,但是大部分属性,方法是共同的。

    好处就是可以一并处理,各自再处理不同的细节。

    这样设计,是服从高内聚,低耦合的原则的。

    附录:

    StringBoot中jackson的配置

    可大写也可小写,可搜索spring.jackson.serialization查看SpringBoot Jar包源码支持的其他类型

    例如

        {
          "name": "spring.jackson.serialization",
          "type": "java.util.Map<com.fasterxml.jackson.databind.SerializationFeature,java.lang.Boolean>",
          "description": "Jackson on/off features that affect the way Java objects are serialized.",
          "sourceType": "org.springframework.boot.autoconfigure.jackson.JacksonProperties"
        }
    

    例:

    # 将日期类型序列化为TIMESTAMP时间戳字符串
    spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS=true
    # 将BIGDECIMAL序列化为 bigDecimal.toPlainString(), 防止生成科学计数法
    spring.jackson.generator.WRITE_BIGDECIMAL_AS_PLAIN=true
    

    ※Spring把这个选项设置为false

    @Configuration(proxyBeanMethods = false)
    @ConditionalOnClass(ObjectMapper.class)
    public class JacksonAutoConfiguration {
    	private static final Map<?, Boolean> FEATURE_DEFAULTS;
    
    	static {
    		Map<Object, Boolean> featureDefaults = new HashMap<>();
    		featureDefaults.put(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
    		featureDefaults.put(SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS, false);
    		FEATURE_DEFAULTS = Collections.unmodifiableMap(featureDefaults);
    	}
    }
    
  • 相关阅读:
    委托~~~~~~~~~~~~~
    Lambda表达式的前世今生~~~~~~
    数据库/MySQL的安装
    flask 源码专题(十一):LocalStack和Local对象实现栈的管理
    python面试题:redis数据库
    python面试题七: mysql数据库
    wtforms: remove ' fill out this field'
    python面试题六: 剑指offer
    python面试题五:Python 编程
    python面试题四:Python web框架
  • 原文地址:https://www.cnblogs.com/slankka/p/15478064.html
Copyright © 2011-2022 走看看