Jdk8 suportted JacksonUtil

XML、JSON 处理的烦恼

java中处理json与xml数据时,有各种各样的第三方库供用户选择。其中具有代表性的有 Gson、FastJson、Jackson、Json-lib、xstream、jaxb 等等。
正因为 java 中可供的选择实在太多,若随意的选用库去处理 json 与 xml 的话,不仅会造成代码混乱难以维护,还会让你的 jar 或 war 的体积膨胀,增加 release 成本。

使用Jackson

为了避免这样的灾难发生,我们要想办法统一程序员们处理 json 与 xml 数据时使用的库。恰恰 jackson 在易用性、效率、社区活跃程度上都是上述第三方库中的佼佼者,能够满足我们的需求。

优秀的 common-Utils 往往都能支持最新的 API,而最新的 jackson 库已经 全面支持了 jdk8 中的新日期 API。
使用支持 jdk8 日期处理 API 的 jackson 需要导入下面这些版本,或以上版本的库。

Jdk8 suportted JacksonUtil_第1张图片
屏幕快照 2016-11-19 下午2.36.33.png-21.4kB

Jackson中的注解支持##

使用 jackson 处理 xml 与 json 的一大好处在于,序列化时使用的注解是通用的。同样的注解能够生效与 json 与 xml 的序列化与反序列化。

  • @JsonIgnoreProperties({"extra"})
    类注解。在反序列化 json 数据时能够忽略注解参数中对应的 json keys。而使用@JsonIgnoreProperties(ignoreUnknown=true) 能够使忽略所有未知元素 。

  • @JsonSerialize(using = JacksonUtil.JsonLocalDateSerializer.class)
    属性注解。需要使用自定义序列化与反序列化解析器时,使用该注解修饰类成员变量。

  • @JsonIgnore
    属性注解。序列化与反序列化时忽略被该注解修饰的成员。

  • @JsonProperty("firstName")
    属性注解。在序列化与反序列化时使用别名。

自定义序列化与反序列化解析器##

通过继承 JsonSerializer 与 JsonDeserializer,我们能够实现自己的解析器。通常自己的解析器用来处理将一个 json 字符串映射为 pojo 的 DateTime 类型属性的问题。

序列化###

    /**
     * 自定义日期序列化处理类
     * LocalDateTime
     * jdk8 support
     */
    public static class JsonLocalDateTimeSerializer extends JsonSerializer {


        @Override
        public void serialize(LocalDateTime localDateTime, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
            String localdateTimeStr = localDateTime.format(DateTimeFormatter.ISO_DATE_TIME);
            jsonGenerator.writeString(localdateTimeStr);
        }
    }

反序列化###

/**
     * 自定义日期序列化处理类
     * LocalDateTime
     * jdk8 support
     */
    public static class JsonLocalDateTimeDeserializer extends JsonDeserializer {


        @Override
        public LocalDateTime deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
            String str = jsonParser.getText().trim();
            return LocalDateTime.parse(str, DateTimeFormatter.ISO_DATE_TIME);
        }
    }

Class TypeFactory##

