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);
}
}