Java SomeObject是一个接口,JAXB可以';t处理接口

Java SomeObject是一个接口,JAXB可以';t处理接口,java,jaxb,Java,Jaxb,在我的应用程序中有一个对象树。要构成该树,每个对象都有一个父引用。由于某些对象类型可以是多个父对象类型的子对象,所有潜在的父对象类型都通过实现公共接口来统一。 我尽可能地缩小了问题的范围(JAXB抱怨父成员变量(注释为@XmlIDREF和@xmldattribute)是一个接口): public interface Parent{ @XmlID @XmlAttribute( name = "oid" ) public String getID(); public

在我的应用程序中有一个对象树。要构成该树,每个对象都有一个父引用。由于某些对象类型可以是多个父对象类型的子对象,所有潜在的父对象类型都通过实现公共接口来统一。 我尽可能地缩小了问题的范围(JAXB抱怨父成员变量(注释为@XmlIDREF和@xmldattribute)是一个接口):

public interface Parent{
    @XmlID
    @XmlAttribute( name = "oid" )
    public String getID();
    public void setID( String id );
}

@XmlRootElement
@XmlAccessorType( XmlAccessType.NONE )
public class ChildObject implements Parent{
    @XmlTransient
    private UUID id = UUID.randomUUID();

    @XmlIDREF
    @XmlAttribute
    protected Parent parent = null;

    public ChildObject() {}

    public ChildObject( Parent parent ){
        this.parent = parent;
    }

    @XmlID
    @XmlAttribute
    @Override
    public String getID(){ return( id.toString() ); }

    @Override
    public void setID( String id ){ this.id = UUID.fromString( id ); }
}

@XmlRootElement
@XmlAccessorType( XmlAccessType.NONE )
public class Repository{

    @XmlElement
    private List<ChildObject> objects = new ArrayList<>();

    public Repository() {}

    public ChildObject addObject( ChildObject o ){
        objects.add( o );
        return( o );
    }

    public static void main( String[] args ){
        Repository r = new Repository();
        ChildObject root = r.addObject( new ChildObject() );
        ChildObject c0 = r.addObject( new ChildObject( root ) );
        ChildObject c1 = r.addObject( new ChildObject( root ) );
        ChildObject c11 = r.addObject( new ChildObject( c1 ) );
        ChildObject c12 = r.addObject( new ChildObject( c1 ) );
        try{ 
            JAXBContext context = JAXBContext.newInstance( Repository.class );
            Marshaller marshaller = context.createMarshaller();
            marshaller.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT, true );
            marshaller.marshal( r, System.out );
        }catch( Exception ex ){ ex.printStackTrace(); }
    }
}
公共接口父级{
@XmlID
@XmlAttribute(name=“oid”)
公共字符串getID();
公共void setID(字符串id);
}
@XmlRootElement
@XmlAccessorType(XmlAccessType.NONE)
公共类ChildObject实现父对象{
@XmlTransient
私有UUID id=UUID.randomUUID();
@XmlIDREF
@XmlAttribute
受保护的父项=null;
公共子对象(){}
公共子对象(父对象){
this.parent=parent;
}
@XmlID
@XmlAttribute
@凌驾
公共字符串getID(){return(id.toString());}
@凌驾
public void setID(String id){this.id=UUID.fromString(id);}
}
@XmlRootElement
@XmlAccessorType(XmlAccessType.NONE)
公共类存储库{
@XmlElement
私有列表对象=新的ArrayList();
公共存储库(){}
公共ChildObject addObject(ChildObject o){
添加(o);
返回(o);
}
公共静态void main(字符串[]args){
Repository r=新存储库();
ChildObject root=r.addObject(new ChildObject());
ChildObject c0=r.addObject(新的ChildObject(根));
ChildObject c1=r.addObject(新的ChildObject(根));
ChildObject c11=r.addObject(新的ChildObject(c1));
ChildObject c12=r.addObject(新的ChildObject(c1));
试试{
JAXBContext context=JAXBContext.newInstance(Repository.class);
Marshaller=context.createMarshaller();
setProperty(marshaller.JAXB_格式化的_输出,true);
marshaller.marshall(r,System.out);
}catch(异常ex){ex.printStackTrace();}
}
}
这是我在尝试运行时遇到的异常:

