2013-07-03 5 views
1

속성 값에 따라 JAXB 빈을 서브 클래스로 언 마샬하고 싶습니다.JAXB 상속 - 어노테이션에서 선언 된 서브 타입에 대한 언 마샬링?

목시는 작업을 수행 할 수 있습니다

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

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

는 그러나, JAXBContext가 지정된 모든 클래스를 필요로한다. "루트"클래스가 아닌 다른 클래스를 정의하는 것은 불쾌한 일입니다. 내가 좋아하는 뭔가를 기대했다

: 나는 XmlAdapter의에 들어갈 싶지 않아

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

,이 사소한 작업이며 사소한 해결책이 있어야합니다.

스펙 또는 MOXy 확장 프로그램이 있습니까? 루트 클래스에 서브 클래스를 나열하는 데 사용할 수 있습니까?

그렇지 않으면 Jandex를 사용하여 자동으로 하위 클래스를 찾습니다. Afterall는, MOXY 너무 ;-)


업데이트를 그렇게 할 수 있습니다 : 한마디로 Exception : "Missing class indicator field from database row [UnmarshalRecordImpl()]." when unmarshalling XML using EclipseLink JAXB (MOXy)

: 기록을 위해, 나는 여기에 설명되어

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

을 얻고 있었다하지 마십시오 @XmlDiscriminatorNode("@name")에있는 이름과 동일한 이름의 속성으로 MOXy를 비 정렬 화하십시오. 그렇다면 @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; 
} 

문제점은 무엇입니까?

이 업데이트 :

최상위 클래스 ContainerOfStackableDefs에 @XmlDiscriminatorNode ("@ 유형을") 퍼팅 후, 내가 얻을 :

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가 없습니다. : 해결할 수 있습니까?


또한, 나는 간단한 테스트 케이스 생성 :

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 {} 

} 

을하지만 나를 Base 2 배이 또한 제공합니다. 디버거에서 확인한 MOXy에서 처리합니다.
여기에 무슨 문제가 있습니까?

답변

3

@XmlSeeAlso (javax.xml.bind.annotation) 주석을 사용할 수 있습니다.

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

UPDATE

당신이보고있는 문제 최신 당신의 상속 계층 구조의 루트 클래스에 배치되고하지 @XmlDescriminatorNode에 의해 발생 업데이트되었습니다. @XmlTransient을 사용하여 상속 계층 구조에서 ContainerOfStackableDefs을 제거했을 때 모든 것이 잘 작동했습니다 (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> 
+0

나는 완전히, 덕분에이 간과! –

+0

@ OndraŽižka - 문제 없습니다. '@ XmlSeeAlso'는 바로이 문제를 해결하기 위해 JAXB 2.1에서 소개되었습니다. –

+0

BTW, Jandex 솔루션을 추가하는 것을 고려해보십시오. 사전에 하위 클래스를 미리 모르는 경우가 있습니까? 예 : 플러그인 등. –

관련 문제