当尝试把一个 jsonArray 转换为为 pojoList 时你会遭遇到一些小麻烦。
你必须首先使用工厂方法创建出一个 JavaType 对象,然后根据你创建出的 JavaType 对象来告诉 jackson 你希望的反序列化对象是什么样子。

 /**
     * json数据转PojoList
     *
     * @param jsonStr json数据
     * @param cls     类型
     * @param      推导类型
     * @return pojoList
     */
    public static  List jsonArray2PojoList(String jsonStr, Class cls) {
        List pojoList = null;
        try {
            CollectionType listType = objectMapper.getTypeFactory().constructCollectionType(List.class, cls);
            pojoList = objectMapper.readValue(jsonStr, listType);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return pojoList;
    }

Class TypeReference##

jackson 在反序列化对象时需要获取到对象的字节码对象。通常使用 Object.class 就能解决这个问题。不过当你期望的反序列化对象是一个泛型对象时,由于泛型的补偿与擦除问题,你是无法使用 List<>.class 的方式获取到字节码对象的。如何是好呢?
查阅文档,看看是否能获取到帮助。

This generic abstract class is used for obtaining full generics type information by sub-classing; it must be converted to ResolvedType implementation (implemented by JavaType from "databind" bundle) to be used. Class is based on ideas from http://gafter.blogspot.com/2006/12/super-type-tokens.html, Additional idea (from a suggestion made in comments of the article) is to require bogus implementation of Comparable (any such generic interface would do, as long as it forces a method with generic type to be implemented). to ensure that a Type argument is indeed given.

根据文档描述,通过TypeReference我们就能获取到泛型类的信息。

/**
     * json转listMap
     *
     * @param jsonArray jsonArray字符串
     * @return Listmap对象
     */
    public static List> jsonArray2ListMap(String jsonArray) {
        List> convertedListMap = null;
        try {
            convertedListMap = objectMapper.readValue(jsonArray, new TypeReference>>() {
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
        return convertedListMap;
    }

一个完整的JacksonUtil##

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.type.CollectionType;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;

import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;


/**
 * XML,JSON处理工具类
 * 依靠jackson提供pojo2json/xml转换
 *
 * @author lincanhan
 */

final public class JacksonUtil {


    private static ObjectMapper objectMapper = new ObjectMapper();

    private static ObjectMapper xmlMapper = new XmlMapper();


    /**
     * 防止反射调用构造器创建对象
     */
    private JacksonUtil() {
        throw new AssertionError();
    }

    /**
     * 自定义日期序列化处理类
     * LocalDateTime
     * jdk8 support
     */
    public static class JsonLocalDateTimeSerializer extends JsonSerializer {


        @Override
        public void serialize(LocalDateTime localDateTime, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
            String localdateTimeStr = localDateTime.format(DateTimeFormatter.ISO_DATE_TIME);
            jsonGenerator.writeString(localdateTimeStr);
        }
    }

    /**
     * 自定义日期序列化处理类
     * LocalDateTime
     * jdk8 support
     */
    public static class JsonLocalDateTimeDeserializer extends JsonDeserializer {


        @Override
        public LocalDateTime deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
            String str = jsonParser.getText().trim();
            return LocalDateTime.parse(str, DateTimeFormatter.ISO_DATE_TIME);
        }
    }

    /**
     * 自定义日期反序列化处理类
     * LocalDate
     * jdk8 support
     */
    public static class JsonLocalDateDeserializer extends JsonDeserializer {

        @Override
        public LocalDate deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
            String str = jsonParser.getText().trim();
            return LocalDate.parse(str, DateTimeFormatter.ISO_DATE);
        }
    }

    /**
     * 自定义日期序列化类
     * LocalDate
     * jdk8 support
     */
    public static class JsonLocalDateSerializer extends JsonSerializer {


        @Override
        public void serialize(LocalDate localDate, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
            String localdateStr = localDate.format(DateTimeFormatter.ISO_DATE);
            jsonGenerator.writeString(localdateStr);
        }
    }

    /**
     * json数据转pojo
     *
     * @param jsonStr json字符串
     * @param cls     映射类型
     * @param      推导类型
     * @return 推导类型json对象
     */
    public static  T json2Pojo(String jsonStr, Class cls) {
        T object = null;
        try {
            object = objectMapper.readValue(jsonStr, cls);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return object;
    }


    /**
     * json数据转PojoList
     *
     * @param jsonStr json数据
     * @param cls     类型
     * @param      推导类型
     * @return pojoList
     */
    public static  List jsonArray2PojoList(String jsonStr, Class cls) {
        List pojoList = null;
        try {
            CollectionType listType = objectMapper.getTypeFactory().constructCollectionType(List.class, cls);
            pojoList = objectMapper.readValue(jsonStr, listType);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return pojoList;
    }


    /**
     * pojo转json
     *
     * @param obj pojo
     * @return json字符串
     */
    public static String pojo2Json(Object obj) {
        String jsonStr = "";
        try {
            jsonStr = objectMapper.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return jsonStr;
    }

    /**
     * json转listMap
     *
     * @param jsonArray jsonArray字符串
     * @return Listmap对象
     */
    public static List> jsonArray2ListMap(String jsonArray) {
        List> convertedListMap = null;
        try {
            convertedListMap = objectMapper.readValue(jsonArray, new TypeReference>>() {
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
        return convertedListMap;
    }

    /**
     * json转map
     *
     * @param json json字符串
     * @return map对象
     */
    public static Map json2Map(String json) {
        Map convertedMap = null;
        try {
            convertedMap = objectMapper.readValue(json, new TypeReference>() {
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
        return convertedMap;
    }


    /**
     * listMap转json
     *
     * @param listMap listMap
     * @return
     */
    public static String listMap2JsonArray(List> listMap) {
        String jsonStr = "";
        try {
            jsonStr = objectMapper.writeValueAsString(listMap);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return jsonStr;
    }


    /**
     * xml转pojo
     *
     * @param xmlStr xml字符串
     * @param cls    映射对象
     * @param     推导类型
     * @return pojo
     */
    public static  T xml2Pojo(String xmlStr, Class cls) {
        T pojo = null;
        try {
            pojo = xmlMapper.readValue(xmlStr, cls);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return pojo;
    }

    /**
     * xml转pojoList
     *
     * @param xmlStr xml字符串
     * @param cls    映射对象
     * @param     推导类型
     * @return pojo
     */
    public static  List xml2PojoList(String xmlStr, Class cls) {
        CollectionType listType = objectMapper.getTypeFactory().constructCollectionType(List.class, cls);
        List pojoList = null;
        try {
            pojoList = xmlMapper.readValue(xmlStr, listType);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return pojoList;
    }


    /**
     * pojo转xml
     *
     * @param object
     */
    public static String pojo2Xml(Object object) {
        String xml = "";
        try {
            xml = xmlMapper.writeValueAsString(object);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return xml;
    }


    /**
     * xml转map
     *
     * @param xmlStr xml字符串
     * @return map对象
     */
    public static Map xml2Map(String xmlStr) {
        Map map = null;
        try {
            map = xmlMapper.readValue(xmlStr, new TypeReference>() {
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
        return map;
    }

    /**
     * xml转ListMap
     *
     * @param xmlStr xml字符串
     * @return map对象
     */
    public static List> xml2ListMap(String xmlStr) {
        List> listMap = null;
        try {
            listMap = xmlMapper.readValue(xmlStr, new TypeReference>>() {
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
        return listMap;
    }

}

Module###

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import jackson.JacksonUtil;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Arrays;

/**
 * 用户模型
 */
//@JsonIgnoreProperties(ignoreUnknown=true)忽略所有未知元素
@JsonIgnoreProperties({"extra"})
public class User {

    // 性别
    private Gender gender;
    // 姓名
    private Name name;

    private boolean isVerified;
    // 用户头像
    private byte[] userImage;

    // 用户生日
    @JsonSerialize(using = JacksonUtil.JsonLocalDateSerializer.class)
    @JsonDeserialize(using = JacksonUtil.JsonLocalDateDeserializer.class)
    private LocalDate birthday;

    // 用户登录时间
    @JsonSerialize(using = JacksonUtil.JsonLocalDateTimeSerializer.class)
    @JsonDeserialize(using = JacksonUtil.JsonLocalDateTimeDeserializer.class)
    private LocalDateTime loginTime;


    // 不想输出此属性,使用此注解。
    @JsonIgnore
    private String note;

    // 性别
    public enum Gender {
        MALE, FEMALE
    }

    // 姓名
    public static class Name {

        private String first;

        // 别名
        //@JsonProperty("LAST")
        private String last;


        public String getFirst() {
            return first;
        }

        public void setFirst(String first) {
            this.first = first;
        }

        public String getLast() {
            return last;
        }

        public void setLast(String last) {
            this.last = last;
        }

        @Override
        public String toString() {
            return "Name{" +
                    "first='" + first + '\'' +
                    ", last='" + last + '\'' +
                    '}';
        }
    }


    public LocalDate getBirthday() {
        return birthday;
    }

    public void setBirthday(LocalDate birthday) {
        this.birthday = birthday;
    }

    public LocalDateTime getLoginTime() {
        return loginTime;
    }

    public void setLoginTime(LocalDateTime loginTime) {
        this.loginTime = loginTime;
    }

    public String getNote() {
        return note;
    }

    public void setNote(String note) {
        this.note = note;
    }

    public Gender getGender() {
        return gender;
    }

    public void setGender(Gender gender) {
        this.gender = gender;
    }

    public Name getName() {
        return name;
    }

    public void setName(Name name) {
        this.name = name;
    }

    public boolean isVerified() {
        return isVerified;
    }

    public void setVerified(boolean verified) {
        this.isVerified = verified;
    }

    public byte[] getUserImage() {
        return userImage;
    }

    public void setUserImage(byte[] userImage) {
        this.userImage = userImage;
    }

    @Override
    public String toString() {
        return "User{" +
                "gender=" + gender +
                ", name=" + name +
                ", isVerified=" + isVerified +
                ", userImage=" + Arrays.toString(userImage) +
                '}';
    }


}


最后##

不仅仅是 jacksonUtil,在项目中规范化使用 dateUtil,HttpClientUtil 等等 common Utils,能够极大的增强项目的可维护性,降低bug 发生几率,缩小项目体积,减少 release 成本。
基于这样的考虑,我已经将 common-Utils 创建为了一个开源项目,如果你也有安全,高效,注释齐全维护性强的 Util 欢迎与大家分享!

你可能感兴趣的:(Jdk8 suportted JacksonUtil)