java - 我怎样才能让 Gson 使用访问器而不是字段?

标签 java json gson

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

最佳答案

Gson 的开发者 say他们从来没有被添加此功能的请求所左右,他们担心混淆 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;

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.");
  }
}

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

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;
  }

这可以在创建 gson 实例时正常指定:

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

关于java - 我怎样才能让 Gson 使用访问器而不是字段?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11385214/

相关文章:

java - 无法使用Java在MYSQL中插入数据

Java FileInputStream 在 Windows 和 Linux 中表现出不同的行为

java - 使用 Maven 将依赖项下载到命令行上的目录

java - 如何做条件Gson反序列化默认值

Java:等于和==

json - 如何使用 flink 流式传输 json?

php - 如何将两个具有不同类型实体的数组组合成一个 json 对象?

json - 从 HttpServletRequest 检索 JSON 对象文字

android - Sharedpreference byte[] 值在通过 'Force Stop' 或任务管理器杀死应用程序后清除

java - Gson解析集合