JAXB - 复合模式和@XmlValue

时间:2014-11-03 12:15:47

标签: java xml jaxb

跟进JAXB and Composite Pattern,我设法映射:

<precondition>
    <or>
        <and>
            <just><query>foo</query></just>
            <just><query>bar</query></just>
        </and>
        <just><query>baz</query></just>
    </or>
</precondition>

但我想映射:

<precondition>
    <or>
        <and>
            <query>foo</query>
            <query>bar</query>
        </and>
        <query>baz</query>
    </or>
</precondition>

我的JAXB类层次结构如下:

@XmlRootElement
@XmlSeeAlso({SimplePreconditionQuery.class, CompoundAndPreconditionQuery.class, CompoundOrPreconditionQuery.class})
public abstract class PreconditionQuery {
    // JAXB does not deal with interfaces by default >:(
}

有几种查询:

@XmlSeeAlso(PreconditionQuery.class)
@XmlRootElement(name = "just")
public class SimplePreconditionQuery extends PreconditionQuery {

    private String query;

    @XmlElement(name = "query")
    public String getQuery() {
        return query;
    }

    public void setQuery(String query) {
        this.query = query;
    }
}

化合物(AND / OR)非常相似:

@XmlSeeAlso(PreconditionQuery.class)
@XmlRootElement(name = "and")
public class CompoundAndPreconditionQuery extends PreconditionQuery {

    private Collection<PreconditionQuery> preconditionQueries = newArrayList();

    @XmlElementRef(name = "query")
    public Collection<PreconditionQuery> getPreconditionQueries() {
        return preconditionQueries;
    }

    public void setPreconditionQueries(Collection<PreconditionQuery> preconditionQueries) {
        this.preconditionQueries = preconditionQueries;
    }
}

封闭的豆子:

public class Precondition {

    private PreconditionQuery query;

    @XmlElementRef(required = true)
    public PreconditionQuery getQuery() {
        return query;
    }

    public void setQuery(PreconditionQuery query) {
        this.query = query;
    }
}

JAXB不允许我在@XmlValue上映射SimplePreconditionQuery。为什么和有什么替代方案?

1 个答案:

答案 0 :(得分:4)

问题

如果您只是这样做:

import javax.xml.bind.annotation.*;

@XmlRootElement(name = "query")
public class SimplePreconditionQuery extends PreconditionQuery {

    private String query;

    @XmlValue
    public String getQuery() {
        return query;
    }

    public void setQuery(String query) {
        this.query = query;
    }

}

您将收到以下异常,因为SimplePreconditionQueryjava.lang.Object以外的其他内容。

Exception in thread "main" com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
@XmlValue is not allowed on a class that derives another class.
    this problem is related to the following location:
        at public java.lang.String forum26714143.SimplePreconditionQuery.getQuery()
        at forum26714143.SimplePreconditionQuery
        at @javax.xml.bind.annotation.XmlSeeAlso(value=[class forum26714143.SimplePreconditionQuery, class forum26714143.CompoundAndPreconditionQuery, class forum26714143.CompoundOrPreconditionQuery])
        at public forum26714143.PreconditionQuery forum26714143.Precondition.getQuery()
        at forum26714143.Precondition

从继承层次结构中删除PreconditionQuery

我们可以在类级别使用@XmlTransient注释从JAXB中删除该类。超类中的所有属性都将被视为超类的属性。

import javax.xml.bind.annotation.*;

@XmlSeeAlso({SimplePreconditionQuery.class, CompoundAndPreconditionQuery.class, CompoundOrPreconditionQuery.class})
@XmlTransient
public abstract class PreconditionQuery {
    // JAXB does not deal with interfaces by default >:(
}

现在我们得到以下异常:

Exception in thread "main" com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 3 counts of IllegalAnnotationExceptions
Invalid @XmlElementRef : Type "class forum26714143.PreconditionQuery" or any of its subclasses are not known to this context.
    this problem is related to the following location:
        at public forum26714143.PreconditionQuery forum26714143.Precondition.getQuery()
        at forum26714143.Precondition

让JAXB意识到子类

现在我们已经从JAXB所关注的类集中删除了PreconditionQuery,现在我们可以从它包含的@XmlSeeAlso注释中获益。因此,我们需要使@XmlElementRef注释更明确:

<强>前提条件

import javax.xml.bind.annotation.*;

@XmlRootElement
public class Precondition {

    private PreconditionQuery query;

    @XmlElementRefs({
        @XmlElementRef(name="and", type = CompoundAndPreconditionQuery.class),
        @XmlElementRef(name="or", type= CompoundOrPreconditionQuery.class),
        @XmlElementRef(name="query", type=SimplePreconditionQuery.class)
    })
    public PreconditionQuery getQuery() {
        return query;
    }

    public void setQuery(PreconditionQuery query) {
        this.query = query;
    }

}

<强> CompoundAndPreconditionQuery

您还需要为CompoundAndPreconditionQueryCompoundAndPreconditionQuery执行此操作。

import java.util.*;
import javax.xml.bind.annotation.*;

@XmlRootElement(name = "and")
public class CompoundAndPreconditionQuery extends PreconditionQuery {

    private Collection<PreconditionQuery> preconditionQueries = new ArrayList();

    @XmlElementRefs({
            @XmlElementRef(name="and", type = CompoundAndPreconditionQuery.class),
            @XmlElementRef(name="or", type= CompoundOrPreconditionQuery.class),
            @XmlElementRef(name="query", type=SimplePreconditionQuery.class)
    })
    public Collection<PreconditionQuery> getPreconditionQueries() {
        return preconditionQueries;
    }

    public void setPreconditionQueries(Collection<PreconditionQuery> preconditionQueries) {
        this.preconditionQueries = preconditionQueries;
    }

}

处理接口

  

// JAXB默认不处理接口&gt; :(

现在JAXB已不再了解Precondition查询类,如果您愿意,可以将其设为接口。

public interface PreconditionQuery {

}