1. Why Jackson?和fastJson的差异以及优劣
- fastJson更新迭代较快,稳定性较差,究其根本原因是底层bug较多,很可能你现在用的最新的版本,一个月之后就被标记为不安全版本了;
- fastJson以解析json和组装json较快著称,但是,其实Jackson的性能瓶颈主要在初始化ObjectMapper上,详细初始化代码下面贴出,而在解析上,Jackson的性能是显著高于fastJson的;
- fastJson解析json主要是用的String类substring这个方法,因为jdk1.7之前substring的实现并没有new一个新对象,申请内存次数很少。但是,在jdk1.7以上版本对string的substring方法做了改写,改成了重新new一个string的方式,于是这个“快”的优势也不存在了(因为不new的话有可能稍不注意就会出现内存泄漏);
- 当然,fastJson也有其优势,针对于易用性来说,fastjson还是很适合的,碾压Jackson,基本可以实现零配置简单使用,具体使用什么还是根据业务场景以及个人爱好来。
public ObjectMapper(JsonFactory jf, DefaultSerializerProvider sp, DefaultDeserializationContext dc) {
this._rootDeserializers = new ConcurrentHashMap(64, 0.6F, 2);
if (jf == null) {
this._jsonFactory = new MappingJsonFactory(this);
} else {
this._jsonFactory = jf;
if (jf.getCodec() == null) {
this._jsonFactory.setCodec(this);
}
}
this._subtypeResolver = new StdSubtypeResolver();
RootNameLookup rootNames = new RootNameLookup();
this._typeFactory = TypeFactory.defaultInstance();
SimpleMixInResolver mixins = new SimpleMixInResolver((MixInResolver)null);
this._mixIns = mixins;
BaseSettings base = DEFAULT_BASE.withClassIntrospector(this.defaultClassIntrospector());
this._configOverrides = new ConfigOverrides();
this._coercionConfigs = new CoercionConfigs();
this._serializationConfig = new SerializationConfig(base, this._subtypeResolver, mixins, rootNames, this._configOverrides);
this._deserializationConfig = new DeserializationConfig(base, this._subtypeResolver, mixins, rootNames, this._configOverrides, this._coercionConfigs);
boolean needOrder = this._jsonFactory.requiresPropertyOrdering();
if (needOrder ^ this._serializationConfig.isEnabled(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY)) {
this.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, needOrder);
}
this._serializerProvider = (DefaultSerializerProvider)(sp == null ? new Impl() : sp);
this._deserializationContext = (DefaultDeserializationContext)(dc == null ? new com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.Impl(BeanDeserializerFactory.instance) : dc);
this._serializerFactory = BeanSerializerFactory.instance;
}
2. Jackson maven依赖
<jackson.version>2.12.0</jackson.version>
<!--jackson start -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson.version}</version>
</dependency>
<!--jackson end -->
3. ObjectMapper初始化
public static final ObjectMapper mapper = new ObjectMapper();
static {
// 转换为格式化的json
mapper.enable(SerializationFeature.INDENT_OUTPUT);
// 如果json中有新增的字段并且是实体类类中不存在的,不报错
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}
其中,mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}这个一定要加上,不然bean中字段和映射的数据流中字段有出入的时候就会报错。
3. 一些常用的方法封装
- javaBean、列表数组转换为json字符串
public static String objectToJson(Object data) {
try {
String result = MAPPER.writeValueAsString(data);
return result;
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
- json 转JavaBean对象
public static <T> T jsonToBean(String jsonData, Class<T> beanType) {
try {
T result = MAPPER.readValue(jsonData, beanType);
return result;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
- json转list
public static <T> List<T> jsonToList(String jsonData, Class<T> beanType) {
JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, beanType);
try {
List<T> resultList = MAPPER.readValue(jsonData, javaType);
return resultList;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
- json转map
public static <K, V> Map<K, V> jsonToMap(String jsonData, Class<K> keyType, Class<V> valueType) {
JavaType javaType = MAPPER.getTypeFactory().constructMapType(Map.class, keyType, valueType);
try {
Map<K, V> resultMap = MAPPER.readValue(jsonData, javaType);
return resultMap;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
- 按照路径取json中的数据
/**
* @param json 原json数据
* @param paths 需要取的路径地址 按照层级
* @return
*/
public static JsonNode getJsonNodeByPath(String json, String... paths) {
JsonNode rootNode = null;
try {
rootNode = MAPPER.readTree(json);
if (paths != null && paths.length > 0) {
//一直遍历下去
for (int i = 0; i < paths.length; i++) {
String path = paths[i];
rootNode = rootNode.path(path);
//如果不存在
if (rootNode.isMissingNode()) {
return null;
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
return rootNode;
}
4. 将json对象按照层级封装为map
工作中经常有场景,需要将json对象按照层级,一层层打平为键值对的形式,比如user.name,user.password这种形式,参考https://tools.ietf.org/html/rfc6901
/**
* This class flatten a json object, the key pattern is defined at the following url:
* https://tools.ietf.org/html/rfc6901
*
* @author bob
* @since 2020-12-14
*/
public final class Rfc6901Flattener
implements Function<JsonNode, Map<String, JsonNode>>, Serializable {
private static final String STANDARD_SEPARATOR = ".";
private static final int DEFAULT_EXPECT_SIZE = 15;
private static final long serialVersionUID = 501491114373294711L;
private final int expectSize;
private final String prefix;
private final String separator;
public Rfc6901Flattener(int expectSize, @NonNull String prefix, @NonNull String separator) {
if (expectSize <= 0 || expectSize > 1000) {
throw new IllegalArgumentException("illegal expect size: " + expectSize);
}
this.expectSize = expectSize;
this.prefix = prefix;
this.separator = separator;
}
public Rfc6901Flattener() {
this(DEFAULT_EXPECT_SIZE, "props.", STANDARD_SEPARATOR);
}
public static String getStandardSeparator() {
return STANDARD_SEPARATOR;
}
private String generateKey(Deque<String> path, StringBuilder keyBuf) {
if (path.size() == 1) {
return prefix.concat(path.peek());
}
keyBuf.setLength(0);
Joiner.on(separator).appendTo(keyBuf.append(prefix), path.descendingIterator());
return keyBuf.toString();
}
@Override
public Map<String, JsonNode> apply(@NonNull JsonNode jsonNode) {
Map<String, JsonNode> result = new HashMap<>(expectSize);
iterateOverNode(result, new ArrayDeque<>(5), new StringBuilder(16), jsonNode);
return result;
}
private void iterateOverObject(
Map<String, JsonNode> map, Deque<String> stack, StringBuilder keyBuf, JsonNode target) {
Iterator<Map.Entry<String, JsonNode>> iterator = target.fields();
while (iterator.hasNext()) {
Map.Entry<String, JsonNode> entry = iterator.next();
stack.push(entry.getKey());
iterateOverNode(map, stack, keyBuf, entry.getValue());
stack.pop();
}
}
private void iterateOverArray(
Map<String, JsonNode> map, Deque<String> stack, StringBuilder keyBuf, JsonNode target) {
int size = target.size();
for (int i = 0; i < size; ++i) {
stack.push(Integer.toString(i));
iterateOverNode(map, stack, keyBuf, target.get(i));
stack.pop();
}
}
private void iterateOverNode(
Map<String, JsonNode> map, Deque<String> stack, StringBuilder keyBuf, JsonNode target) {
if (target.isObject()) {
iterateOverObject(map, stack, keyBuf, target);
} else if (target.isArray()) {
iterateOverArray(map, stack, keyBuf, target);
} else if (target.isValueNode() && !target.isNull() && !stack.isEmpty()) {
String key = generateKey(stack, keyBuf);
map.put(key, target);
}
}
}