JAXB使用@XmlJavaTypeAdapter封送集合的子集

JAXB使用@XmlJavaTypeAdapter封送集合的子集,java,jaxb,xmladapter,Java,Jaxb,Xmladapter,我有一个实体,它包含一个不同类型实体的集合。我想做的是让JAXB根据一些标准仅封送集合的一部分 @XmlRootElement @Entity public class A{ // other fields @OneToMany(mappedBy = "x", fetch = FetchType.LAZY, cascade = CascadeType.ALL) private Collection<B> bees; @XmlJavaTypeAdap

我有一个实体,它包含一个不同类型实体的集合。我想做的是让JAXB根据一些标准仅封送集合的一部分

@XmlRootElement
@Entity
public class A{

    // other fields
    @OneToMany(mappedBy = "x", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    private Collection<B> bees;

    @XmlJavaTypeAdapter(BFormatter.class)
    public Collection<B> getBees() {
        return bees;
    }

    public void setBees(Collection<B> bees) {
        this.bees= bees;
    }
}


@XmlRootElement
@Entity
public class B{
    // fields
}

public class BFormatter extends XmlAdapter<Collection<B>, Collection<B>>{

    @Override
    public Collection<B> unmarshal(Collection<B> v) throws Exception {
        return v;
    }

    @Override
    public Collection<B> marshal(Collection<B> v) throws Exception {
        Collection<B> subset;
        // making subset
        return subset;
    }

}
@XmlRootElement
@实体
公共A类{
//其他领域
@OneToMany(mappedBy=“x”,fetch=FetchType.LAZY,cascade=CascadeType.ALL)
私人收集蜜蜂;
@XmlJavaTypeAdapter(BFormatter.class)
公众收集蜜蜂(){
返回蜜蜂;
}
公共空间受挫者(收集蜜蜂){
这个。蜜蜂=蜜蜂;
}
}
@XmlRootElement
@实体
公共B级{
//田地
}
公共类BFormatter扩展了XmlAdapter{
@凌驾
公共集合解组(集合v)引发异常{
返回v;
}
@凌驾
公共集合封送处理程序(集合v)引发异常{
集合子集;
//生成子集
返回子集;
}
}
这会导致错误,如“java.util.Collection是一个接口,JAXB无法处理接口”和“java.util.Collection没有无参数默认构造函数”


我做错了什么,这是正确的方法吗?

重要的是,您不能使集合(接口)适应JAXB可以处理的东西,因为它不会封送ArrayList或其他集合类。它被设计为封送(bean)类,其中包含列表或类似字段,这意味着“消失”,仅作为其元素的重复而保留。换句话说,没有XML元素表示ArrayList(或其他)本身

因此,适配器必须修改包含元素。(参见下面的备选方案。)以下类别正在运行;只需组装一个根元素,并根据您的设计修改上述格式。(注释参考第页的示例。) )

(大多数类都应该进行修改,以避免字段公开,但实际上,它很简单且有效。)

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
公共类根{//培训
@XmlElement
私人A;//小册子
公共根(){}
public A getA(){return A;}
公共无效集合A(A值){A=value;}
}
@XmlJavaTypeAdapter(一个format.class)
公共A类{///小册子
私人收集蜜蜂;
公共A(){
bees=新的ArrayList();
}
公众收集蜜蜂(){
如果(bees==null)bees=newarraylist();
返回蜜蜂;
}
}
@XmlAccessorType(XmlAccessType.FIELD)
公共B级{//课程
@XmlElement
私有字符串id;
公共B(){}
公共字符串getId(){return id;}
public void setId(字符串值){id=value;}
}
公共类格式扩展了XmlAdapter{
@凌驾
公共A解组(蜂巢v)引发异常{
A=新的A();
对于(B:v.beeList){
a、 添加(b);
}
返回a;
}
@凌驾
公共蜂箱封送员(AV)抛出异常{
蜂巢蜂巢=新蜂巢();
对于(B:v.getBees()){
如果(b.getId().startsWith(“a”))beeHive.beeList.add(b);
}                              
返回蜂巢;
}
}
公共类蜂巢{//Courses
@xmlement(name=“b”)
public List beeList=new ArrayList();
}

备选方案:如果B-list的常规getter将返回应该封送的getter,这将非常简单。如果应用程序需要查看所有内容,可以添加一个替代getter。或者,该类可以有一个静态标志,指示getter返回用于编组的列表,或者在其他时间返回常规列表。

谢谢您的回答。我尝试了你的建议,但现在得到的xml只是:如中所示,没有放入任何B实例。我不得不稍微回溯一下,摆脱了调整集合本身的想法。请参阅完全重写的答案。
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Root{ // Training
    @XmlElement
    private A a;  // Brochure
    public Root(){}
    public A getA(){ return a; }
    public void setA( A value ){ a = value; }
}

@XmlJavaTypeAdapter(AFormatter.class)
public class A{  // Brochure
    private Collection<B> bees;
    public A(){
        bees = new ArrayList<>();
    }
    public Collection<B> getBees() {
        if( bees == null ) bees = new ArrayList<>();
        return bees;
    }
}

@XmlAccessorType(XmlAccessType.FIELD)
public class B{  // Course
    @XmlElement
    private String id;
    public B(){}
    public String getId(){ return id; }
    public void setId( String value ){ id = value; }
}

public class AFormatter extends XmlAdapter<BeeHive, A>{
    @Override
    public A unmarshal(BeeHive v) throws Exception {
        A a = new A();
        for( B b: v.beeList ){
            a.getBees().add( b );
        }
        return a;
    }
    @Override
    public BeeHive marshal(A v) throws Exception {
    BeeHive beeHive = new BeeHive();
        for( B b: v.getBees() ){
             if( b.getId().startsWith("a") ) beeHive.beeList.add( b ); 
        }                              
        return beeHive;
    }
}

public class BeeHive { // Courses
    @XmlElement(name="b")
    public List<B> beeList = new ArrayList<B>();
}