问题
I'm trying to use JAXB to unmarshal this file into Java objects. I know that there's a problem with SAX in J6 that rejects the maxOccurs line, and I've changed it to unbounded
. However, when I xjc
it, it's not creating all the classes & enums I need. For example, there should be a educationLevelType
enum. What's more, I'ved tried MS's xsd unmarshaller, it it creates everything correctly.
Can someone with more experience than I look at this and tell me what I'm missing? Is there something that needs to be corrected in the xsd, or is there a bug in JAXB?
Update Blaise completely answered this question as asked. Unfortunately, IMHO, this makes JAXB worthless. The whole idea is that I can generate classes from a schema - I shouldn't have to know stuff about the structure beforehand. If I have to create a custom bindings file, I might as well just create a schema that produces the code I want. But then, why stop there? Why not just skip all those steps and generate the classes I want?
In the end, a coworker pointed me to Apache XMLBeans - the project's a little older, but it creates the objects without trouble. Codehaus also has a xmlbeans-maven-plugin for it.
回答1:
There are a couple of enumeration values that are causing this issue. These issues can be overcome through the use of a JAXB external binding file (see below).
Enum Issue #1 - Empty String
Some of your enum values are empty string (""), which is causing a String rather than an enum property to be generated:
<xs:enumeration value="">
<xs:annotation>
<xs:documentation>Blank</xs:documentation>
</xs:annotation>
</xs:enumeration>
Enum Issue #2 - Numeric String
Some of the enum values are numbers which is causing a String rather than an enum property to be generated:
<xs:enumeration value="6">
<xs:annotation>
<xs:documentation>6th grade</xs:documentation>
</xs:annotation>
</xs:enumeration>
Bindings File (bindings.xml)
The following bindings file can be used to address the issues with the educationLevelType, the concepts here can be applied to all the problematic types:
<jxb:bindings
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
version="2.1">
<jxb:bindings schemaLocation="http://www.acf.hhs.gov/programs/cb/systems/nytd/nytd_data_file_format.xsd">
<jxb:bindings node="//xs:simpleType[@name='educationLevelType']/xs:restriction/xs:enumeration[@value='6']">
<jxb:typesafeEnumMember name="SIX"/>
</jxb:bindings>
<jxb:bindings node="//xs:simpleType[@name='educationLevelType']/xs:restriction/xs:enumeration[@value='7']">
<jxb:typesafeEnumMember name="SEVEN"/>
</jxb:bindings>
<jxb:bindings node="//xs:simpleType[@name='educationLevelType']/xs:restriction/xs:enumeration[@value='8']">
<jxb:typesafeEnumMember name="EIGHT"/>
</jxb:bindings>
<jxb:bindings node="//xs:simpleType[@name='educationLevelType']/xs:restriction/xs:enumeration[@value='9']">
<jxb:typesafeEnumMember name="NINE"/>
</jxb:bindings>
<jxb:bindings node="//xs:simpleType[@name='educationLevelType']/xs:restriction/xs:enumeration[@value='10']">
<jxb:typesafeEnumMember name="TEN"/>
</jxb:bindings>
<jxb:bindings node="//xs:simpleType[@name='educationLevelType']/xs:restriction/xs:enumeration[@value='11']">
<jxb:typesafeEnumMember name="ELEVEN"/>
</jxb:bindings>
<jxb:bindings node="//xs:simpleType[@name='educationLevelType']/xs:restriction/xs:enumeration[@value='12']">
<jxb:typesafeEnumMember name="TWELVE"/>
</jxb:bindings>
<jxb:bindings node="//xs:simpleType[@name='educationLevelType']/xs:restriction/xs:enumeration[@value='']">
<jxb:typesafeEnumMember name="BLANK"/>
</jxb:bindings>
</jxb:bindings>
</jxb:bindings>
The XJC call can be made as follows (the -nv flag is described below):
xjc -nv -b bindings.xml -d out http://www.acf.hhs.gov/programs/cb/systems/nytd/nytd_data_file_format.xsd
This will cause the following Enum to be generated:
package gov.hhs.acf.nytd;
import javax.xml.bind.annotation.XmlEnum;
import javax.xml.bind.annotation.XmlEnumValue;
import javax.xml.bind.annotation.XmlType;
@XmlType(name = "educationLevelType")
@XmlEnum
public enum EducationLevelType {
@XmlEnumValue("under 6")
UNDER_6("under 6"),
@XmlEnumValue("6")
SIX("6"),
@XmlEnumValue("7")
SEVEN("7"),
@XmlEnumValue("8")
EIGHT("8"),
@XmlEnumValue("9")
NINE("9"),
@XmlEnumValue("10")
TEN("10"),
@XmlEnumValue("11")
ELEVEN("11"),
@XmlEnumValue("12")
TWELVE("12"),
@XmlEnumValue("post secondary")
POST_SECONDARY("post secondary"),
@XmlEnumValue("college")
COLLEGE("college"),
@XmlEnumValue("")
BLANK("");
private final String value;
EducationLevelType(String v) {
value = v;
}
public String value() {
return value;
}
public static EducationLevelType fromValue(String v) {
for (EducationLevelType c: EducationLevelType.values()) {
if (c.value.equals(v)) {
return c;
}
}
throw new IllegalArgumentException(v);
}
}
maxOccurs Issue
For the maxOccurs issue, the following command line with the no verify (-nv) flag can be used to parse the XML schema:
xjc -nv -d out http://www.acf.hhs.gov/programs/cb/systems/nytd/nytd_data_file_format.xsd
This will get you past the following error without having to modify the XML schema:
parsing a schema... [ERROR] Current configuration of the parser doesn't allow a maxOccurs attribute value to be set greater than the value 5,000.
line 41 of http://www.acf.hhs.gov/programs/cb/systems/nytd/nytd_data_file_format.xsdFailed to parse a schema.
For More Information
- http://blog.bdoughan.com/2011/08/jaxb-and-enums.html
回答2:
Instead of specifying a binding for each enum value, you can also use a globalBindings with typesafeEnumMemberName="generateName"
<?xml version="1.0" encoding="UTF-8"?>
<bindings xmlns="http://java.sun.com/xml/ns/jaxb"
xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
xsi:schemaLocation="
http://java.sun.com/xml/ns/jaxb http://java.sun.com/xml/ns/jaxb/bindingschema_2_0.xsd"
version="2.1" schemaLocation="xxxxxxxxx.xsd" >
<schemaBindings>
<package name="xx.xx.xx" />
</schemaBindings>
<globalBindings typesafeEnumMemberName="generateName"/>
</bindings>
see http://download.oracle.com/docs/cd/E17802_01/webservices/webservices/docs/1.5/tutorial/doc/JAXBUsing4.html#wp148515
回答3:
XMLBeans does not generate an enum for this XML schema either. Using XMLBeans 2.5.0 (the latest from http://xmlbeans.apache.org/) the following is what is generated for educationLevelType:
/*
* XML Type: educationLevelType
* Namespace: http://nytd.acf.hhs.gov
* Java type: gov.hhs.acf.nytd.EducationLevelType
*
* Automatically generated - do not modify.
*/
package gov.hhs.acf.nytd;
/**
* An XML educationLevelType(@http://nytd.acf.hhs.gov).
*
* This is an atomic type that is a restriction of gov.hhs.acf.nytd.EducationLevelType.
*/
public interface EducationLevelType extends org.apache.xmlbeans.XmlString
{
public static final org.apache.xmlbeans.SchemaType type = (org.apache.xmlbeans.SchemaType)
org.apache.xmlbeans.XmlBeans.typeSystemForClassLoader(EducationLevelType.class.getClassLoader(), "schemaorg_apache_xmlbeans.system.s1A8CC5216945B0856A28CEF895800DEB").resolveHandle("educationleveltypeb147type");
org.apache.xmlbeans.StringEnumAbstractBase enumValue();
void set(org.apache.xmlbeans.StringEnumAbstractBase e);
static final Enum UNDER_6 = Enum.forString("under 6");
static final Enum X_6 = Enum.forString("6");
static final Enum X_7 = Enum.forString("7");
static final Enum X_8 = Enum.forString("8");
static final Enum X_9 = Enum.forString("9");
static final Enum X_10 = Enum.forString("10");
static final Enum X_11 = Enum.forString("11");
static final Enum X_12 = Enum.forString("12");
static final Enum POST_SECONDARY = Enum.forString("post secondary");
static final Enum COLLEGE = Enum.forString("college");
static final Enum X = Enum.forString("");
static final int INT_UNDER_6 = Enum.INT_UNDER_6;
static final int INT_X_6 = Enum.INT_X_6;
static final int INT_X_7 = Enum.INT_X_7;
static final int INT_X_8 = Enum.INT_X_8;
static final int INT_X_9 = Enum.INT_X_9;
static final int INT_X_10 = Enum.INT_X_10;
static final int INT_X_11 = Enum.INT_X_11;
static final int INT_X_12 = Enum.INT_X_12;
static final int INT_POST_SECONDARY = Enum.INT_POST_SECONDARY;
static final int INT_COLLEGE = Enum.INT_COLLEGE;
static final int INT_X = Enum.INT_X;
/**
* Enumeration value class for gov.hhs.acf.nytd.EducationLevelType.
* These enum values can be used as follows:
* <pre>
* enum.toString(); // returns the string value of the enum
* enum.intValue(); // returns an int value, useful for switches
* // e.g., case Enum.INT_UNDER_6
* Enum.forString(s); // returns the enum value for a string
* Enum.forInt(i); // returns the enum value for an int
* </pre>
* Enumeration objects are immutable singleton objects that
* can be compared using == object equality. They have no
* public constructor. See the constants defined within this
* class for all the valid values.
*/
static final class Enum extends org.apache.xmlbeans.StringEnumAbstractBase
{
/**
* Returns the enum value for a string, or null if none.
*/
public static Enum forString(java.lang.String s)
{ return (Enum)table.forString(s); }
/**
* Returns the enum value corresponding to an int, or null if none.
*/
public static Enum forInt(int i)
{ return (Enum)table.forInt(i); }
private Enum(java.lang.String s, int i)
{ super(s, i); }
static final int INT_UNDER_6 = 1;
static final int INT_X_6 = 2;
static final int INT_X_7 = 3;
static final int INT_X_8 = 4;
static final int INT_X_9 = 5;
static final int INT_X_10 = 6;
static final int INT_X_11 = 7;
static final int INT_X_12 = 8;
static final int INT_POST_SECONDARY = 9;
static final int INT_COLLEGE = 10;
static final int INT_X = 11;
public static final org.apache.xmlbeans.StringEnumAbstractBase.Table table =
new org.apache.xmlbeans.StringEnumAbstractBase.Table
(
new Enum[]
{
new Enum("under 6", INT_UNDER_6),
new Enum("6", INT_X_6),
new Enum("7", INT_X_7),
new Enum("8", INT_X_8),
new Enum("9", INT_X_9),
new Enum("10", INT_X_10),
new Enum("11", INT_X_11),
new Enum("12", INT_X_12),
new Enum("post secondary", INT_POST_SECONDARY),
new Enum("college", INT_COLLEGE),
new Enum("", INT_X),
}
);
private static final long serialVersionUID = 1L;
private java.lang.Object readResolve() { return forInt(intValue()); }
}
/**
* A factory class with static methods for creating instances
* of this type.
*/
public static final class Factory
{
public static gov.hhs.acf.nytd.EducationLevelType newValue(java.lang.Object obj) {
return (gov.hhs.acf.nytd.EducationLevelType) type.newValue( obj ); }
public static gov.hhs.acf.nytd.EducationLevelType newInstance() {
return (gov.hhs.acf.nytd.EducationLevelType) org.apache.xmlbeans.XmlBeans.getContextTypeLoader().newInstance( type, null ); }
public static gov.hhs.acf.nytd.EducationLevelType newInstance(org.apache.xmlbeans.XmlOptions options) {
return (gov.hhs.acf.nytd.EducationLevelType) org.apache.xmlbeans.XmlBeans.getContextTypeLoader().newInstance( type, options ); }
/** @param xmlAsString the string value to parse */
public static gov.hhs.acf.nytd.EducationLevelType parse(java.lang.String xmlAsString) throws org.apache.xmlbeans.XmlException {
return (gov.hhs.acf.nytd.EducationLevelType) org.apache.xmlbeans.XmlBeans.getContextTypeLoader().parse( xmlAsString, type, null ); }
public static gov.hhs.acf.nytd.EducationLevelType parse(java.lang.String xmlAsString, org.apache.xmlbeans.XmlOptions options) throws org.apache.xmlbeans.XmlException {
return (gov.hhs.acf.nytd.EducationLevelType) org.apache.xmlbeans.XmlBeans.getContextTypeLoader().parse( xmlAsString, type, options ); }
/** @param file the file from which to load an xml document */
public static gov.hhs.acf.nytd.EducationLevelType parse(java.io.File file) throws org.apache.xmlbeans.XmlException, java.io.IOException {
return (gov.hhs.acf.nytd.EducationLevelType) org.apache.xmlbeans.XmlBeans.getContextTypeLoader().parse( file, type, null ); }
public static gov.hhs.acf.nytd.EducationLevelType parse(java.io.File file, org.apache.xmlbeans.XmlOptions options) throws org.apache.xmlbeans.XmlException, java.io.IOException {
return (gov.hhs.acf.nytd.EducationLevelType) org.apache.xmlbeans.XmlBeans.getContextTypeLoader().parse( file, type, options ); }
public static gov.hhs.acf.nytd.EducationLevelType parse(java.net.URL u) throws org.apache.xmlbeans.XmlException, java.io.IOException {
return (gov.hhs.acf.nytd.EducationLevelType) org.apache.xmlbeans.XmlBeans.getContextTypeLoader().parse( u, type, null ); }
public static gov.hhs.acf.nytd.EducationLevelType parse(java.net.URL u, org.apache.xmlbeans.XmlOptions options) throws org.apache.xmlbeans.XmlException, java.io.IOException {
return (gov.hhs.acf.nytd.EducationLevelType) org.apache.xmlbeans.XmlBeans.getContextTypeLoader().parse( u, type, options ); }
public static gov.hhs.acf.nytd.EducationLevelType parse(java.io.InputStream is) throws org.apache.xmlbeans.XmlException, java.io.IOException {
return (gov.hhs.acf.nytd.EducationLevelType) org.apache.xmlbeans.XmlBeans.getContextTypeLoader().parse( is, type, null ); }
public static gov.hhs.acf.nytd.EducationLevelType parse(java.io.InputStream is, org.apache.xmlbeans.XmlOptions options) throws org.apache.xmlbeans.XmlException, java.io.IOException {
return (gov.hhs.acf.nytd.EducationLevelType) org.apache.xmlbeans.XmlBeans.getContextTypeLoader().parse( is, type, options ); }
public static gov.hhs.acf.nytd.EducationLevelType parse(java.io.Reader r) throws org.apache.xmlbeans.XmlException, java.io.IOException {
return (gov.hhs.acf.nytd.EducationLevelType) org.apache.xmlbeans.XmlBeans.getContextTypeLoader().parse( r, type, null ); }
public static gov.hhs.acf.nytd.EducationLevelType parse(java.io.Reader r, org.apache.xmlbeans.XmlOptions options) throws org.apache.xmlbeans.XmlException, java.io.IOException {
return (gov.hhs.acf.nytd.EducationLevelType) org.apache.xmlbeans.XmlBeans.getContextTypeLoader().parse( r, type, options ); }
public static gov.hhs.acf.nytd.EducationLevelType parse(javax.xml.stream.XMLStreamReader sr) throws org.apache.xmlbeans.XmlException {
return (gov.hhs.acf.nytd.EducationLevelType) org.apache.xmlbeans.XmlBeans.getContextTypeLoader().parse( sr, type, null ); }
public static gov.hhs.acf.nytd.EducationLevelType parse(javax.xml.stream.XMLStreamReader sr, org.apache.xmlbeans.XmlOptions options) throws org.apache.xmlbeans.XmlException {
return (gov.hhs.acf.nytd.EducationLevelType) org.apache.xmlbeans.XmlBeans.getContextTypeLoader().parse( sr, type, options ); }
public static gov.hhs.acf.nytd.EducationLevelType parse(org.w3c.dom.Node node) throws org.apache.xmlbeans.XmlException {
return (gov.hhs.acf.nytd.EducationLevelType) org.apache.xmlbeans.XmlBeans.getContextTypeLoader().parse( node, type, null ); }
public static gov.hhs.acf.nytd.EducationLevelType parse(org.w3c.dom.Node node, org.apache.xmlbeans.XmlOptions options) throws org.apache.xmlbeans.XmlException {
return (gov.hhs.acf.nytd.EducationLevelType) org.apache.xmlbeans.XmlBeans.getContextTypeLoader().parse( node, type, options ); }
/** @deprecated {@link org.apache.xmlbeans.xml.stream.XMLInputStream} */
public static gov.hhs.acf.nytd.EducationLevelType parse(org.apache.xmlbeans.xml.stream.XMLInputStream xis) throws org.apache.xmlbeans.XmlException, org.apache.xmlbeans.xml.stream.XMLStreamException {
return (gov.hhs.acf.nytd.EducationLevelType) org.apache.xmlbeans.XmlBeans.getContextTypeLoader().parse( xis, type, null ); }
/** @deprecated {@link org.apache.xmlbeans.xml.stream.XMLInputStream} */
public static gov.hhs.acf.nytd.EducationLevelType parse(org.apache.xmlbeans.xml.stream.XMLInputStream xis, org.apache.xmlbeans.XmlOptions options) throws org.apache.xmlbeans.XmlException, org.apache.xmlbeans.xml.stream.XMLStreamException {
return (gov.hhs.acf.nytd.EducationLevelType) org.apache.xmlbeans.XmlBeans.getContextTypeLoader().parse( xis, type, options ); }
/** @deprecated {@link org.apache.xmlbeans.xml.stream.XMLInputStream} */
public static org.apache.xmlbeans.xml.stream.XMLInputStream newValidatingXMLInputStream(org.apache.xmlbeans.xml.stream.XMLInputStream xis) throws org.apache.xmlbeans.XmlException, org.apache.xmlbeans.xml.stream.XMLStreamException {
return org.apache.xmlbeans.XmlBeans.getContextTypeLoader().newValidatingXMLInputStream( xis, type, null ); }
/** @deprecated {@link org.apache.xmlbeans.xml.stream.XMLInputStream} */
public static org.apache.xmlbeans.xml.stream.XMLInputStream newValidatingXMLInputStream(org.apache.xmlbeans.xml.stream.XMLInputStream xis, org.apache.xmlbeans.XmlOptions options) throws org.apache.xmlbeans.XmlException, org.apache.xmlbeans.xml.stream.XMLStreamException {
return org.apache.xmlbeans.XmlBeans.getContextTypeLoader().newValidatingXMLInputStream( xis, type, options ); }
private Factory() { } // No instance of this class allowed
}
}
来源:https://stackoverflow.com/questions/4820113/enums-dont-match-schema-problem-with-jaxb-or-xsd