我有一个实体,其中包含不同类型实体的集合。我想要做的是让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没有no-arg默认构造函数。”
我做错了什么,这是否是正确的方法呢?
答案 0 :(得分:2)
重要的是,您无法使Collection(接口)适应JAXB可以处理的内容,因为它不会封送ArrayList或其他集合类。它被设计为编组(bean)类包含列表或类似的字段,这意味着&#34;消失&#34;,仍然只是重复的它的元素。换句话说,没有表示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返回一个List用于编组,或者在其他时间返回常规列表。