2013-03-26 78 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