2013-03-26 23 views
3

我正在嘗試使用GraphAdapterBuilder這是GSON庫的一個額外功能,以便通過循環引用序列化一個對象。它非常適用於類,但在嘗試反序列化接口時失敗。GSON GraphAdapterBuilder失敗,接口

反序列化接口(GSON默認情況下不會這樣做)我使用的是PropertyBasedInterfaceMarshalInterfaceAdapter。這些被註冊爲接口的自定義類型適配器。

當使用上面的ether時,無法對接口進行反序列化,因爲它們只傳遞GraphAdapterBuilder生成的圖形id,如「0x4」。這是作爲解串器中的JsonElement傳遞的。很顯然,在解串器中沒有任何東西可以用這個id來完成。

不應該被GraphAdapterBuilder捕獲,而不是嘗試反序列化?我一直無法解決這個問題,這是一個GraphAdapterBuilder的錯誤還是有辦法解決這個問題?

+1

你能提供你有的類和它們之間的依賴嗎?只有類,沒有微不足道的屬性。 – 2013-04-02 21:56:43

回答

1

好的,這是一個解決方案的(工作)存根。意大利已經太晚了,爲了讓它更好。

都需要這樣的

package com.google.gson.graph; 

/** 
* @author Giacomo Tesio 
*/ 
public interface GenericFunction<Domain, Codomain> { 
    Codomain map(Domain domain); 
} 

這樣的TypeAdapterFactory的委託功能:

package com.google.gson.graph; 

import com.google.gson.Gson; 
import com.google.gson.TypeAdapter; 
import com.google.gson.TypeAdapterFactory; 
import com.google.gson.reflect.TypeToken; 
import com.google.gson.stream.JsonReader; 
import com.google.gson.stream.JsonToken; 
import com.google.gson.stream.JsonWriter; 
import java.io.IOException; 
import java.util.HashMap; 
import java.util.Map; 


/** 
* @author Giacomo Tesio 
*/ 
public class InterfaceAdapterFactory implements TypeAdapterFactory { 

    final Map<String, GenericFunction<Gson, TypeAdapter<?>>> adapters; 
    private final Class<?> commonInterface; 
    public InterfaceAdapterFactory(Class<?> commonInterface, Class<?>[] concreteClasses) 
    { 
     this.commonInterface = commonInterface; 
     this.adapters = new HashMap<String, GenericFunction<Gson, TypeAdapter<?>>>(); 
     final TypeAdapterFactory me = this; 
     for(int i = 0; i < concreteClasses.length; ++i) 
     { 
      final Class<?> clazz = concreteClasses[i]; 
      this.adapters.put(clazz.getName(), new GenericFunction<Gson, TypeAdapter<?>>(){ 
       public TypeAdapter<?> map(Gson gson) { 
        TypeToken<?> type = TypeToken.get(clazz); 
        return gson.getDelegateAdapter(me, type); 
       } 
      }); 
     } 
    } 
    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) { 
     final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type); 
     if(!this.commonInterface.isAssignableFrom(type.getRawType()) 
      && !this.commonInterface.equals(type.getRawType())) 
     { 
      return delegate; 
     } 
     final TypeToken<T> typeToken = type; 
     final Gson globalGson = gson; 
     return new TypeAdapter<T>() { 
      public void write(JsonWriter out, T value) throws IOException { 
      out.beginObject(); 
      out.name("@t"); 
      out.value(value.getClass().getName()); 
      out.name("@v"); 
      delegate.write(out, value); 
      out.endObject(); 
      } 
      @SuppressWarnings({"unchecked"}) 
      public T read(JsonReader in) throws IOException { 
       JsonToken peekToken = in.peek(); 
       if(peekToken == JsonToken.NULL) { 
        in.nextNull(); 
        return null; 
       } 

       in.beginObject(); 
       String dummy = in.nextName(); 
       String typeName = in.nextString(); 
       dummy = in.nextName(); 
       TypeAdapter<?> specificDelegate = adapters.get(typeName).map(globalGson); 
       T result = (T)specificDelegate.read(in); 
       in.endObject(); 
       return result; 
      } 
     }; 
    } 

} 

一對測試,如這些

public final class InterfaceAdapterFactoryTest extends TestCase { 

