繁体   English   中英

通用类的XStream反序列化返回java.lang.Object

[英]XStream deserialization of generic class returns java.lang.Object

我正在努力将一些XML转换为通用类的对象。 我的代码适用于非泛型类,但不适用于泛型类。

让我们看一下这个例子,它使解释变得更容易。 我使用通用类和非通用类来比较它们的行为。

Xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<Box>
    <doubleFieldA>
        <myGenericField>20.3</myGenericField>
    </doubleFieldA>
    <doubleFieldB>
        <myNonGenericField>20.3</myNonGenericField>
    </doubleFieldB>
</Box>

XSD模式:

<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Box">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="doubleFieldA">
          <xs:complexType>
            <xs:sequence>
              <xs:element type="xs:double" name="myGenericField"/>
            </xs:sequence>
          </xs:complexType>
        </xs:element>
        <xs:element name="doubleFieldB">
          <xs:complexType>
            <xs:sequence>
              <xs:element type="xs:double" name="myNonGenericField"/>
            </xs:sequence>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
</xs:element>

GenericClass.java:

public class GenericClass<T> {
    public T myGenericField;
}

NonGenericClass.java:

public class NonGenericClass {
    public double myNonGenericField;
}

Box.java:

import com.thoughtworks.xstream.XStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;

public class Box {
    public GenericClass<Double> doubleFieldA;
    public NonGenericClass doubleFieldB;

    private void deserialize() {
        Box b;
        String s;
        XStream xs = new XStream();
        try{
            s = new String(Files.readAllBytes(Paths.get("src/my_xml.xml")));
            b = (Box)xs.fromXML(s);
            doubleFieldA = b.doubleFieldA;
            doubleFieldB = b.doubleFieldB;
        } catch (IOException ioe) {
            System.err.println("IOException: " + ioe.getMessage());
        }
    }

    public Box() {
        deserialize();
    }
}

Main.java:

public class Main {

    public static void main(String[] args) {
        Box box = new Box();
        System.out.println("myGenericField = " + box.doubleFieldA.myGenericField);
        System.out.println("myNonGenericField = " + box.doubleFieldB.myNonGenericField);
    }
}

输出:

myGenericField = java.lang.Object@2d928643

myNonGenericField = 20.3

预期的输出(我想要什么!):

myGenericField = 20.3

myNonGenericField = 20.3

我有一个具有两个属性的Box类:一个是通用类,另一个只是普通类。
两者都有一个属性,在此特定示例中,其类型为double。
我尝试使用XStream使用存储在XML文件(两个均为20.3)中的值来初始化它们。
最终,当我打印这些属性时,我为非泛型类获得了正确的值。 相反,泛型类属性将导致java.lang.Object。
我应该如何修改代码以获得预期的行为?

我怀疑问题可能出在XStream处理泛型类型的方式上,但我不确定。 一般而言,我对XStream和XML技术没有太多的经验,所以我非常希望通过有效的代码/示例获得答案,而不是“您需要实现XYZ,在此凌乱的教程中了解如何实现!”。

非常感谢你!

注意:此代码的唯一目的是显示我的问题。 我在一个更大的项目中遇到了这个问题,所以这只是重现它的一个小例子。

使用XStream并没有很好的方法,只是不知道泛型甚至存在。 您可以添加自定义转换器:

public static class BoxConverter implements Converter {

    public boolean canConvert(Class clazz) {
            return clazz.equals(Box.class);
    }

    public void marshal(Object value, HierarchicalStreamWriter writer,
                    MarshallingContext context) {
            throw new RuntimeException("to do");
    }

    public Object unmarshal(HierarchicalStreamReader reader,
                    UnmarshallingContext context) {
            Box box = new Box();
             while (reader.hasMoreChildren()) {
                    reader.moveDown();
                    if ("doubleFieldA".equals(reader.getNodeName())) {
                            reader.moveDown();
                            Double val = Double.valueOf(reader.getValue());
                            reader.moveUp();
                            GenericClass<Double> genericObject = new GenericClass<>();
                            genericObject.myGenericField = val;
                            box.doubleFieldA = genericObject;
                    } else if ("doubleFieldB".equals(reader.getNodeName())) {
                            box.doubleFieldB =(NonGenericClass)context.convertAnother(box, NonGenericClass.class);
                    }
                    reader.moveUp();
            }
            return box;
    }
}

并注册:

XStream xs = new XStream();
xs.registerConverter(new BoxConverter());
Box b = (Box) xs.fromXML(input);

但这需要为每个具有GenericClass作为字段/成员的类编写一个单独的转换器。 请注意,当您使用XStream封送此类对象时,它会生成:

<Box>
  <doubleFieldA>
    <myGenericField class="double">20.3</myGenericField>
  </doubleFieldA>
  <doubleFieldB>
    <myNonGenericField>20.3</myNonGenericField>
  </doubleFieldB>
</Box>

XStream无法自行推断出额外的class="double"

这里的问题是TypeErasure ,尤其是

如果类型参数不受限制,则将通用类型中的所有类型参数替换为其边界或对象。 因此,产生的字节码仅包含普通的类,接口和方法。

所以

public T myGenericField;

public Object myGenericField; 

在运行时/在字节码中。

因此XStream无法确定myGenericField应该为double ...,因此将其反序列化为Object实例。

java.lang.Object@2d928643只是myGenericField.toString()的输出

因此,我看到的唯一方法是创建一个自定义转换器

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM