簡體   English   中英

使用XStream解組XML時的異常

[英]Exception when unmarshalling XML with XStream

我已經為javafx.scene.shape.Path創建了一些Converter ,這基本上是一個Bèzier路徑。 為此,我將轉換類型為MoveToCubicCurveTo的路徑元素,為此我也有轉換器:

public class MoveToConverter implements Converter {
    @Override
    public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
        writer.startNode("move-to");
        MoveTo start = (MoveTo) source;
        writer.addAttribute("startX", String.valueOf(start.getX()));
        writer.addAttribute("startY", String.valueOf(start.getY()));
        writer.endNode();

    }

    @Override
    public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
        reader.moveDown();
        MoveTo moveTo = new MoveTo();
        moveTo.setX(Double.valueOf(reader.getAttribute("startX")));
        moveTo.setY(Double.valueOf(reader.getAttribute("startY")));
        reader.moveUp();
        return moveTo;
    }

    @Override
    public boolean canConvert(Class type) {
        return MoveTo.class.equals(type);
    }
}

public class CubicCurveToConverter implements Converter {
    @Override
    public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
        CubicCurveTo curveTo = (CubicCurveTo) source;
        writer.startNode("cubic-curve-to");
        writer.addAttribute("controlX1", String.valueOf(curveTo.getControlX1()));
        writer.addAttribute("controlY1", String.valueOf(curveTo.getControlY1()));
        writer.addAttribute("controlX2", String.valueOf(curveTo.getControlX2()));
        writer.addAttribute("controlY2", String.valueOf(curveTo.getControlY2()));
        writer.addAttribute("x", String.valueOf(curveTo.getX()));
        writer.addAttribute("y", String.valueOf(curveTo.getY()));
        writer.endNode();
    }

    @Override
    public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
        reader.moveDown();
        CubicCurveTo curveTo = new CubicCurveTo();
        curveTo.setX(Double.valueOf(reader.getAttribute("x")));
        curveTo.setY(Double.valueOf(reader.getAttribute("y")));
        curveTo.setControlX1(Double.valueOf(reader.getAttribute("controlX1")));
        curveTo.setControlY1(Double.valueOf(reader.getAttribute("controlY1")));
        curveTo.setControlX2(Double.valueOf(reader.getAttribute("controlX2")));
        curveTo.setControlY2(Double.valueOf(reader.getAttribute("controlY2")));
        reader.moveUp();
        return curveTo;
    }

    @Override
    public boolean canConvert(Class type) {
        return CubicCurveTo.class.equals(type);
    }
}

public class PathConverter implements Converter {
    @Override
    public void marshal(Object o, HierarchicalStreamWriter writer, MarshallingContext marshallingContext) {
        Path path = (Path) o;

        List<PathElement> elements = path.getElements();
        writer.startNode("bezier-path");
        writer.addAttribute("count", String.valueOf(elements.size()));
        MoveTo start = (MoveTo) elements.get(0);
        marshallingContext.convertAnother(start);
        // serialize start
        for (int i = 1; i < elements.size(); i++) {
            CubicCurveTo curveTo = (CubicCurveTo) elements.get(i);
            marshallingContext.convertAnother(curveTo);
        }

        writer.endNode();
    }

    @Override
    public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
        reader.moveDown();
        Path path = new Path();
        path.setStrokeWidth(2);
        path.setStroke(Color.RED);
        int nbElements = Integer.parseInt(reader.getAttribute("count"));
        MoveTo moveTo = (MoveTo) context.convertAnother(path, MoveTo.class);

        path.getElements().add(moveTo);
        for (int i = 1; i < nbElements; i++) {
            CubicCurveTo curveTo = (CubicCurveTo) context.convertAnother(path, CubicCurveTo.class);
            path.getElements().add(curveTo);
            System.out.println("Added curve to: "+curveTo);
        }
        reader.moveUp();
        return path;
    }

    @Override
    public boolean canConvert(Class aClass) {
        return Path.class.equals(aClass);
    }
}

我有這個測試代碼:

Path path = new Path();
path.getElements().add(new MoveTo(2, 1));
path.getElements().add(new CubicCurveTo(1, 2, 3, 4, 5, 6));
path.getElements().add(new CubicCurveTo(11, 12, 13, 14, 15, 16));
path.getElements().add(new CubicCurveTo(21, 22, 23, 24, 25, 26));
path.getElements().add(new CubicCurveTo(31, 32, 33, 34, 35, 36));
path.getElements().add(new CubicCurveTo(41, 42, 43, 44, 45, 46));
XStream xStream = new XStream();
xStream.registerConverter(converter);
xStream.registerConverter(new MoveToConverter());
xStream.registerConverter(new CubicCurveToConverter());
File f = File.createTempFile(getClass().getName(), ".xml");
OutputStream os = new FileOutputStream(f);

xStream.toXML(path, os);
Object result = xStream.fromXML(f);

