2012-03-02 101 views
1

一个对象假设我们有以下2类: 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;

有人可以帮助我吗?

回答

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迫使你在前面做所有的反思。这有助于更早地发现错误,还有助于您的代码更高效地运行。

+1

不要忘记使用GsonBuilder.registerTypeAdapterFactory(新的InlinedFieldFactory())来利用这个野兽! – 2012-03-03 06:23:58

+0

不幸的是我们使用gson 1.7.1,现在我们无法迁移到新版本。 – Deplake 2012-03-05 09:43:35

+0

为什么不呢? (我是Gson的维护者;我总是很好奇为什么人们不能获得新的热情)。 – 2012-03-06 02:34:24