在平时工作处理JSON格式的数据比较费劲,自己根据jackson来写了一个简单实用的JSONHelper,实现了懒加载,并且是线程安全的
首先maven导入jackson包:
com.fasterxml.jackson.core
jackson-databind
2.5.3
JSONHelper代码如下:
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import sun.misc.Unsafe;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Objects;
/**
* @author Eric
* @email [email protected]
* @date 2018-08-09
* @more lazy initialization & thread safe
*/
public class JSONHelper {
/**
* objectMapper is jackson json parse core , do all the work
* lazy initialization
*/
private static volatile ObjectMapper objectMapper = null;
/**
* flag for initialization ,
* 0 => default
* -1 => initializing
* 1 => initialized
*/
private transient volatile int flag = 0;
/**
* transform Object to String
* for example : toJson(new Student()) -> transform Student instance to String
*
* @param object
* @return
*/
public static String toJSON(Object object) {
Objects.requireNonNull(object,"param can not be null");
new JSONHelper().initObjectMapper();
try {
return objectMapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
/**
* transform Object to any Class
* for example : readValue(new Student(),Map.class) -> transform instance of Student Class to Map instance
* readValue(new String("{\"name\":\"Eric",\"age\":\"23\"}"),Student.class) -> transform string to Student class instance
*
* @param object
* @param clazz
* @param
* @return
*/
public static T readValue(Object object, Class clazz) {
Objects.requireNonNull(object,"param can not be null");
new JSONHelper().initObjectMapper();
try {
return object instanceof String
? readValue(object.toString(), clazz)
: objectMapper.readValue(toJSON(object), clazz);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* transform Object to List of any Class
* for example : readValue(new String("[{\"name\":\"Eric\",\"age\":\"23\"}]"),Student.class) -> transform string to List class instance
*
* @param object
* @param clazz
* @param
* @return
*/
public static List readValueList(Object object, Class clazz) {
Objects.requireNonNull(object,"param can not be null");
new JSONHelper().initObjectMapper();
JavaType javaType = objectMapper.getTypeFactory().constructParametricType(List.class, clazz);
try {
return object instanceof String
? readValueList(object.toString(), javaType)
: objectMapper.readValue(toJSON(object), javaType);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
private static T readValue(String original, Class clazz) {
new JSONHelper().initObjectMapper();
try {
return objectMapper.readValue(original, clazz);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static List readValueList(String original, Class clazz) {
new JSONHelper().initObjectMapper();
JavaType javaType = objectMapper.getTypeFactory().constructParametricType(List.class, clazz);
try {
return objectMapper.readValue(original, javaType);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
private static List readValueList(String original, JavaType javaType) {
new JSONHelper().initObjectMapper();
try {
return objectMapper.readValue(original, javaType);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* make sure JSONHelper is singleton , user spin , use more CPU,more efficient
* thread safe
*/
private void initObjectMapper() {
while (objectMapper == null) {
int flag_cur;
if ((flag_cur = flag) < 0)
Thread.yield();//lose initialization race, just spin
else if (U.compareAndSwapInt(this, FLAG, flag_cur, -1)) {
if (objectMapper == null) {
try {
objectMapper = new ObjectMapper();
objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
flag_cur = 1;
} finally {
flag = flag_cur;
}
break;
}
}
}
}
private static sun.misc.Unsafe U;
private static long FLAG;
static {
try {
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
U = (Unsafe) field.get(null);
Class> k = JSONHelper.class;
FLAG = U.objectFieldOffset(k.getDeclaredField("flag"));
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
throw new Error(e);
}
}
}
具体使用都有说明,按照说明,即可实现JSON解析。
示例均使用lombok插件,建议现在IDE上安装该插件。
例1:Object 转 String
Student.java
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
@Accessors(chain = true)
public class Student {
@JsonProperty("stu_name")
private String stuName;
private Integer age;
}
JSONTest.java
import com.cn.util.JSONHelper;
public class JOSNTest {
public static void main(String[] args){
Student student = new Student().setStuName("Eric")
.setAge(23);
String studentJson = JSONHelper.toJSON(student);
System.out.print(studentJson);
}
}
output:{"age":23,"stu_name":"Eric"}
注:在jackson解析中,可以使用@JsonProperty来改变json解析之后的键值,比如Student.java中变量名为stuName,解析之后为stu_name。
例2:String 转 Object (String to Student)
Student.java 请参考例1
JSONTest.java
import com.cn.util.JSONHelper;
public class JOSNTest {
public static void main(String[] args){
String studentStr = "{\"age\":23,\"stu_name\":\"Eric\"}";
Student student1 = JSONHelper.readValue(studentStr,Student.class);
assert student1 != null;
System.out.println(student1.toString());
}
output:Student(stuName=Eric, age=23)
同理,如果是Map转Student,也是一样的,如下:
JSONTest.java
import com.cn.util.JSONHelper;
import java.util.HashMap;
import java.util.Map;
public class JOSNTest {
public static void main(String[] args){
Map map = new HashMap(3){
{
put("age",23);
put("stu_name","Eric");
}
};
Student student2 = JSONHelper.readValue(map,Student.class);
assert student2 != null;
System.out.println(student2.toString());
}
}
output:Student(stuName=Eric, age=23)
例3. String 转 List
JSONTest.java
import com.cn.util.JSONHelper;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class JOSNTest {
public static void main(String[] args){
String students = "[{\"age\":23,\"stu_name\":\"Eric\"},{\"age\":25,\"stu_name\":\"Jack\"}]";
List student3 = JSONHelper.readValueList(students,Student.class);
assert student3 != null;
System.out.println(student3.toString());
}
}
output:[Student(stuName=Eric, age=23), Student(stuName=Jack, age=25)]
例4. enum的处理办法
在jackson解析中,如果直接处理enum的话,通常会得到实例名称,如下
Major.java
public enum Major {
MATH("math"),
ENGLISH("english");
private String name;
Major(String name){
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
每个实例有一个大写的名称(MATH)跟一个小写的值(math)
Student.java 中添加一个Major枚举类型,代表每个学生有会一门主修课
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.experimental.Accessors;
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
@Accessors(chain = true)
public class Student {
@JsonProperty("stu_name")
private String stuName;
private Integer age;
private Major major;
}
JSONTest.java
import com.cn.util.JSONHelper;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class JOSNTest {
public static void main(String[] args){
Student student = new Student().setStuName("Eric")
.setAge(23)
.setMajor(Major.ENGLISH);
String studentJson = JSONHelper.toJSON(student);
System.out.println(studentJson);
}
}
output:{"age":23,"major":"ENGLISH","stu_name":"Eric"}
发现,major属性是大写的ENGLISH,就是枚举类的实例名称,那么如果我们想要得到小写的名称有什么办法呢?
两种办法:1.把实例名称ENGLISH改成小写的,解析的时候就直接得到了。
2.使用@JsonValue属性
我们主要讲第2中方法
Major.java
import com.fasterxml.jackson.annotation.JsonValue;
public enum Major {
MATH("math"),
ENGLISH("english");
private String name;
Major(String name){
this.name = name;
}
@JsonValue
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Student.java 不变
JSONTest.java 不变
output:{"age":23,"major":"english","stu_name":"Eric"}
总结:目前,JSONHelper已经在我的项目成为一个必备的Json解析工具。在这里分享出来,希望能帮助到更多的人。
如果觉得有帮助,可以关注一下,谢谢。
声明:原创博客,谢绝转载。