assertEquals(path.toString(), result.toString());
f.delete();

mashalling路徑時創建的文件如下所示,這是我基本上想要的:

<javafx.scene.shape.Path>
  <bezier-path count="6">
    <move-to startX="2.0" startY="1.0"/>
    <cubic-curve-to controlX1="1.0" controlY1="2.0" controlX2="3.0" controlY2="4.0" x="5.0" y="6.0"/>
    <cubic-curve-to controlX1="11.0" controlY1="12.0" controlX2="13.0" controlY2="14.0" x="15.0" y="16.0"/>
    <cubic-curve-to controlX1="21.0" controlY1="22.0" controlX2="23.0" controlY2="24.0" x="25.0" y="26.0"/>
    <cubic-curve-to controlX1="31.0" controlY1="32.0" controlX2="33.0" controlY2="34.0" x="35.0" y="36.0"/>
    <cubic-curve-to controlX1="41.0" controlY1="42.0" controlX2="43.0" controlY2="44.0" x="45.0" y="46.0"/>
  </bezier-path>
</javafx.scene.shape.Path>

但是,在解組XML時遇到了以下異常:

com.thoughtworks.xstream.converters.ConversionException: only START_TAG can have attributes END_TAG seen ...<bezier-path count="6">\n    <move-to startX="2.0" startY="1.0"/>... @3:41 : only START_TAG can have attributes END_TAG seen ...<bezier-path count="6">\n    <move-to startX="2.0" startY="1.0"/>... @3:41
---- Debugging information ----
message             : only START_TAG can have attributes END_TAG seen ...<bezier-path count="6">\n    <move-to startX="2.0" startY="1.0"/>... @3:41
cause-exception     : java.lang.IndexOutOfBoundsException
cause-message       : only START_TAG can have attributes END_TAG seen ...<bezier-path count="6">\n    <move-to startX="2.0" startY="1.0"/>... @3:41
class               : javafx.scene.shape.Path
required-type       : javafx.scene.shape.Path
converter-type      : ch.sahits.game.openpatrician.persistence.converter.PathConverter
path                : /javafx.scene.shape.Path/bezier-path
line number         : 3
version             : 1.4.8
-------------------------------

    at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:79)
    at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:65)
    at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66)
    at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:50)
    at com.thoughtworks.xstream.core.TreeUnmarshaller.start(TreeUnmarshaller.java:134)
    at com.thoughtworks.xstream.core.AbstractTreeMarshallingStrategy.unmarshal(AbstractTreeMarshallingStrategy.java:32)
    at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1206)
    at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1190)
    at com.thoughtworks.xstream.XStream.fromXML(XStream.java:1154)
    at com.thoughtworks.xstream.XStream.fromXML(XStream.java:1096)
    at ch.sahits.game.openpatrician.persistence.converter.PathConverterTest.shouldConvertObjectToXMLAndBack(PathConverterTest.java:49)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
Caused by: java.lang.IndexOutOfBoundsException: only START_TAG can have attributes END_TAG seen ...<bezier-path count="6">\n    <move-to startX="2.0" startY="1.0"/>... @3:41
    at org.xmlpull.mxp1.MXParser.getAttributeValue(MXParser.java:927)
    at com.thoughtworks.xstream.io.xml.XppReader.getAttribute(XppReader.java:139)
    at com.thoughtworks.xstream.io.ReaderWrapper.getAttribute(ReaderWrapper.java:52)
    at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:53)
    at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66)
    at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:50)
    at ch.sahits.game.openpatrician.persistence.converter.PathConverter.unmarshal(PathConverter.java:52)
    at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72)
    ... 36 more

PathConverter中的第52行指向此行(for循環中的第一個調用):

CubicCurveTo curveTo = (CubicCurveTo) context.convertAnother(path, CubicCurveTo.class);

我的猜測是,問題與unmarshal方法上的moveDownmoveUp方法有關,因此讀者仍然處於期望move-to結束節點的狀態。 對於其他兩個轉換器,我也進行了測試,它們運行良好,因此問題似乎出在組合和對context.convertAnother的調用上。

我想知道我在創建轉換器時的想法哪里出了問題以及如何解決。

您正在流上操作。 如果下一步沒有讀取標簽的值。 可能導致錯誤

嘗試:

reader.moveDown();
Path path = new Path();
path.setStrokeWidth(2);
path.setStroke(Color.RED);
int nbElements = Integer.parseInt(reader.getAttribute("count"));
MoveTo moveTo = (MoveTo) context.convertAnother(path, MoveTo.class);

path.getElements().add(moveTo);
reader.moveUp();
for (int i = 1; i < nbElements; i++) {
     reader.moveDown();
    CubicCurveTo curveTo = (CubicCurveTo) context.convertAnother(path, CubicCurveTo.class);
    path.getElements().add(curveTo);
    System.out.println("Added curve to: "+curveTo);
     reader.moveUp();
}
return path;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM