Following up JAXB and Composite Pattern , I managed to map:
<precondition>
<or>
<and>
<just><query>foo</query></just>
<just><query>bar</query></just>
</and>
<just><query>baz</query></just>
</or>
</precondition>
But I'd like to map:
<precondition>
<or>
<and>
<query>foo</query>
<query>bar</query>
</and>
<query>baz</query>
</or>
</precondition>
My JAXB class hierarchy is as follows:
@XmlRootElement
@XmlSeeAlso({SimplePreconditionQuery.class, CompoundAndPreconditionQuery.class, CompoundOrPreconditionQuery.class})
public abstract class PreconditionQuery {
// JAXB does not deal with interfaces by default >:(
}
With several kinds of queries:
@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;
}
}
The compound ones (AND/OR) are very similar:
@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;
}
}
And the enclosing bean:
public class Precondition {
private PreconditionQuery query;
@XmlElementRef(required = true)
public PreconditionQuery getQuery() {
return query;
}
public void setQuery(PreconditionQuery query) {
this.query = query;
}
}
JAXB won't allow me to just map a @XmlValue
on SimplePreconditionQuery
. Why and what's the alternative?
If you simply do:
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;
}
}
You will get the following exception because SimplePreconditionQuery
subclasses something other than java.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
from the inheritance hierarchy. We can use the @XmlTransient
annotation at the class level to remove the class from JAXB. All the properties from the super class will be treated as properties of the super class.
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 >:(
}
Now we get the following exception:
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
Now that we have removed PreconditionQuery
from the set of classes that JAXB cares about, we now longer benefit from the @XmlSeeAlso
annotation that it contains. As such we need to make our @XmlElementRef
annotations more explicit:
Precondition
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
You will also need to do this for CompoundAndPreconditionQuery
and CompoundAndPreconditionQuery
.
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 does not deal with interfaces by default >:(
Now that JAXB is no longer aware of the Precondition
query class, you could make it an interface if you wanted to.
public interface PreconditionQuery {
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.