3

属性値に基づいて、JAXB Bean をサブクラスにアンマーシャリングしたいと考えています。

MOXyはそれを行うことができます:

@XmlDiscriminatorNode("@type")
public static class ActionDef extends ContainerOfStackableDefs { ... }

@XmlDiscriminatorValue("cli")
public static class CliActionDef extends ActionDef {
    /** CLI command. EL. */
    @XmlAttribute public String command;
}

ただし、 にはJAXBContext指定されたすべてのクラスが必要です。「ルート」クラス以外の場所で定義するのはちょっと不快です。

私は次のようなことを望んでいました:

@XmlDiscriminatorNode("@type")
@XmlSubClasses({ CliActionDef.class, XsltActionDef.class, ... })
public static class ActionDef extends ContainerOfStackableDefs { ... }

私は s に入りたくありませんXmlAdapter。これは簡単な作業であり、簡単な解決策が必要です。

仕様またはMOXy拡張のいずれかで、ルートクラスのサブクラスを単純にリストするために使用できるものはありますか?

それ以外の場合は、Jandex を使用してサブクラスを自動的に見つけようとしています。結局、MOXyもそれを行うことができました;-)


更新:記録のために、私は得ていました

Descriptor: XMLDescriptor(org.jboss.loom.migrators._ext.MigratorDefinition$ActionDef --> [])
at org.eclipse.persistence.exceptions.DescriptorException.missingClassIndicatorField(DescriptorException.java:957)
    ...

ここで説明されている:例外:「データベース行 [UnmarshalRecordImpl()] からクラス インジケーター フィールドが見つかりません。」EclipseLink JAXB (MOXy)を使用してXMLをアンマーシャリングする場合

要するに: の名前と同じ名前のプロパティへの MOXy アンマーシャリングを行わないでください@XmlDiscriminatorNode("@name")。もしそうなら、それを持って@XmlReadOnlyいて、クラスの抽象を持っていません。


更新:まだうまくいきません。私は基本クラスを取得し続けます。JDK の impl ではなく、MOXy によって処理されます。

私のコード:

    <action type="xslt" var="addAction" ...>
    </action>

    <action type="manual">
        ...
    </action>

豆:

//@XmlRootElement
@XmlDiscriminatorNode("@type")
@XmlSeeAlso({ CliActionDef.class, ModuleActionDef.class, CopyActionDef.class, XsltActionDef.class })
public static class ActionDef extends ContainerOfStackableDefs {
    //@XmlAttribute
    //@XmlReadOnly
    public String typeVal; // Was type, caused an exception.

    //public List<PropertyBean> properties;
    //@XmlAnyAttribute
    public Map<String, String> attribs = new HashMap();
}

@XmlRootElement
@XmlDiscriminatorValue("manual")
public static class ManualActionDef extends ActionDef {
}

public static class FileBasedActionDef extends ActionDef {
    /** Path mask. Ant-like wildcards, EL. */
    @XmlAttribute public String pathMask;

    /** Where to store the result. May be a dir or a file. EL. */
    @XmlAttribute public String dest;
}

@XmlRootElement
@XmlDiscriminatorValue("xslt")
public static class XsltActionDef extends FileBasedActionDef {
    /** XSLT template path. */
    @XmlAttribute public String xslt;
}

どうしたの?

アップデート:

@XmlDiscriminatorNode("@type") を最上位の classContainerOfStackableDefsに配置すると、次のようになります。

Exception Description: Missing class for indicator field value [manual] of type [class java.lang.String].
Descriptor: XMLDescriptor(org.jboss.loom.migrators._ext.MigratorDefinition$ActionDef --> [])
at org.eclipse.persistence.exceptions.DescriptorException.missingClassForIndicatorFieldValue(DescriptorException.java:938)
at org.eclipse.persistence.internal.oxm.QNameInheritancePolicy.classFromRow(QNameInheritancePolicy.java:264)

要するに:欠落してjava.lang.Stringいます。:-o 解ける?


