0

我有一个包含不同类型实体集合的实体。我想要做的是让 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;
    }

}

这会导致错误提示“java.util.Collection 是一个接口,而 JAXB 无法处理接口”以及“java.util.Collection 没有无参数默认构造函数”。

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

4

1 回答 1

2

重要的是您不能将 Collection(接口)改编为 JAXB 可以处理的东西,因为它不会编组 ArrayList 或其他一些集合类。它旨在编组(bean)包含列表或类似字段的类,这意味着“消失”,仅保留其元素的重复。换句话说,没有代表 ArrayList(或其他)本身的 XML 元素。

因此,适配器必须修改包含元素。(请参阅下面的替代方案。)以下课程正在工作;只需组装一个 Root 元素并根据您的设计修改 AFormatter。(评论参考 https://jaxb.java.net/tutorial/section_6_2_9-Type-Adapters-XmlJavaTypeAdapter.html#Type%20Adapters:%20XmlJavaTypeAdapter的示例。)

(应该修改大多数类以避免公开字段,但事实上,它是简短且有效的。)

@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>();
}

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

于 2014-07-24T14:45:09.723 回答