当前位置: 首页 > 工具软件 > JSONHelper > 使用案例 >

JSONUtil之JSONHelper

公良运锋
2023-12-01

在平时工作处理JSON格式的数据比较费劲,自己根据jackson来写了一个简单实用的JSONHelper,实现了懒加载,并且是线程安全的

首先maven导入jackson包:

      <dependencies>
        <dependency>
          <groupId>com.fasterxml.jackson.core</groupId>
          <artifactId>jackson-databind</artifactId>
          <version>2.5.3</version>
        </dependency>
      </dependencies>

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 ericsteves@outlook.com
     * @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 <T>
       * @return
       */
      public static <T> T readValue(Object object, Class<T> 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<Student> class instance
       *
       * @param object
       * @param clazz
       * @param <T>
       * @return
       */
      public static <T> List<T> readValueList(Object object, Class<T> 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> T readValue(String original, Class<T> clazz) {
        new JSONHelper().initObjectMapper();
        try {
          return objectMapper.readValue(original, clazz);
        } catch (IOException e) {
          e.printStackTrace();
        }
        return null;
      }
     
      public static <T> List<T> readValueList(String original, Class<T> 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 <T> List<T> 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<String,Object> map = new HashMap<String,Object>(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<Student> 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解析工具。在这里分享出来,希望能帮助到更多的人。

如果觉得有帮助,可以关注一下,谢谢。
---------------------
作者:Death_Eric
来源:CSDN
原文:https://blog.csdn.net/Death_Eric/article/details/81782077

 类似资料: