上篇文章Json工具Demo(一) 说了一些Json和Jackson框架的基本知识,以及Demo中需要用到的基本类。这篇文章主要写下json和java对象之间相互转换的工具类JacksonUtil.java和测试类Main.java。
如果是List<User>
或者Map<String, User>
使用toJsonWithRoot方法转换成json串,当用jsonToBeanByTypeReferenceWithRoot方法转换成Java Bean时,会导致该Bean为null。因此,需要使用一个新的类,如UserList或者UserMap类来实现,就可以避免这个问题。
使用下面的代码需要的依赖是:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.8.5</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.5</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.8.5</version>
</dependency>
JacksonUtil
JacksonUtil.java
package org.fan.learn.utils;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.Locale;
import java.util.Map;
/**
* Created by fan on 15-11-18.
*/
public class JacksonUtil {
private static final Logger LOGGER = LoggerFactory.getLogger(JacksonUtil.class);
private static ObjectMapper mapper;
public static synchronized ObjectMapper getMapperInstance(boolean createNew) {
if (createNew) {
return new ObjectMapper();
} else if (mapper == null) {
mapper = new ObjectMapper();
//对象属性按字母顺序排列
mapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true);
//在反序列化时,如果类中没有对应的属性,不抛出JsonMappingException异常
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
//序列化时,如果对象的某属性为null,生成Json字符串时不包含这个null属性
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
mapper.setLocale(Locale.CHINA);
}
return mapper;
}
/**
* 将java对象转换为字符串
* @param param java 对象
* @return json字符串
*/
public static String toJson(Object param){
try {
ObjectMapper objectMapper = JacksonUtil.getMapperInstance(false);
objectMapper.configure(SerializationFeature.WRAP_ROOT_VALUE, false);
String dataJson = objectMapper.writeValueAsString(param);
return dataJson;
}catch (Exception e){
LOGGER.warn("toJson",e);
}
return null;
}
/**
* 将java对象为字符串 类名作为json的顶级属性
* @param param java 对象
* @returnjson字符串
*/
public static String toJsonWithRoot(Object param){
try {
ObjectMapper objectMapper = JacksonUtil.getMapperInstance(false);
objectMapper.configure(SerializationFeature.WRAP_ROOT_VALUE, true);
String dataJson = objectMapper.writeValueAsString(param);
return dataJson;
}catch (Exception e){
LOGGER.warn("toJson",e);
}
return null;
}
/**
* 将json字符串转换为java对象
* @param json json字符串
* @param cls java对象类型
* @param <T>
* @return
*/
public static <T> T jsonToBean(String json, Class<T> cls){
try {
ObjectMapper objectMapper = JacksonUtil.getMapperInstance(false);
objectMapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE,false);
return objectMapper.readValue(json, cls);
} catch (Exception e) {
LOGGER.warn("jsonToBean",e);
return null;
}
}
/**
* 将json字符串转换为java对象 ,解析字符串时,将类的名字或者别名作为顶级属性来解析
* @param json json字符串
* @param cls java对象类型
* @param <T>
* @return
*/
public static <T> T jsonToBeanWithRoot(String json, Class<T> cls){
try {
ObjectMapper objectMapper = JacksonUtil.getMapperInstance(false);
objectMapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
return objectMapper.readValue(json, cls);
} catch (Exception e) {
LOGGER.warn("jsonToBean",e);
return null;
}
}
/**
* 将json字符串转换为java对象
* @param json json字符串
* @param typeReference 复杂的java对象类型
* @param <T>
* @return
*/
public static <T> T jsonToBeanByTypeReference(String json, TypeReference typeReference){
try {
ObjectMapper objectMapper = JacksonUtil.getMapperInstance(false);
objectMapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE,false);
return objectMapper.readValue(json, typeReference);
} catch (Exception e) {
LOGGER.warn("jsonToBean",e);
return null;
}
}
/**
* 将json字符串转换为java对象,解析字符串时,将类的名字或者别名作为顶级属性来解析
* @param json json字符串
* @param typeReference 复杂的java对象类型
* @param <T>
* @return
*/
public static <T> T jsonToBeanByTypeReferenceWithRoot(String json, TypeReference typeReference){
try {
ObjectMapper objectMapper = JacksonUtil.getMapperInstance(false);
objectMapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE,true);
return objectMapper.readValue(json, typeReference);
} catch (Exception e) {
LOGGER.warn("jsonToBean",e);
return null;
}
}
/**
* 从json字符串中读取出指定的节点
*
* @param json
* @param key
* @return
* @throws JsonProcessingException
* @throws IOException
*/
public static JsonNode getValueFromJson(String json, String key) {
ObjectMapper objectMapper = JacksonUtil.getMapperInstance(false);
objectMapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE,false);
JsonNode node = null;
try {
node = objectMapper.readTree(json);
return node.get(key);
} catch (IOException e) {
LOGGER.warn("getValueFromJson",e);
return null;
}
}
}
Main测试
package org.fan.learn.json;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.fan.learn.utils.JacksonUtil;
import java.util.List;
import java.util.Map;
/**
* Created by fan on 15-11-18.
*/
public class Main {
public static void main(String[] args) {
List<User> userList = Lists.newArrayList();
String[] phone = {"15888888888", "15222222222"};
Birthday birthday = new Birthday(2000,8,8);
User user = new User("宝宝", -26, phone, birthday, true);
User user1 = new User("fan", 25, phone, birthday, false);
/* User user = new User();
user.setName("fan");
user.setAge(26);
User user1 = new User();
user1.setName("li");
user1.setAge(25);*/
userList.add(user);
userList.add(user1);
Map<String, User> userMap = Maps.newHashMap();
userMap.put("user1", user);
userMap.put("user2", user1);
//会调用get方法
String userString = JacksonUtil.toJson(user);
//会调用无参构造函数,set方法
User userJson = JacksonUtil.jsonToBean(userString, User.class);
Map<String,String> userJsonMap = JacksonUtil.jsonToBean(userString, Map.class);
System.out.println(userJsonMap);
JsonNode name = JacksonUtil.getValueFromJson(userString, "NAME");
JsonNode age = JacksonUtil.getValueFromJson(userString, "AGE");
JsonNode phoneNode = JacksonUtil.getValueFromJson(userString, "PHONE");
JsonNode birthdayNode = JacksonUtil.getValueFromJson(userString, "BIRTHDAY");
JsonNode maleNode = JacksonUtil.getValueFromJson(userString, "MALE");
String nameStr = name.toString();
int ageInt = age.intValue();
//List<String> phoneArr = phoneNode.findValuesAsText("PHONE");
String[] phoneArr = new String[phoneNode.size()];
for (int i = 0; i < phoneNode.size(); i++) {
phoneArr[i] = phoneNode.get(i).toString();
}
Birthday birthdayObj = new Birthday();
//会分别调用Birthday的3个setter方法
birthdayObj.setYear(birthdayNode.get("year").intValue());
birthdayObj.setMonth(birthdayNode.get("month").intValue());
birthdayObj.setDay(birthdayNode.get("day").intValue());
boolean male = maleNode.booleanValue();
String userString2 = JacksonUtil.toJsonWithRoot(user);
//使用这种内部数据将会是null
User userJson2_1 = JacksonUtil.jsonToBean(userString2, User.class);
User userJson2_2 = JacksonUtil.jsonToBeanWithRoot(userString2, User.class);
String userListString = JacksonUtil.toJson(userList);
List<User> userListJson = JacksonUtil.jsonToBeanByTypeReference(
userListString,
new TypeReference<List<User>>(){});
String userListStringRoot = JacksonUtil.toJsonWithRoot(userList);
//这种使用方法,得到的userListJsonRoot是null
List<User> userListJsonRoot = JacksonUtil.jsonToBeanByTypeReferenceWithRoot(
userListStringRoot,
new TypeReference<List<User>>(){});
//使用UserList类
UserList userListClass = new UserList();
userListClass.setUserList(userList);
String userListClassString = JacksonUtil.toJson(userListClass);
UserList userListClassJason = JacksonUtil.jsonToBean(userListClassString, UserList.class);
String userListClassStringRoot = JacksonUtil.toJsonWithRoot(userListClass);
UserList userListClassJasonRoot = JacksonUtil.jsonToBeanWithRoot(userListClassStringRoot, UserList.class);
String userMapString = JacksonUtil.toJson(userMap);
Map<String, User> userMapJson = JacksonUtil.jsonToBeanByTypeReference(
userMapString,
new TypeReference<Map<String, User>>(){});
String userMapStringRoot = JacksonUtil.toJsonWithRoot(userMap);
//这种使用方法,得到的userMapJsonRoot是null
Map<String, User> userMapJsonRoot = JacksonUtil.jsonToBeanByTypeReferenceWithRoot(
userMapStringRoot,
new TypeReference<Map<String, User>>(){});
//使用UserMap类
UserMap userMapClass = new UserMap();
userMapClass.setUserMap(userMap);
String userMapClassString = JacksonUtil.toJson(userMapClass);
UserMap userMapClassJson = JacksonUtil.jsonToBean(userMapClassString, UserMap.class);
String userMapClassStringRoot = JacksonUtil.toJsonWithRoot(userMapClass);
UserMap userMapClassJsonRoot = JacksonUtil.jsonToBeanWithRoot(userMapClassStringRoot, UserMap.class);
}
}
代码分析及运行结果
1 关于Google guava
google guava所包含的内容远不止在Demo中使用的样子。由于本篇博文的重点在json,这里对guava不详细说明,给出链接资料:http://ifeve.com/google-guava/
在java 7之前,在构造新的泛型集合时要反复重新声明泛型。如下所示:
List<User> userList = new ArrayList<User>();
这样写太繁琐,因此guava推出了能够推断泛型的静态工厂方法:
List<User> userList = Lists.newArrayList();
2 json与java对象之间的转换
java对象转换成json,使用JacksonUtil.toJson
,这个方法调用过程中会调用java bean的get方法。如果java bean中不存在get方法也不影响转换的过程。
json转换成java对象,使用JacksonUtil.jsonToBean
, 这个方法调用过程中首先会调用java bean的默认构造函数。如果java bean没有其他构造函数的话,编译器会自动添加默认构造函数。总之,默认构造函数必须要有,否则会报错。由json转java bean时也会调用setter方法。如果java bean中不存在set方法也不影响转换的过程。
//会调用get方法
String userString = JacksonUtil.toJson(user);
//会调用无参构造函数,set方法
User userJson = JacksonUtil.jsonToBean(userString, User.class);
Map<String,String> userJsonMap = JacksonUtil.jsonToBean(userString, Map.class);
为了检验默认构造方法,setter,getter方法的调用,在POJO中有打印信息。
上面代码的执行结果,如下所示。
userString的内容:
{"AGE":-26,"BIRTHDAY":{"day":8,"month":8,"year":2000},"MALE":true,"NAME":"宝宝","PHONE":["15888888888","15222222222"]}
从上面可以看到,键值对的排序都是按照字母顺序排序的,而且还是大写的。原因如下:
mapper = new ObjectMapper();
//对象属性按字母顺序排列
mapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true);
在创建POJO User.java时使用了注解。
@JsonProperty("NAME")
private String name;
@JsonProperty("AGE")
private int age;
@JsonProperty("PHONE")
private String[] phone;
@JsonProperty("BIRTHDAY")
private Birthday birthday;
@JsonProperty("MALE")
private boolean male;
userJson对象的内容
userJsonMap的内容
3 从json字符串中直接得到某一属性的值
JsonNode name = JacksonUtil.getValueFromJson(userString, "NAME");
JsonNode age = JacksonUtil.getValueFromJson(userString, "AGE");
JsonNode phoneNode = JacksonUtil.getValueFromJson(userString, "PHONE");
JsonNode birthdayNode = JacksonUtil.getValueFromJson(userString, "BIRTHDAY");
JsonNode maleNode = JacksonUtil.getValueFromJson(userString, "MALE");
String nameStr = name.toString();
int ageInt = age.intValue();
//List<String> phoneArr = phoneNode.findValuesAsText("PHONE");
String[] phoneArr = new String[phoneNode.size()];
for (int i = 0; i < phoneNode.size(); i++) {
phoneArr[i] = phoneNode.get(i).toString();
}
Birthday birthdayObj = new Birthday();
//会分别调用Birthday的3个setter方法
birthdayObj.setYear(birthdayNode.get("year").intValue());
birthdayObj.setMonth(birthdayNode.get("month").intValue());
birthdayObj.setDay(birthdayNode.get("day").intValue());
boolean male = maleNode.booleanValue();
4 在json字符串中显示根的名字
String userString2 = JacksonUtil.toJsonWithRoot(user);
//使用这种内部数据将会是null
User userJson2_1 = JacksonUtil.jsonToBean(userString2, User.class);
User userJson2_2 = JacksonUtil.jsonToBeanWithRoot(userString2, User.class);
userString2的内容如下所示:
{"FAN":{"AGE":-26,"BIRTHDAY":{"day":8,"month":8,"year":2000},"MALE":true,"NAME":"宝宝","PHONE":["15888888888","15222222222"]}}
之所以会显示头时因为,有注解:
@JsonRootName(value = "FAN")
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
public class User {
}
userJson2_1和userJson2_2的内容如下:
userJson2_1是null的,因为json串是有root的,重新解析时也要使用有root的。
5 关于集合List
String userListString = JacksonUtil.toJson(userList);
List<User> userListJson = JacksonUtil.jsonToBeanByTypeReference(
userListString,
new TypeReference<List<User>>(){});
String userListStringRoot = JacksonUtil.toJsonWithRoot(userList);
//这种使用方法,得到的userListJsonRoot是null
List<User> userListJsonRoot = JacksonUtil.jsonToBeanByTypeReferenceWithRoot(
userListStringRoot,
new TypeReference<List<User>>(){});
userListString的内容如下:
[{"AGE":-26,"BIRTHDAY":{"day":8,"month":8,"year":2000},"MALE":true,"NAME":"宝宝","PHONE":["15888888888","15222222222"]},{"AGE":25,"BIRTHDAY":{"day":8,"month":8,"year":2000},"MALE":false,"NAME":"fan","PHONE":["15888888888","15222222222"]}]
userListJson的内容:
但是有了root之后就有问题了:
因此对于集合最好不要使用jsonToBeanByTypeReference这种方式来将json转换成java bean。当遇到集合时,最好能新建一个集合的类。
//使用UserList类
UserList userListClass = new UserList();
userListClass.setUserList(userList);
String userListClassString = JacksonUtil.toJson(userListClass);
UserList userListClassJason = JacksonUtil.jsonToBean(userListClassString, UserList.class);
String userListClassStringRoot = JacksonUtil.toJsonWithRoot(userListClass);
UserList userListClassJasonRoot = JacksonUtil.jsonToBeanWithRoot(userListClassStringRoot, UserList.class);
userListClassString的内容如下:
{"USERLIST":[{"AGE":-26,"BIRTHDAY":{"day":8,"month":8,"year":2000},"MALE":true,"NAME":"宝宝","PHONE":["15888888888","15222222222"]},{"AGE":25,"BIRTHDAY":{"day":8,"month":8,"year":2000},"MALE":false,"NAME":"fan","PHONE":["15888888888","15222222222"]}]}
userListClassStringRoot的内容如下:
{"AAAAA":{"USERLIST":[{"AGE":-26,"BIRTHDAY":{"day":8,"month":8,"year":2000},"MALE":true,"NAME":"宝宝","PHONE":["15888888888","15222222222"]},{"AGE":25,"BIRTHDAY":{"day":8,"month":8,"year":2000},"MALE":false,"NAME":"fan","PHONE":["15888888888","15222222222"]}]}}
6 (1)map的情况跟list类似
String userMapString = JacksonUtil.toJson(userMap);
Map<String, User> userMapJson = JacksonUtil.jsonToBeanByTypeReference(
userMapString,
new TypeReference<Map<String, User>>(){});
String userMapStringRoot = JacksonUtil.toJsonWithRoot(userMap);
//这种使用方法,得到的userMapJsonRoot是null
Map<String, User> userMapJsonRoot = JacksonUtil.jsonToBeanByTypeReferenceWithRoot(
userMapStringRoot,
new TypeReference<Map<String, User>>(){});
userMapString的内容:
{"user2":{"AGE":25,"BIRTHDAY":{"day":8,"month":8,"year":2000},"MALE":false,"NAME":"fan","PHONE":["15888888888","15222222222"]},"user1":{"AGE":-26,"BIRTHDAY":{"day":8,"month":8,"year":2000},"MALE":true,"NAME":"宝宝","PHONE":["15888888888","15222222222"]}}
userMapStringRoot的内容:
{"HashMap":{"user2":{"AGE":25,"BIRTHDAY":{"day":8,"month":8,"year":2000},"MALE":false,"NAME":"fan","PHONE":["15888888888","15222222222"]},"user1":{"AGE":-26,"BIRTHDAY":{"day":8,"month":8,"year":2000},"MALE":true,"NAME":"宝宝","PHONE":["15888888888","15222222222"]}}}
(2)
//使用UserMap类
UserMap userMapClass = new UserMap();
userMapClass.setUserMap(userMap);
String userMapClassString = JacksonUtil.toJson(userMapClass);
UserMap userMapClassJson = JacksonUtil.jsonToBean(userMapClassString, UserMap.class);
String userMapClassStringRoot = JacksonUtil.toJsonWithRoot(userMapClass);
UserMap userMapClassJsonRoot = JacksonUtil.jsonToBeanWithRoot(userMapClassStringRoot, UserMap.class);
userMapClassString的内容:
{"USERMAP":{"user2":{"AGE":25,"BIRTHDAY":{"day":8,"month":8,"year":2000},"MALE":false,"NAME":"fan","PHONE":["15888888888","15222222222"]},"user1":{"AGE":-26,"BIRTHDAY":{"day":8,"month":8,"year":2000},"MALE":true,"NAME":"宝宝","PHONE":["15888888888","15222222222"]}}}
userMapClassStringRoot的内容:
{"BB":{"USERMAP":{"user2":{"AGE":25,"BIRTHDAY":{"day":8,"month":8,"year":2000},"MALE":false,"NAME":"fan","PHONE":["15888888888","15222222222"]},"user1":{"AGE":-26,"BIRTHDAY":{"day":8,"month":8,"year":2000},"MALE":true,"NAME":"宝宝","PHONE":["15888888888","15222222222"]}}}}