4

我正在尝试使用GraphAdapterBuilder来序列化具有循环引用的对象,它是 GSON 库的附加组件。它适用于类,但在尝试反序列化接口时失败。

要反序列化接口(默认情况下 GSON 不这样做),我使用的是PropertyBasedInterfaceMarshalInterfaceAdapter。这些被注册为接口的自定义类型适配器。

当使用上面的以太时,两者都无法反序列化接口,因为它们只传递了由 GraphAdapterBuilder 生成的图形 ID,如“0x4”。这在反序列化器中作为 JsonElement 传递。显然,在反序列化器中无法用这个 id 做任何事情。

这些不应该被 GraphAdapterBuilder 捕获而不是尝试反序列化吗?我无法解决这个问题,这是 GraphAdapterBuilder 的错误还是有办法解决这个问题?

4

1 回答 1

2

好的,这是解决方案的(工作)存根。在意大利为时已晚,无法让它变得更好。

您需要这样的委托功能

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 专家,所以有点棘手)。

于 2013-04-05T01:01:08.283 回答