    public void testInterfaceSerialization1(){ 
     SampleInterface first = new SampleImplementation1(10); 
     SampleInterfaceContainer toSerialize = new SampleInterfaceContainer("container", first); 

     GsonBuilder gsonBuilder = new GsonBuilder(); 

     new GraphAdapterBuilder() 
      .addType(SampleInterfaceContainer.class) 
      .addType(SampleImplementation1.class) 
      .addType(SampleImplementation2.class) 
      .registerOn(gsonBuilder); 
     gsonBuilder.registerTypeAdapterFactory(new InterfaceAdapterFactory(
       SampleInterface.class, new Class<?>[] { SampleImplementation1.class, SampleImplementation2.class } 
       )); 
     Gson gson = gsonBuilder.create(); 

     String json = gson.toJson(toSerialize); 
     System.out.println(json); 
     SampleInterfaceContainer deserialized = gson.fromJson(json, SampleInterfaceContainer.class); 

     assertNotNull(deserialized); 
     assertEquals(toSerialize.getName(), deserialized.getName()); 
     assertEquals(toSerialize.getContent().getNumber(), deserialized.getContent().getNumber()); 
    } 

    public void testInterfaceSerialization2(){ 
     SampleImplementation2 first = new SampleImplementation2(5, "test"); 
     SampleInterfaceContainer toSerialize = new SampleInterfaceContainer("container", first); 
     first.Container = toSerialize; 

     GsonBuilder gsonBuilder = new GsonBuilder(); 

     new GraphAdapterBuilder() 
      .addType(SampleInterfaceContainer.class) 
      .addType(SampleImplementation1.class) 
      .addType(SampleImplementation2.class) 
      .registerOn(gsonBuilder); 
     gsonBuilder.registerTypeAdapterFactory(new InterfaceAdapterFactory(
       SampleInterface.class, new Class<?>[] { SampleImplementation1.class, SampleImplementation2.class } 
       )); 
     Gson gson = gsonBuilder.create(); 

     String json = gson.toJson(toSerialize); 
     System.out.println(json); 
     SampleInterfaceContainer deserialized = gson.fromJson(json, SampleInterfaceContainer.class); 

     assertNotNull(deserialized); 
     assertEquals(toSerialize.getName(), deserialized.getName()); 
     assertEquals(5, deserialized.getContent().getNumber()); 
     assertEquals("test", ((SampleImplementation2)deserialized.getContent()).getName()); 
     assertSame(deserialized, ((SampleImplementation2)deserialized.getContent()).Container); 
    } 
} 

和一些樣品類(驗證測試通過)

public class SampleInterfaceContainer { 
    private SampleInterface content; 
    private String name; 
    public SampleInterfaceContainer(String name, SampleInterface content) 
    { 
     this.name = name; 
     this.content = content; 
    } 

    public String getName() 
    { 
     return this.name; 
    } 

    public SampleInterface getContent() 
    { 
     return this.content; 
    } 
} 
public interface SampleInterface { 
    int getNumber(); 
} 
public class SampleImplementation1 implements SampleInterface{ 
    private int number; 
    public SampleImplementation1() 
    { 
     this.number = 0; 
    } 
    public SampleImplementation1(int number) 
    { 
     this.number = number; 
    } 
    public int getNumber() 
    { 
     return this.number; 
    } 
} 

public class SampleImplementation2 implements SampleInterface{ 
    private int number; 
    private String name; 
    public SampleInterfaceContainer Container; 
    public SampleImplementation2() 
    { 
     this.number = 0; 
     this.name = ""; 
    } 
    public SampleImplementation2(int number, String name) 
    { 
     this.number = number; 
     this.name = name; 
    } 
    public int getNumber() 
    { 
     return this.number; 
    } 
    public String getName() 
    { 
     return this.name; 
    } 
} 

雖然這是一個快速的&骯髒的黑客,它的作品像一個魅力。

你只需要注意GsonBuilder初始化時的操作順序。您必須在註冊該工廠後首先初始化並註冊GraphAdapterBuilder

它很有趣(如果有點棘手,因爲我不是Java專家)。

+0

而不是基礎接口,我嘗試了一個基本的抽象類,它的工作完美。謝謝。 – 2015-07-14 11:37:40