JSONUtil之JSONHelper

在平时工作处理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解析工具。在这里分享出来,希望能帮助到更多的人。

如果觉得有帮助,可以关注一下,谢谢。

声明:原创博客,谢绝转载。

 

 

你可能感兴趣的:(Java)