如何使用 JAXB 使用不同的标签 marshal/unmarshal 抽象 class

How to marshal/unmarshal abstract class with a different tags using JAXB

<root-object>
    <synchronous>
        <command>C:\hello_world.exe</command>
        <argument>aaaa</argument>
        <argument>bbbb</argument>
    </synchronous>
    <asynchronous>
        <command>C:\hello_world.exe</command>
        <argument>aaaa</argument>
        <argument>bbbb</argument>
    </asynchronous>
    <synchronous>
        <command>C:\hello_world.exe</command>
        <argument>aaaa</argument>
        <argument>bbbb</argument>
    </synchronous>
</root-object>

在这种 XML 格式中,我想通过 JAXB unmarshal/marshal 同步和异步对象到一个列表中。

我写了下面的代码,但是items里面什么都没有输入

我怎样才能使这个结构成为可能?

@XmlRootElement(name = "root-object")
@XmlAccessorType(XmlAccessType.FIELD)
@lombok.ToString
public class RootObject {
    @XmlElement(type = CommandItem.class)
    private List<CommandItem> items= new ArrayList<>();

    public RootObject() {}

    @lombok.Getter
    @lombok.Setter
    @lombok.NoArgsConstructor
    @XmlType
    @XmlSeeAlso({AsyncCommandItem.class, SyncCommandItem.class})
    @XmlAccessorType(XmlAccessType.FIELD)
    public static class CommandItem {
        @XmlElement(name = "command")
        private String command;
        @XmlElement(name = "argument")
        private List<String> argument;
    }

    @lombok.NoArgsConstructor
    @XmlRootElement(name = "synchronous")
    public static class SyncCommandItem extends CommandItem {

    }

    @lombok.NoArgsConstructor
    @XmlRootElement(name = "asynchronous")
    public static class AsyncCommandItem extends CommandItem {

    }
}

我为您提供的 XML 使用了以下代码,它似乎对我来说工作正常。您需要稍微修改 POJO 才能使其正常工作。

RootObject.class:

@XmlRootElement(name = "root-object")
@Data
@XmlAccessorType(XmlAccessType.FIELD)
public class RootObject     {
    @XmlElement(name = "synchronous")
    private List<Synchronous> synchronous;

    @XmlElement(name = "asynchronous")
    private List<Asynchronous> asynchronous;
}

Synchronous.class:

@Data
@XmlAccessorType(XmlAccessType.NONE)
public class Synchronous {
    @XmlElement(name = "command")
    private String command;

    @XmlElement(name = "argument")
    private List<String> argument;
}

Asynchronous.class:

@Data
@XmlAccessorType(XmlAccessType.NONE)
public class Asynchronous {
    @XmlElement(name = "command")
    private String command;

    @XmlElement(name = "argument")
    private List<String> argument;
}

Main.class:

public class Main {
    public static void main(String[] args) throws JAXBException, XMLStreamException {
        final InputStream inputStream = Unmarshalling.class.getClassLoader().getResourceAsStream("synchronous.xml");
        final XMLStreamReader xmlStreamReader = XMLInputFactory.newInstance().createXMLStreamReader(inputStream);
        final Unmarshaller unmarshaller = JAXBContext.newInstance(RootObject.class).createUnmarshaller();
        final RootObject rootObject = unmarshaller.unmarshal(xmlStreamReader, RootObject.class).getValue();
        System.out.println(rootObject.toString());

        Marshaller marshaller = JAXBContext.newInstance(RootObject.class).createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
        marshaller.marshal(rootObject, System.out);
    }
}

输出如下:

RootObject(synchronous=[Synchronous(command=C:\hello_world.exe, argument=[aaaa, bbbb]), Synchronous(command=C:\hello_world.exe, argument=[aaaa, bbbb])], asynchronous=[Asynchronous(command=C:\hello_world.exe, argument=[aaaa, bbbb])])
<root-object>
   <synchronous>
      <command>C:\hello_world.exe</command>
      <argument>aaaa</argument>
      <argument>bbbb</argument>
   </synchronous>
   <synchronous>
      <command>C:\hello_world.exe</command>
      <argument>aaaa</argument>
      <argument>bbbb</argument>
   </synchronous>
   <asynchronous>
      <command>C:\hello_world.exe</command>
      <argument>aaaa</argument>
      <argument>bbbb</argument>
   </asynchronous>
</root-object>

我通过@XmlElements解决了。

@XmlRootElement(name = "root-object")
@XmlAccessorType(XmlAccessType.FIELD)
@lombok.ToString
public class RootObject {
    @XmlElements({
        @XmlElement(name = "synchronous", type = SyncCommandItem.class),
        @XmlElement(name = "asynchronous", type = AsyncCommandItem .class),
    })
    private List<CommandItem> items= new ArrayList<>();

    public RootObject() {}

    @lombok.Getter
    @lombok.Setter
    @lombok.NoArgsConstructor
    @XmlType
    @XmlSeeAlso({AsyncCommandItem.class, SyncCommandItem.class})
    @XmlAccessorType(XmlAccessType.FIELD)
    public static class CommandItem {
        @XmlElement(name = "command")
        private String command;
        @XmlElement(name = "argument")
        private List<String> argument;
    }

    @lombok.NoArgsConstructor
    @XmlRootElement(name = "synchronous")
    public static class SyncCommandItem extends CommandItem {

    }

    @lombok.NoArgsConstructor
    @XmlRootElement(name = "asynchronous")
    public static class AsyncCommandItem extends CommandItem {

    }
}