我如何让Gson使用访问器而不是字段? [英] How can I get Gson to use accessors rather than fields?

查看:104
本文介绍了我如何让Gson使用访问器而不是字段?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

默认情况下,Gson使用字段作为序列化的基础。有没有办法让它使用访问器呢?

解决方案

Gson的开发者,他们从来不会因为添加此功能的请求而感到不安,而且他们担心为了增加对此功能的支持而使用api。

添加此功能的一种方法是使用TypeAdapter(我为粗糙的代码道歉,但这表明了原则):

  import java.io.IOException; 
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

导入com.google.common.base.CaseFormat;
import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;

public class AccessorBasedTypeAdaptor< T>扩展TypeAdapter< T> {

私人Gson gson;

public AccessorBasedTypeAdaptor(Gson gson){
this.gson = gson;
}

@SuppressWarnings(unchecked)
@Override
public void write(JsonWriter out,T value)throws IOException {
out.beginObject ();
for(Method method:value.getClass()。getMethods()){
boolean nonBooleanAccessor = method.getName()。startsWith(get);
boolean booleanAccessor = method.getName()。startsWith(is); $()(){
if((nonBooleanAccessor || booleanAccessor)&&!method.getName()。equals(getClass)&& amp; method.getParameterTypes()。length == 0){
try {
String name = method.getName()。substring(nonBooleanAccessor?3:2);
name = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_CAMEL,name);
Object returnValue = method.invoke(value);
if(returnValue!= null){
TypeToken<?> token = TypeToken.get(returnValue.getClass());
TypeAdapter adapter = gson.getAdapter(token);
out.name(name);
adapter.write(out,returnValue);
}
} catch(Exception e){
throw new ConfigurationException(编写json:的问题,e);
}
}
}
out.endObject();

$ b @Override
public T read(JsonReader in)throws IOException {
throw new UnsupportedOperationException(Only supports writes。);






$ b

您可以将其注册为普通类型的适配器给定类型或通过TypeAdapterfactory - 可能检查是否存在运行时注释:

  public class TypeFactory implements TypeAdapterFactory {

@SuppressWarnings(未选中)
public< T> TypeAdapter< T>创建(最终的Gson gson,最终的TypeToken< T>类型){
Class< ;?超T> t = type.getRawType();
if(t.isAnnotationPresent(UseAccessor.class)){
return(TypeAdapter< T>)new AccessorBasedTypeAdaptor(gson);
}
返回null;

创建gson实例时,可以将其指定为正常值:

  new GsonBuilder()。registerTypeAdapterFactory(new TypeFactory())。create(); 


By default Gson uses fields as a basis for it's serialization. Is there a way to get it to use accessors instead?

解决方案

The developers of Gson say that they never felt swayed by the requests to add this feature and they were worried about murkying up the api to add support for this.

One way of adding this functionality is by using a TypeAdapter (I apologize for the gnarly code but this demonstrates the principle):

import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import com.google.common.base.CaseFormat;
import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;

public class AccessorBasedTypeAdaptor<T> extends TypeAdapter<T> {

  private Gson gson;

  public AccessorBasedTypeAdaptor(Gson gson) {
    this.gson = gson;
  }

  @SuppressWarnings("unchecked")
  @Override
  public void write(JsonWriter out, T value) throws IOException {
    out.beginObject();
    for (Method method : value.getClass().getMethods()) {
      boolean nonBooleanAccessor = method.getName().startsWith("get");
      boolean booleanAccessor = method.getName().startsWith("is");
      if ((nonBooleanAccessor || booleanAccessor) && !method.getName().equals("getClass") && method.getParameterTypes().length == 0) {
        try {
          String name = method.getName().substring(nonBooleanAccessor ? 3 : 2);
          name = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_CAMEL, name);
          Object returnValue = method.invoke(value);
          if(returnValue != null) {
            TypeToken<?> token = TypeToken.get(returnValue.getClass());
            TypeAdapter adapter = gson.getAdapter(token);
            out.name(name);
            adapter.write(out, returnValue);
          }
        } catch (Exception e) {
          throw new ConfigurationException("problem writing json: ", e);
        }
      }
    }
    out.endObject();
  }

  @Override
  public T read(JsonReader in) throws IOException {
    throw new UnsupportedOperationException("Only supports writes.");
  }
}

You can register this as a normal type adapter for a given type or through a TypeAdapterfactory - possibly checking for the presence of a runtime annotation:

public class TypeFactory implements TypeAdapterFactory {

  @SuppressWarnings("unchecked")
  public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> type) {
    Class<? super T> t = type.getRawType();
    if(t.isAnnotationPresent(UseAccessor.class)) {
     return (TypeAdapter<T>) new AccessorBasedTypeAdaptor(gson);
    }
    return null;
  }

This can be specified as normal when creating your gson instance:

new GsonBuilder().registerTypeAdapterFactory(new TypeFactory()).create();

这篇关于我如何让Gson使用访问器而不是字段?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