また、最も単純なテスト ケースを作成しました。

public class JaxbInheritanceTest {    
    @Test
    public void testUnmarshall() throws JAXBException{
        final Unmarshaller marshaller = XmlUtils.createJaxbContext(Root.class).createUnmarshaller();
        Root root = (Root) marshaller.unmarshal( new StringReader(
                "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<root><sub disc=\"foo\"/><sub disc=\"bar\"/></root>") );

        boolean rightClass = (DiscFoo.class.isAssignableFrom( root.subs.get(0).getClass() ));
        Assert.assertTrue( "base elements go into subclasses", rightClass );

        rightClass = (DiscBar.class.isAssignableFrom( root.subs.get(1).getClass() ));
        Assert.assertTrue( "base elements go into subclasses", rightClass );
    }

    @XmlRootElement
    public static class Root {
        @XmlElement(name = "sub")
        List<Base> subs;
    }

    @XmlDiscriminatorNode("@disc")
    @XmlSeeAlso({DiscFoo.class, DiscBar.class})
    public static abstract class Base {}

    @XmlRootElement @XmlDiscriminatorValue("foo")
    public static class DiscFoo {}

    @XmlRootElement @XmlDiscriminatorValue("bar")
    public static class DiscBar {}

}

しかし、これも私に 2x を与えますBase。これは MOXy によって処理されます - デバッガーでチェックされます。
ここで何が問題なのですか?

4

1 に答える 1

4

@XmlSeeAlsoこれには(javax.xml.bind.annotation) アノテーションを使用できます。

@XmlDiscriminatorNode("@type")
@XmlSeeAlso({ CliActionDef.class, XsltActionDef.class, ... })
public static class ActionDef extends ContainerOfStackableDefs { ... }

アップデート

最新のアップデートで見られる問題は@XmlDescriminatorNode、継承階層のルート クラスに配置されていないことが原因です。ContainerOfStackableDefsすべてを使用して継承階層から削除すると、正常に機能し@XmlTransientました ( http://blog.bdoughan.com/2011/06/ignoring-inheritance-with-xmltransient.htmlを参照)。

デモ

import java.io.File;
import java.util.*;
import javax.xml.bind.*;
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.*;

public class Demo {

    @XmlTransient
    public static class ContainerOfStackableDefs {
    }

    @XmlDiscriminatorNode("@type")
    @XmlSeeAlso({ ManualActionDef.class, FileBasedActionDef.class, XsltActionDef.class })
    public static class ActionDef extends ContainerOfStackableDefs {
        //@XmlAttribute
        //@XmlReadOnly
        public String typeVal; // Was type, caused an exception.

        //public List<PropertyBean> properties;
        //@XmlAnyAttribute
        public Map<String, String> attribs = new HashMap();
    }

    @XmlDiscriminatorValue("manual")
    public static class ManualActionDef extends ActionDef {
    }

    @XmlDiscriminatorValue("fileBased")
    public static class FileBasedActionDef extends ActionDef {
        /** Path mask. Ant-like wildcards, EL. */
        @XmlAttribute public String pathMask;

        /** Where to store the result. May be a dir or a file. EL. */
        @XmlAttribute public String dest;
    }

    @XmlDiscriminatorValue("xslt")
    public static class XsltActionDef extends FileBasedActionDef {
        /** XSLT template path. */
        @XmlAttribute public String xslt;
    }

    @XmlRootElement
    public static class Root {

        @XmlElement(name="actionDef")
        public List<ActionDef> actionDefs;

    }

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Root.class);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        File xml = new File("src/forum17453793/input.xml");
        Root root = (Root) unmarshaller.unmarshal(xml);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(root, System.out);
    }

}

input.xml/出力

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <actionDef type="manual"/>
   <actionDef pathMask="PATH MASK" dest="DEST" type="fileBased"/>
   <actionDef xslt="XSLT" type="xslt"/>
</root>
于 2013-07-03T16:52:44.643 に答える