2017-10-11 1 views
0

목표는 Collection 인터페이스를 구현하는 클래스를 JSON 배열 대신 JSON 객체로 직렬화하는 것입니다.GSON을 사용하여 JsonArray 대신 JsonObject로 컬렉션을 serialize

public class CollectionImplementation implements Collection<String> { 
    private final List<String> _wrappedList = new LinkedList<>(); 
    private String _otherField = "asdf"; 

    @Override 
    public boolean add(String e) { 
    return _wrappedList.add(e); 
    } 

    @Override 
    ... 
} 

new Gson().toJson(collectionImplementationInstance)의 결과이다 : 다른 필드 그리워

["str1","str2",...] 

다음 클래스는 simplyfied 예이다. 대신 다음을 얻으려고합니다 :

{"_wrappedList":["str1","str2"],"_otherField":"asdf"} 

수동으로 모든 필드를 JSON에 추가하지 않고 방법이 있습니까?

+0

CollectionTypeAdapterFactory가 JSON 배열을 만드는 유형 어댑터를 생성하고 ReflectiveTypeAdapterFactory가 내 목표로 연결되는 유형 어댑터를 생성한다는 것을 알았습니다. 다른 유형의 어댑터에 위임하는 방법에 대해 알고 있지만 ReflectiveTypeAdapterFactory에서 유형 어댑터의 유효한 인스턴스를 얻으려면 어떻게해야합니까? – efzwo

답변

0

this tutorial을 기반으로하면 JsonSerializer를 사용할 수 있습니다.

참고 : 아래 예제에서 클래스 이름을 CollectionImpl로 변경했습니다.

public class CollectionImpl implements Collection<String> { 

    private final List<String> _wrappedList = new LinkedList<>(); 
    private String _otherField = "asdf"; 

    // ... 

    // Note: I've created the class as subclass of CollectionImpl in order to access the 
    // private fields without implementing a getter (as you maybe want to keep 
    // your fields completely private) 
    public static class CollectionImplJsonSerializer implements JsonSerializer<CollectionImpl> { 
     @Override 
     public JsonElement serialize(CollectionImpl src, Type typeOfSrc, JsonSerializationContext context) { 
      JsonObject jsonColl = new JsonObject(); 
      JsonArray array = new JsonArray(); 

      for (String s: src._wrappedList) { 
       array.add(s); 
      } 

      jsonColl.add("_wrappedList", array); 
      jsonColl.addProperty("_otherField", src._otherField); 


      return jsonColl; 
     } 
    } 
} 

그럼 당신은 할 수 있습니다 :

CollectionImpl ci = new CollectionImpl(); 

GsonBuilder builder = new GsonBuilder(); 
CollectionImpl.CollectionImplJsonSerializer serializer = new CollectionImpl.CollectionImplJsonSerializer(); 
builder.registerTypeAdapter(CollectionImpl.class, serializer); 
Gson gson = builder.create(); 

String json = gson.toJson(ci); 
+0

이미 내 질문에 직접 모든 필드/속성을 추가하지 않고 솔루션을 찾고 있어요. – efzwo

+0

죄송합니다.이 라인을 놓쳤습니다. Serializer/Deserializer를 구현하지 않고는 불가능하다고 생각합니다. Idk는 당신이 달성하려고 시도하지만 다른 옵션은 클래스가'Collection <>'을 구현하지 않을 수있다. – Eselfar

0

을 해결 방법으로, 하나는 자신의 TypeAdapterFactoryReflectiveTypeAdapterFactory의 인스턴스를 얻기 위해 반사를 사용할 수 있습니다

public class CollectionImplementationTypeAdapterFactory implements TypeAdapterFactory { 
    @Override 
    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) { 
    if (!type.getRawType().equals(CollectionImplementation.class)) { 
     return null; 
    } 
    try { 
     Field factoriesField = Gson.class.getDeclaredField("factories"); 
     factoriesField.setAccessible(true); 
     @SuppressWarnings("unchecked") 
     List<TypeAdapterFactory> factories = (List<TypeAdapterFactory>) factoriesField.get(gson); 
     TypeAdapterFactory typeAdapterFactory = factories.stream().filter(f -> f instanceof ReflectiveTypeAdapterFactory).findAny().get(); 
     return typeAdapterFactory.create(gson, type); 
    } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException exception) { 
     return null; 
    } 
    } 
} 

이 등록 할 수 있습니다 와 함께

gsonBuilder.registerTypeAdapterFactory(new CollectionImplementationTypeAdapterFactory()); 

누군가 Reflection이없는 해결책을 알고 있습니까?

관련 문제