美文网首页项目填坑工具类
解决Gson序列化实体类属性为null时返回null

解决Gson序列化实体类属性为null时返回null

作者: 黄金矿工00七 | 来源:发表于2017-09-19 19:32 被阅读0次

    问题描述: ssm框架中

    实体类属性值为null时Gson序列化返回的json对应值为null

    最近几天在给app开发接口,使用了Gson进行json的序列/反序列化,虽然Gson在使用上和性能上又优点,但是美中不足的是实体类属性为null是返回的json只有两种结果(注意我说的属性值都是String类型,Gson版本为2.8)
    1.返回的json中实体类属性值为null的对应的为null

    Gson gson = new GsonBuilder()//建造者模式设置不同的配置
            .serializeNulls()//序列化为null对象
            .setDateFormat("yyyy-MM-dd HH:mm:ss") //设置日期的格式
            .disableHtmlEscaping()//防止对网址乱码 忽略对特殊字符的转换
            .create();
    

    如所示

       {
        "uId": 1,
        "token": null,
        "code": 200,
        "userName": "admin"
    }
    

    2.返回的json中忽略了实体类属性值为null的属性

    Gson gson = new GsonBuilder()//建造者模式设置不同的配置
            .setDateFormat("yyyy-MM-dd HH:mm:ss") //设置日期的格式
            .disableHtmlEscaping()//防止对网址乱码 忽略对特殊字符的转换
            .create();
    

    如所示

       {
        "uId": 1,
        "code": 200,
        "userName": "admin"
    }
    
    两者不同请自行对比,然而这两种模式对于app来说都是无法使用的,最好的办法就是实体类属性值为空的时候返回" "(空字符串)。
    • 具体思路
      1.自定义MyHttpMessagerCovert转换器继承GsonHttpMessageConverter
      2.自定义NullStringToEmptyAdapterFactory和StringNullAdapter,重写write方法,使用""替代返回的nullValue()
      3.重新配置GsonBuilder生成我们需要的gson对象,使用自定义的适配器

    spring-mvc.xml中配置

    <!--使用自定义的转换器-->
      <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"
        p:ignoreDefaultModelOnRedirect="true" >
        <property name="messageConverters">
          <list>
            <bean class="com.xqxf.utils.MyHttpMessagerCovert">
              <!--避免IE执行Ajax时,返回JSON出现下载文件 -->
              <!-- 自定义 -->
            <property name="supportedMediaTypes">
              <list>
                <value>text/html;charset=UTF-8</value>
                <value>application/json;charset=UTF-8</value>
              </list>
            </property>
            </bean>
          </list>
        </property>
      </bean>
    
    • MyHttpMessagerCovert 类实现
    package com.xqxf.utils.Json;
    
    import com.google.gson.Gson;
    import com.google.gson.GsonBuilder;
    import com.google.gson.JsonIOException;
    import com.google.gson.reflect.TypeToken;
    import com.xqxf.dto.UserDto;
    import com.xqxf.dto.WorkOrderDto;
    import com.xqxf.utils.Json.NullStringToEmptyAdapterFactory;
    import com.xqxf.utils.Json.UserDeserializer;
    import java.io.IOException;
    import java.io.OutputStreamWriter;
    import java.lang.ref.PhantomReference;
    import java.lang.ref.WeakReference;
    import java.lang.reflect.Type;
    import java.nio.charset.Charset;
    import java.util.HashMap;
    import java.util.List;
    import org.springframework.http.HttpHeaders;
    import org.springframework.http.HttpInputMessage;
    import org.springframework.http.HttpOutputMessage;
    import org.springframework.http.MediaType;
    import org.springframework.http.converter.HttpMessageNotReadableException;
    import org.springframework.http.converter.HttpMessageNotWritableException;
    import org.springframework.http.converter.json.GsonHttpMessageConverter;
    
    /**
     * Package com.xqxf.utils
     *
     * author liyaocai
     *
     * date 2017/10/1 14:39
     *
     * Description:
     *
     * version V1.0
     */
    
    public class MyHttpMessagerCovert extends GsonHttpMessageConverter {
    
      private Gson gson = new GsonBuilder()//建造者模式设置不同的配置
          .serializeNulls()//序列化为null对象
          .setDateFormat("yyyy-MM-dd HH:mm:ss") //设置日期的格式
          .disableHtmlEscaping()//防止对网址乱码 忽略对特殊字符的转换
          .excludeFieldsWithoutExposeAnnotation()
    //      使用自定义适配器
          .registerTypeAdapterFactory(new NullStringToEmptyAdapterFactory())
          .registerTypeAdapter(UserDto.class,new UserDeserializer())
          .registerTypeAdapter(WorkOrderDto.class,new WorkOrderDeserializer())
          .create();
      private String jsonPrefix;
    
      public MyHttpMessagerCovert() {
        super();
        super.setGson(this.gson);
      }
    
    
    
      @Override
      public void setJsonPrefix(String jsonPrefix) {
        this.jsonPrefix = jsonPrefix;
      }
    
      @Override
      public void setPrefixJson(boolean prefixJson) {
        this.jsonPrefix = prefixJson ? ")]}', " : null;
      }
    
      @Override
      public Object read(Type type, Class<?> contextClass, HttpInputMessage inputMessage)
          throws IOException, HttpMessageNotReadableException {
        return super.read(type, contextClass, inputMessage);
      }
    
      @Override
      protected Object readInternal(Class<?> clazz, HttpInputMessage inputMessage)
          throws IOException, HttpMessageNotReadableException {
        return super.readInternal(clazz, inputMessage);
      }
    
      /**
       * @deprecated
       */
      @Override
      protected TypeToken<?> getTypeToken(Type type) {
        return super.getTypeToken(type);
      }
    
      @Override
      protected void writeInternal(Object o, Type type, HttpOutputMessage outputMessage)
          throws IOException, HttpMessageNotWritableException {
        Charset charset = this.getCharset(outputMessage.getHeaders());
        OutputStreamWriter writer = new OutputStreamWriter(outputMessage.getBody(), charset);
    
        try {
          if (this.jsonPrefix != null) {
            writer.append(this.jsonPrefix);
          }
    
          if (type != null) {
            this.gson.toJson(o, type, writer);
          } else {
            this.gson.toJson(o, writer);
          }
    
          writer.close();
        } catch (JsonIOException var7) {
          throw new HttpMessageNotWritableException("Could not write JSON: " + var7.getMessage(), var7);
        }
      }
    
      @Override
      protected boolean supports(Class<?> clazz) {
        return super.supports(clazz);
      }
    
      @Override
      public boolean canRead(Type type, Class<?> contextClass, MediaType mediaType) {
        return super.canRead(type, contextClass, mediaType);
      }
    
      @Override
      public boolean canWrite(Type type, Class<?> clazz, MediaType mediaType) {
        return super.canWrite(type, clazz, mediaType);
      }
    
      Charset getCharset(HttpHeaders headers) {
        return headers != null && headers.getContentType() != null
            && headers.getContentType().getCharset() != null ? headers.getContentType().getCharset()
            : DEFAULT_CHARSET;
      }
    
      @Override
      protected void writeInternal(Object o, HttpOutputMessage outputMessage)
          throws IOException, HttpMessageNotWritableException {
        super.writeInternal(o, outputMessage);
      }
    
      @Override
      public List<MediaType> getSupportedMediaTypes() {
        return super.getSupportedMediaTypes();
      }
    
      @Override
      public void setSupportedMediaTypes(List<MediaType> supportedMediaTypes) {
        super.setSupportedMediaTypes(supportedMediaTypes);
      }
    
      @Override
      public Charset getDefaultCharset() {
        return super.getDefaultCharset();
      }
    
      @Override
      public void setDefaultCharset(Charset defaultCharset) {
        super.setDefaultCharset(defaultCharset);
      }
    
      @Override
      public boolean canRead(Class<?> clazz, MediaType mediaType) {
        return super.canRead(clazz, mediaType);
      }
    
      @Override
      protected boolean canRead(MediaType mediaType) {
        return super.canRead(mediaType);
      }
    
      @Override
      public boolean canWrite(Class<?> clazz, MediaType mediaType) {
        return super.canWrite(clazz, mediaType);
      }
    
      @Override
      protected boolean canWrite(MediaType mediaType) {
        return super.canWrite(mediaType);
      }
    
      @Override
      protected void addDefaultHeaders(HttpHeaders headers, Object o, MediaType contentType)
          throws IOException {
        super.addDefaultHeaders(headers, o, contentType);
      }
    
      @Override
      protected MediaType getDefaultContentType(Object o) throws IOException {
        return super.getDefaultContentType(o);
      }
    
      @Override
      protected Long getContentLength(Object o, MediaType contentType) throws IOException {
        return super.getContentLength(o, contentType);
      }
    
      /**
       * Returns a hash code value for the object. This method is supported for the benefit of hash
       * tables such as those provided by {@link HashMap}. <p> The general contract of {@code hashCode}
       * is: <ul> <li>Whenever it is invoked on the same object more than once during an execution of a
       * Java application, the {@code hashCode} method must consistently return the same integer,
       * provided no information used in {@code equals} comparisons on the object is modified. This
       * integer need not remain consistent from one execution of an application to another execution of
       * the same application. <li>If two objects are equal according to the {@code equals(Object)}
       * method, then calling the {@code hashCode} method on each of the two objects must produce the
       * same integer result. <li>It is <em>not</em> required that if two objects are unequal according
       * to the {@link Object#equals(Object)} method, then calling the {@code hashCode} method on each
       * of the two objects must produce distinct integer results.  However, the programmer should be
       * aware that producing distinct integer results for unequal objects may improve the performance
       * of hash tables. </ul> <p> As much as is reasonably practical, the hashCode method defined by
       * class {@code Object} does return distinct integers for distinct objects. (This is typically
       * implemented by converting the internal address of the object into an integer, but this
       * implementation technique is not required by the Java&trade; programming language.)
       *
       * @return a hash code value for this object.
       * @see Object#equals(Object)
       * @see System#identityHashCode
       */
      @Override
      public int hashCode() {
        return super.hashCode();
      }
    
      /**
       * Indicates whether some other object is "equal to" this one. <p> The {@code equals} method
       * implements an equivalence relation on non-null object references: <ul> <li>It is
       * <i>reflexive</i>: for any non-null reference value {@code x}, {@code x.equals(x)} should return
       * {@code true}. <li>It is <i>symmetric</i>: for any non-null reference values {@code x} and
       * {@code y}, {@code x.equals(y)} should return {@code true} if and only if {@code y.equals(x)}
       * returns {@code true}. <li>It is <i>transitive</i>: for any non-null reference values {@code x},
       * {@code y}, and {@code z}, if {@code x.equals(y)} returns {@code true} and {@code y.equals(z)}
       * returns {@code true}, then {@code x.equals(z)} should return {@code true}. <li>It is
       * <i>consistent</i>: for any non-null reference values {@code x} and {@code y}, multiple
       * invocations of {@code x.equals(y)} consistently return {@code true} or consistently return
       * {@code false}, provided no information used in {@code equals} comparisons on the objects is
       * modified. <li>For any non-null reference value {@code x}, {@code x.equals(null)} should return
       * {@code false}. </ul> <p> The {@code equals} method for class {@code Object} implements the most
       * discriminating possible equivalence relation on objects; that is, for any non-null reference
       * values {@code x} and {@code y}, this method returns {@code true} if and only if {@code x} and
       * {@code y} refer to the same object ({@code x == y} has the value {@code true}). <p> Note that
       * it is generally necessary to override the {@code hashCode} method whenever this method is
       * overridden, so as to maintain the general contract for the {@code hashCode} method, which
       * states that equal objects must have equal hash codes.
       *
       * @param obj the reference object with which to compare.
       * @return {@code true} if this object is the same as the obj argument; {@code false} otherwise.
       * @see #hashCode()
       * @see HashMap
       */
      @Override
      public boolean equals(Object obj) {
        return super.equals(obj);
      }
    
      /**
       * Creates and returns a copy of this object.  The precise meaning of "copy" may depend on the
       * class of the object. The general intent is that, for any object {@code x}, the expression:
       * <blockquote>
       * <pre>
       * x.clone() != x</pre></blockquote>
       * will be true, and that the expression: <blockquote>
       * <pre>
       * x.clone().getClass() == x.getClass()</pre></blockquote>
       * will be {@code true}, but these are not absolute requirements. While it is typically the case
       * that: <blockquote>
       * <pre>
       * x.clone().equals(x)</pre></blockquote>
       * will be {@code true}, this is not an absolute requirement. <p> By convention, the returned
       * object should be obtained by calling {@code super.clone}.  If a class and all of its
       * superclasses (except {@code Object}) obey this convention, it will be the case that {@code
       * x.clone().getClass() == x.getClass()}. <p> By convention, the object returned by this method
       * should be independent of this object (which is being cloned).  To achieve this independence, it
       * may be necessary to modify one or more fields of the object returned by {@code super.clone}
       * before returning it.  Typically, this means copying any mutable objects that comprise the
       * internal "deep structure" of the object being cloned and replacing the references to these
       * objects with references to the copies.  If a class contains only primitive fields or references
       * to immutable objects, then it is usually the case that no fields in the object returned by
       * {@code super.clone} need to be modified. <p> The method {@code clone} for class {@code Object}
       * performs a specific cloning operation. First, if the class of this object does not implement
       * the interface {@code Cloneable}, then a {@code CloneNotSupportedException} is thrown. Note that
       * all arrays are considered to implement the interface {@code Cloneable} and that the return type
       * of the {@code clone} method of an array type {@code T[]} is {@code T[]} where T is any
       * reference or primitive type. Otherwise, this method creates a new instance of the class of this
       * object and initializes all its fields with exactly the contents of the corresponding fields of
       * this object, as if by assignment; the contents of the fields are not themselves cloned. Thus,
       * this method performs a "shallow copy" of this object, not a "deep copy" operation. <p> The
       * class {@code Object} does not itself implement the interface {@code Cloneable}, so calling the
       * {@code clone} method on an object whose class is {@code Object} will result in throwing an
       * exception at run time.
       *
       * @return a clone of this instance.
       * @throws CloneNotSupportedException if the object's class does not support the {@code Cloneable}
       * interface. Subclasses that override the {@code clone} method can also throw this exception to
       * indicate that an instance cannot be cloned.
       * @see Cloneable
       */
      @Override
      protected Object clone() throws CloneNotSupportedException {
        return super.clone();
      }
    
      /**
       * Returns a string representation of the object. In general, the {@code toString} method returns
       * a string that "textually represents" this object. The result should be a concise but
       * informative representation that is easy for a person to read. It is recommended that all
       * subclasses override this method. <p> The {@code toString} method for class {@code Object}
       * returns a string consisting of the name of the class of which the object is an instance, the
       * at-sign character `{@code @}', and the unsigned hexadecimal representation of the hash code of
       * the object. In other words, this method returns a string equal to the value of: <blockquote>
       * <pre>
       * getClass().getName() + '@' + Integer.toHexString(hashCode())
       * </pre></blockquote>
       *
       * @return a string representation of the object.
       */
      @Override
      public String toString() {
        return super.toString();
      }
    
      /**
       * Called by the garbage collector on an object when garbage collection determines that there are
       * no more references to the object. A subclass overrides the {@code finalize} method to dispose
       * of system resources or to perform other cleanup. <p> The general contract of {@code finalize}
       * is that it is invoked if and when the Java&trade; virtual machine has determined that there is
       * no longer any means by which this object can be accessed by any thread that has not yet died,
       * except as a result of an action taken by the finalization of some other object or class which
       * is ready to be finalized. The {@code finalize} method may take any action, including making
       * this object available again to other threads; the usual purpose of {@code finalize}, however,
       * is to perform cleanup actions before the object is irrevocably discarded. For example, the
       * finalize method for an object that represents an input/output connection might perform explicit
       * I/O transactions to break the connection before the object is permanently discarded. <p> The
       * {@code finalize} method of class {@code Object} performs no special action; it simply returns
       * normally. Subclasses of {@code Object} may override this definition. <p> The Java programming
       * language does not guarantee which thread will invoke the {@code finalize} method for any given
       * object. It is guaranteed, however, that the thread that invokes finalize will not be holding
       * any user-visible synchronization locks when finalize is invoked. If an uncaught exception is
       * thrown by the finalize method, the exception is ignored and finalization of that object
       * terminates. <p> After the {@code finalize} method has been invoked for an object, no further
       * action is taken until the Java virtual machine has again determined that there is no longer any
       * means by which this object can be accessed by any thread that has not yet died, including
       * possible actions by other objects or classes which are ready to be finalized, at which point
       * the object may be discarded. <p> The {@code finalize} method is never invoked more than once by
       * a Java virtual machine for any given object. <p> Any exception thrown by the {@code finalize}
       * method causes the finalization of this object to be halted, but is otherwise ignored.
       *
       * @throws Throwable the {@code Exception} raised by this method
       * @jls 12.6 Finalization of Class Instances
       * @see WeakReference
       * @see PhantomReference
       */
      @Override
      protected void finalize() throws Throwable {
        super.finalize();
      }
    }
    
    
    • StringNullAdapter类实现
    /**
     * Package com.xqxf.utils
     *
     * author liyaocai
     *
     * date 2017/10/1 15:22
     *
     * Description:
     *
     * version V1.0
     */
    
    public class StringNullAdapter extends TypeAdapter<String> {
    
      @Override
      public String read(JsonReader reader) throws IOException {
        // TODO Auto-generated method stub
        if (reader.peek() == JsonToken.NULL) {
          reader.nextNull();
          return "";
        }
        return reader.nextString();
      }
    
      @Override
      public void write(JsonWriter writer, String value) throws IOException {
        // TODO Auto-generated method stub
        if (value == null) {
          writer.value("");
          return;
        }
        writer.value(value);
      }
    }
    
    
    • NullStringToEmptyAdapterFactory类实现
    
    /**
     * Package com.xqxf.utils
     *
     * author liyaocai
     *
     * date 2017/10/1 15:23
     *
     * Description:
     *
     * version V1.0
     */
    
    public class NullStringToEmptyAdapterFactory<T> implements TypeAdapterFactory {
    
      @SuppressWarnings("unchecked")
      public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
        Class<T> rawType = (Class<T>) type.getRawType();
        if (rawType != String.class) {
          return null;
        }
        return (TypeAdapter<T>) new StringNullAdapter();
      }
    }
    
    

    相关文章

      网友评论

        本文标题:解决Gson序列化实体类属性为null时返回null

        本文链接:https://www.haomeiwen.com/subject/wbjgsxtx.html