简体   繁体   English

JAXB使用@XmlJavaTypeAdapter封送Collection的子集

[英]JAXB using @XmlJavaTypeAdapter to marshal a subset of a Collection

I've got an entity which contains a collection of a different type of entities. 我有一个实体,其中包含不同类型的实体的集合。 What I want to do is have JAXB marshal only a select subset of the collection, based on some criteria. 我想要做的是根据某些条件让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;
    }

}

This results in errors saying "java.util.Collection is an interface, and JAXB can't handle interfaces" and that "java.util.Collection does not have a no-arg default constructor." 这将导致错误,指出“ java.util.Collection是一个接口,JAXB无法处理接口”,并且“ java.util.Collection没有无参数的默认构造函数”。

What am I doing wrong, and is this even the right way to go about it? 我在做什么错,这甚至是正确的解决方法吗?

The important thing is that you can't adapt a Collection (an interface) to something JAXB can handle, since it doesn't marshal an ArrayList or some other collection class . 重要的是,您不能使Collection(接口)适应JAXB可以处理的内容,因为它不会封送ArrayList或其他Collection类 It is designed to marshal (bean) classes containing fields that are Lists or similar, which is meant to "disappear", remaining as the mere repetition of its elements. 它旨在封送(豆类) 包含 List或类似字段的类,这意味着“消失”,仅保留其元素的重复 In other words, there's no XML element representing the ArrayList (or whatever) itself. 换句话说,没有XML元素表示ArrayList(或其他任何元素)本身。

Therefore, the adapter has to modify the containing element. 因此,适配器必须修改包含元素。 (See below for alternatives.) The following classes are working; (有关其他选择,请参见下文。)以下类正在运行; just assemble a Root element and modify the AFormatter according to your design. 只需组装一个Root元素并根据您的设计修改AFormatter。 (The comments refer to the example at https://jaxb.java.net/tutorial/section_6_2_9-Type-Adapters-XmlJavaTypeAdapter.html#Type%20Adapters:%20XmlJavaTypeAdapter .) (注释参考https://jaxb.java.net/tutorial/section_6_2_9-Type-Adapters-XmlJavaTypeAdapter.html#Type%20Adapters:%20XmlJavaTypeAdapter上的示例。)

(Most classes should be modified to avoid making fields public, but as it is, it is brief and working.) (应修改大多数类,以避免将字段公开,但实际上,它是简短且有效的。)

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

Alternatives: It would be quite simple if the regular getter of the B-list would return the ones that should be marshalled. 备选方案:如果B列表的常规获取者返回应编组的列表,那将非常简单。 If the application needs to see all, an alternative getter could be added. 如果应用程序需要全部查看,则可以添加替代的getter。 Or, the class could have a static flag that instructs the getter to return a List to be used for marshalling, or the regular list at other times. 或者,该类可以具有一个静态标志,该标志指示getter返回用于编组的List或其他时间的常规列表。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM