GSON从复杂对象创建一个对象

时间:2012-03-02 15:42:34

标签: annotations gson

想象一下,我们有以下两个类:

public class Test {
    private String element1;
    private SubTest subTest;
}
public class SubTest {
    private String element2;
}

如果我从Test类创建json,我将有下一个字符串:

{element1:null,subTest:{element2:null}}

但我需要结果json这个观点:

{element1:null,subTest_element2:null}

我知道我可以通过创建一个适配器来实现这一点,我可以根据需要实现序列化方法,但我需要其他东西,例如注释,我将放在private SubTest subTest;

有人可以帮我吗?

1 个答案:

答案 0 :(得分:2)

Gson 2.2的新TypeAdapterFactory接口为您提供了检查传入类型注释的钩子,并根据这些注释定义了类型适配器。这是一个查找带注释的字段JsonInlined的完整示例。如果找到,则类型适配器将外部对象序列化为内部对象。

@Retention(RetentionPolicy.RUNTIME)
@interface JsonInlined {}

static class InlinedFieldFactory implements TypeAdapterFactory {
  public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
    Class<? super T> rawType = type.getRawType();
    Field field = getJsonInlinedField(rawType);
    if (field == null) {
      return null; // this factory doesn't know how to adapt this type
    }
    field.setAccessible(true);
    TypeAdapter<?> delegate = gson.getAdapter(field.getType());
    @SuppressWarnings("unchecked") // this creates a type adapter handles for instances of 'T'
    TypeAdapter<T> fieldAdapter = (TypeAdapter<T>) newAdapter(rawType, field, delegate);
    return fieldAdapter;
  }

  private Field getJsonInlinedField(Class<?> c) {
    for (Field field : c.getDeclaredFields()) {
      if (field.isAnnotationPresent(JsonInlined.class)) {
        return field;
      }
    }
    return null;
  }

  static <F> TypeAdapter<Object> newAdapter(final Class<?> c,
      final Field field, final TypeAdapter<F> fieldAdapter) {
    return new TypeAdapter<Object>() {
      @Override public void write(JsonWriter out, Object value) throws IOException {
        try {
          if (value != null) {
            @SuppressWarnings("unchecked") // we define 'F' by the type of field
            F fieldValue = (F) field.get(value);
            fieldAdapter.write(out, fieldValue);
          } else {
            out.nullValue();
          }
        } catch (IllegalAccessException e) {
          throw new AssertionError(e);
        }
      }
      @Override public Object read(JsonReader in) throws IOException {
        try {
          if (in.peek() == JsonToken.NULL) {
            return null;
          } else {
            Object instance = c.newInstance();
            field.set(instance, fieldAdapter.read(in));
            return instance;
          }
        } catch (InstantiationException e) {
          throw new AssertionError(e);
        } catch (IllegalAccessException e) {
          throw new AssertionError(e);
        }
      }
    };
  }
}

我不打算解释整个实施;对TypeAdapterTypeAdapterFactory javadocs中的移动部分有一个不错的描述。

最重要的是要记住,您可以使用其他类型适配器编写类型的适配器。工厂API强制您预先完成所有的反射。这有助于更早地捕获错误,并且还有助于您的代码更有效地运行。