java - 使用 Gson 反序列化可通过接口(interface)引用访问的通用类实例

标签 java json generics gson deserialization

我正在使用Universal Java Matrix Package它工作得非常好,但我无法让它与 Gson 很好地配合 - 序列化似乎工作得很好,但当然这是更容易的部分。
反序列化会产生一些问题,因为我试图将 JSON 反序列化为一个类的实例,该类具有 DefaultDenseGenericMatrix2D 类型的通用私有(private)成员,其中 Square 是我自己的类。 DefaultDenseGenericMatrix2D其中,实现 Matrix我用来引用实际成员的接口(interface)。因此,接口(interface)本身不是通用的,但实际上实现它的类是通用的。 我尝试过使用 RuntimeTypeAdapterFactory它不包含在 Gson 库本身中,但可以在其 GitHub 存储库中找到。

如果重要的话,我正在 Android 上使用它。

这是目前的样子:

// Grid
public class Grid implements Cloneable {
    private GridPosition _position; // works fine
    private GridSize _size; // this one also
    private int _dimensions; // like this one, as well
    private Matrix _squaresMatrix; // this little rascal refuses to play nice

    public Grid(GridPosition position, GridSize size) {
        _position = position;
        _size = size;

        Integer sizeValue = Converters.valueOf(size);
        _dimensions = sizeValue != null ? sizeValue : 0;

        // as you can see, it really is generic but the interface isn't
        _squaresMatrix = new DefaultDenseGenericMatrix2D<Square>(_dimensions, _dimensions); // can be either 10, 15 or 20 (100, 225 or 400 elements in total)

        // initializing the matrix, doesn't really matter
        for (long[] coordinates : _squaresMatrix.allCoordinates()) {
            Long x = coordinates[0];
            Long y = coordinates[1];

            _squaresMatrix.setAsObject(new Square(SquareState.VACANT, new Coordinates(x.intValue(), y.intValue())), coordinates);
        }
    }

    // ... (unimportant stuff)
}

/*********************************************/

// Square
public class Square {
    // all members are otherwise serialized correctly, on their own
    private SquareState _state;
    private Coordinates _coordinates;
    private Ship _owner;

    public Square(SquareState state, Coordinates coordinates) {
        _state = state;
        _coordinates = coordinates;
        _owner = null;
    }

    // ... (unimportant stuff)
}

/*********************************************/

// constructing the Gson object
Type genericType = new TypeToken<DefaultDenseGenericMatrix2D<Square>>(){}.getType(); // not used (where to put it?)
final RuntimeTypeAdapterFactory<Matrix> typeFactory = RuntimeTypeAdapterFactory
        .of(Matrix.class, "_squaresMatrix")
        // DefaultDenseGenericMatrix2D<Square>.class is illegal, of course (wouldn't make sense either way due to the infamous type erasure)
        .registerSubtype(DefaultDenseGenericMatrix2D.class);

GsonBuilder builder = new GsonBuilder().registerTypeAdapterFactory(typeFactory);
Gson gson = builder.create();

在反序列化期间,“_squaresMatrix”字段确实被反序列化,但我得到的不是 Square 类型的 DefaultDenseGenericMatrix2D,而是 LinkedTreeMap 类型,因为 Gson 不知道实际使用哪种类型,并且 DefaultDenseGenericMatrix2D 类本身可以很好地处理普通旧对象,当然。
我相信解决方案可能是在某个地方使用 TypeToken 类,但我只是不知道在哪里合并它。
作为最后的手段,我可​​以将 LinkedTreeMap 实例映射到 Square 类型的实例,因为数据就在那里,但如果可能的话,我想尽量避免这种情况。

提前谢谢您。

最佳答案

使用 InstanceCreator 允许您告诉 Gson 如何创建特定类型的实例。

在这里你可以告诉它创建一个 DefaultDenseGenericMatrix2D<Square>每次它找到 Matrix :

GsonBuilder builder = new GsonBuilder().registerTypeAdapter(Matrix.class, new MatrixInstanceCreator());
Gson gson = builder.create();

MatrixInstanceCreator是:

public class MatrixInstanceCreator()  implements InstanceCreator<Matrix> {
    @Override
    public Matrix createInstance() {
        // the dimensions will be overridden by Gson anyway
        return new DefaultDenseGenericMatrix2D<Square>(0, 0);
    }
}

警告:尽管如此,这并不是很强大,因为每个Matrix在您的应用程序中将创建为 DefaultDenseGenericMatrix2D<Square> 。但是,如果您只有这个,或者您的所有Matrix属于具体类型,无论如何这都会满足您的需求。

关于java - 使用 Gson 反序列化可通过接口(interface)引用访问的通用类实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39556500/

相关文章:

java - JSONArray 未正确返回

java - Python 的 Java 标准 for 循环的等价物是什么?

java - 在 JDBC 中使用 postgres 锁定表

json - 如何在数组数组上执行OPENJSON

json - 如何在 jmeter 中使用 json 响应 token

java - 意外绑定(bind)

javascript - 在流程中如何接受异构数组并返回该数组

java - 如何解决 java.lang.NumberFormatException : For input string: "TooLow"

JavaFX:工件仅显示空窗口

c# - 实现接口(interface)