如何编组和解组对象类型字段?

时间:2014-02-26 00:02:42

标签: java marshalling xstream unmarshalling

我有一个带有通用方法的接口

public interface A {
  public void setValue(Object value);
  public Object getValue();
  }

实现此接口但将值限制为某个特定枚举类的类(例如,值为X,Y,Z):

public class B implements A {
  private MyEnum value=null;
  public Object getValue() { return value; }
  public void setValue(Object value) { 
    if (!(value instanceof MyEnum)) throw IllegalArgumentException(...);
    this.value=(MyEnum)value;
    }
  }

对于编组和解组,我写了一个特定的转换器 对于编组,我有

public boolean canConvert(Class clazz) {
    return A.class.isAssignableFrom(clazz);
}

public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
    ...
    A entry = (A) source;
    writer.startNode("value");
    context.convertAnother(entry.getValue());
    writer.endNode();
    ...
}

这将产生B类的实例

...
    <value>X</value>
...

XStream不会添加任何有关此字段类的说明。只是枚举的字符串值。

对于我的解组:

public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
  ...
  reader.moveDown();
  Object type = context.convertAnother(extra, Object.class);
  extra.setValue(type);
  reader.moveUp();
  ...
  return extra;
}

我放Object.class因为我不知道它包含哪种对象类型。我希望XStream能够添加一些有关它的信息。

这会失败,因为Object type = context.convertAnother(extra, Object.class)使用“X”字符串而不会产生类型为MyEnum 的对象,这是extra.setValue(type)所期望的。 / p>

如何强制或添加信息以便XStream知道它必须生成的对象类型?

感谢您阅读这篇长篇文章......

2 个答案:

答案 0 :(得分:2)

我按照这里的建议添加了一些关于值类的信息,并将其用于解组。我发布我的工作解决方案作为对可能发现此问题的任何其他读者的参考:

public static class ExtraSearchOptionConverter implements Converter {
    public boolean canConvert(Class type) {
        return ExtraSearchOption.class.isAssignableFrom(type);
    }
    public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
        ExtraSearchOption entry = (ExtraSearchOption) source;
        ...
        if (entry.getValue() != null) {
            writer.startNode("value");
            writer.addAttribute("class", entry.getValue().getClass().getName());
            context.convertAnother(entry.getValue());
            writer.endNode();
        }
    }
    public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
        ExtraSearchOption extra = new ExtraSearchOption();
        ...
        if (reader.hasMoreChildren()) {
            reader.moveDown();
            String className = reader.getAttribute("class");
            Class<?> valueClass = null;
            if (className != null) {
                try {
                    valueClass = Class.forName(className);
                    Object type = context.convertAnother(extra, valueClass);
                    extra.setValue(type);
                } catch (ClassNotFoundException ex) {
                    logger.error("While retrieving class for ExtraSearchOptions value", ex);
                    }
            }
            reader.moveUp();
        }

        return extra;
    }

}

答案 1 :(得分:0)

默认情况下,如果XStream遇到一个对象,该对象的类派生自XStream类可以转换的类,它会将类名放在“class”属性中。

如果您的转化器canConvert()true返回Object.class,那么您基本上会覆盖XStream的默认转换器,您有责任完成以前的操作。除非您实现了自己存储类型信息的方法,否则您将无法获得有关XML中类的信息。

要么放弃A.class / Object.class转换器(不知道你没有显示你的转换器你有什么),并且仅使转换器特定于具体类(canConvert只返回对于B.class)为true,或者至少通过为基本接口而不是通用Object.class转换器(canConvertA.class.isAssignableFrom(theclass)返回true)转换器来限制损坏由您决定如何在文件中存储有关具体类的类的信息。