com.sun.xml.internal.bind.v2.runtime.illegalannotations异常:1 IllegalAnnotationExceptions的计数父级是一个接口,而JAXB 无法处理接口。此问题与以下方面有关 位置:在受保护的父对象处的父对象处。父对象处 位于私有java.util.List Repository.objects的ChildObject 存储库

在 com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException$Builder.check(IllegalAnnotationsException.java:91) 在 com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.getTypeInfoSet(JAXBContextImpl.java:445) 在 com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.(JAXBContextImpl.java:277) 在 com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.(JAXBContextImpl.java:124) 在 com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl$JAXBContextBuilder.build(JAXBContextImpl.java:1123) 在 com.sun.xml.internal.bind.v2.ContextFactory.createContext(ContextFactory.java:147) 位于的sun.reflect.NativeMethodAccessorImpl.invoke0(本机方法) invoke(NativeMethodAccessorImpl.java:62) 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 位于java.lang.reflect.Method.invoke(Method.java:498) javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:247)位于 javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:234)位于 javax.xml.bind.ContextFinder.find(ContextFinder.java:462)位于 javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:641)位于 javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:584)位于 main(Repository.java:33)


这是JAXB的预期行为(还是一个bug),我应该怎么做才能避免它?

我通过向接口添加一个虚拟的
@XmlJavaTypeAdapter
解决了这个问题,如下所示:

@XmlAccessorType( XmlAccessType.NONE )
@XmlJavaTypeAdapter(ChildObject.ParentAdapter.class)
public interface Parent{
    @XmlID
    @XmlAttribute( name = "oid" )
    public abstract String getID();
    public abstract void setID( String id );
}

@XmlRootElement
@XmlAccessorType( XmlAccessType.NONE )
public class ChildObject implements Parent{

    @XmlTransient
    private UUID id = UUID.randomUUID();

    @XmlIDREF
    @XmlAttribute
    protected Parent parent = null;

    public ChildObject() {}

    public ChildObject( Parent parent ){
        this.parent = parent;
    }

    @XmlID
    @XmlAttribute( name = "oid" )
    @Override
    public String getID(){ return( id.toString() ); }

    @Override
    public void setID( String id ){ this.id = UUID.fromString( id ); }


    public static class ParentAdapter extends XmlAdapter<Object,Object>{
        @Override
        public Object marshal( Object arg0 ) throws Exception{ return arg0; }

        @Override
        public Object unmarshal( Object arg0 ) throws Exception{ return arg0; }
    }
}
@xmlacessortype(xmlacesstype.NONE)
@XmlJavaTypeAdapter(ChildObject.ParentAdapter.class)
公共接口父级{
@XmlID
@XmlAttribute(name=“oid”)
公共抽象字符串getID();
公共抽象void setID(字符串id);
}
@XmlRootElement
@XmlAccessorType(XmlAccessType.NONE)
公共类ChildObject实现父对象{
@XmlTransient
私有UUID id=UUID.randomUUID();
@XmlIDREF
@XmlAttribute
受保护的父项=null;
公共子对象(){}
公共子对象(父对象){
this.parent=parent;
}
@XmlID
@XmlAttribute(name=“oid”)
@凌驾
公共字符串getID(){return(id.toString());}
@凌驾
public void setID(String id){this.id=UUID.fromString(id);}
公共静态类ParentAdapter扩展了XmlAdapter{
@凌驾
公共对象封送处理程序(对象arg0)引发异常{return arg0;}
@凌驾
公共对象解组(对象arg0)引发异常{return arg0;}
}
}

不过,我不确定这是一个bug还是JAXB(OracleJDK8U121)的预期行为用
@XmlTransient
注释接口也能起作用。不需要空的
XmlAdapter