Generating big enum classes with numbers in enum values JAXB, XJC - java

I'm trying to generate java classes using XJC and I have the following problem:
I'm trying to parse this schema which is a big enum type (bigger than default typesafeEnumMaxMembers). So I use following binding:
<jxb:bindings
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
version="2.1">
<!-- Raise theEnumMemberSizeCap limit -->
<jxb:bindings >
<jxb:globalBindings typesafeEnumMaxMembers="2000"/>
</jxb:bindings>
</jxb:bindings>
and then I call xjc with following line:
C:\Program Files\Java\jdk1.7.0_17\bin\xjc.exe -d C:\Users\buriak\out xml\dAllDocuments_v02.1.xsd xml/binding.xjb
this gives no errors, just that:
parsing a schema...
compiling a schema...
Then it ends without creating anything.
Smaller enum types are easily parsed same way, but bigger once are just ignored and if they are a part of some other type other xsd - they simply become a string:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:include schemaLocation="dAllDocuments_v02.1.xsd"/>
<xs:complexType name="tDocument">
<xs:annotation>
<xs:documentation>Документ - описание</xs:documentation>
</xs:annotation>
<xs:sequence>
<xs:element name="Code_Document" type="dAllDocuments">
<xs:annotation>
<xs:documentation>Код документа</xs:documentation>
</xs:annotation>
</xs:element>
...............
public class TDocument {
#XmlElement(name = "Code_Document", required = true)
protected String codeDocument;
...............
Using JAXB or XmlBeans results with nothing aswell.
Hope somebody knows what to do with that.
EDIT
After browsing without finding answers for long time I started to think, that it is not the size that is the problem.
I was right and as a result I found this - JAXB enumeration with numeric values
But XSD which I'm trying to parse is very big:
<xs:simpleType name="dAllDocuments">
<xs:restriction base="xs:string">
<xs:enumeration value="008001000000"/>
<xs:enumeration value="008001001000"/>
<xs:enumeration value="008001002000"/>
<xs:enumeration value="008001003000"/>
<xs:enumeration value="008001004000"/>
<xs:enumeration value="008001005000"/>
<xs:enumeration value="008001006000"/>
<xs:enumeration value="008001007000"/>
<xs:enumeration value="008001008000"/>
<xs:enumeration value="008001009000"/>
<xs:enumeration value="008001010000"/>....
And it keeps going for long more. There is absolutely no way I can write them all down in such a way:
<jxb:bindings node="//xs:simpleType[#name='dAllDocuments']/xs:restriction/xs:enumeration[#value='008001000000']">
<jxb:typesafeEnumMember name="OOBOOIOOOOOO"/>
</jxb:bindings>
Is there any way to make this work other than specifying name for each value manually?
I mean I can create a program which will make that kind of stuff using Strings, but is there any smart way?
Because actual XSD that I'm parsing is connected to multiple of such ENUM XSD and I need to parse them all.

After spending some more time on research I finally managed to get results which I was waiting for from xjc.
Here is binding file I was using, so that I don't get warning for enum type being too big and so that all those big enum types would have a generated name like VALUE_1, VALUE_2 etc.
<jxb:bindings
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
version="2.1">
<!-- Raise theEnumMemberSizeCap limit -->
<jxb:bindings >
<jxb:globalBindings typesafeEnumMaxMembers="2000" typesafeEnumMemberName="generateName"/>
</jxb:bindings>
<jxb:bindings schemaLocation="STD_Region_Cadastr.xsd">
<jxb:bindings node="//xs:complexType[#name='tRight_Owner']">
<jxb:class name="tRight_Owner2"/>
</jxb:bindings>
</jxb:bindings>
</jxb:bindings>
Also I'd like to mention that, since XSD files, which I was parsing, had a lot of cyrillic letters, here is xjc call I was using:
C:\Program Files\Java\jdk1.7.0_17\bin>xjc.exe -b xml/binding.xjb -d C:\Users\buriak\out xml\STD_Region_Cadastr.xsd -encoding UTF-8
That makes almost every cyrillic letter enterance show in java files correctly.
That's it.

Related

Generate enum from deeply nested xsd elements

I'm having a problem generating enum from deeply nested xsd elements. When I generate the code during maven build, my enums are of type string. Here's an example.
<xs:element name="Car">
<xs:complexType>
<xs:sequence>
<xs:element name="CarModal">
<xs:complexType>
<xs:sequence>
<xs:element name="Type">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="SomeValue"/>
<xs:enumeration value="AnotherValue"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:sequence>
</xs:completType>
</xs:element>
</xs:sequence>
From the above example we would have another 20 elements inside of Car element that contains enum value name 'Type'. I have a binding file to bind 'Type' to jaxb:typesafeEnumClass but it's not working, i'm still getting strings as my enum type. Here's an example of my binding.
<jaxb:bindings schemaLocation="someLocation">
<jaxb:bindings node="//xs:element[#name='Car']>
<jaxb:bindings node="//xs:element[#name='CarModal']">
<jaxb:bindings node="xs:element[#name='Type']/xs:simpleType>
<jaxb:typesafeEnumClass name="Type"/>
</jaxb:bindings>
</jaxb:bindings>
</jaxb:bindings>
</jaxb:bindings>
Thanks for any help and I can't change the xsd
I guess your bindings are nor precise enough. When you write //xs:element[#name='CarModal'], you basically say "any CarModal element inside my schema". Next, you say you have many Type elements so xs:element[#name='Type']/xs:simpleType is not precise enough.
Try more precise expressions like
xs:complexType/xs:sequence/xs:element[#name='CarModal']/
xs:complexType/xs:sequence/xs:element[#name='Type']/xs:simpleType
Next, your binding makes a general impression of the incorrect syntax. For instance this:
<jaxb:bindings node="xs:element[#name='Type']/xs:simpleType>
is invalid XML (missing " after xs:simpleType). So it might be the case that you binding is not considered at all - otherwise you should have gotten an error instead of generated code. Double-check if the binding is applied at all.

Organizing XSDs in a JAR

I have the following structure in a JAR:
Products.xsd
ProductCommonTypes.xsd
/com
/foo
Products.class
When I do
schemaURL = Products.class.getClassLoader().getResource(schemaFile);
I see "Using schemaURL: jar:file:/C:/my.jar!/Products.xsd". I think this is good.
Later, I try to create a Schema and get an exception stating "Cannot resolve the name 'common:nonEmptyString' to a(n) 'type definition' component."
I believe that the problem is that it is unable to find common:nonEmptyString (which is in ProductCommonTypes.xsd) but can not figure out how to fix it.
Products.xsd
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:p="http://www.foo.com/Products"
targetNamespace="http://www.foo.com/Products"
xmlns:common="http://www.foo.com/ProductsCommonTypes"
elementFormDefault="qualified">
<xs:import schemaLocation="ProductsCommonTypes.xsd"
namespace="http://www.foo.com/ProductsCommonTypes"/>
<xs:element name="products">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="common:nonEmptyString" minOccurs="1" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
ProductCommonTypes.xsd
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.foo.com/ProductsCommonTypes"
xmlns="http://www.foo.com/ProductsCommonTypes"
elementFormDefault="qualified" >
<xs:simpleType name="nonEmptyString">
<xs:annotation>
<xs:documentation>A type that will require a non-empty string value be present
</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:pattern value="(\s*[^\s]\s*)+"></xs:pattern>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="url">
<xs:annotation>
<xs:documentation>A HTTP URL</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:anyURI">
<xs:pattern value="https?://.+"></xs:pattern>
</xs:restriction>
</xs:simpleType>
</xs:schema>
[jaxb - Unable to unmarshall from XSD which included other xsd
suggests adding all schema references, but I am working with many schemas that all import several other schemas. Seems like it could get ugly quick!
Is there a generic/dynamic solution that does not require me to identify and hardcode all schemas everytime I plan on working with one that might import others?
I plan to move all XSDs to a MyXSDs folder within the jar at some point. After moving them, will I have to do anything differently due to the location change?
Solution
I was able to solve this using an XMLCatalogResolver and creating an XML catalog file.
I moved all of my XSDs into a single folder and have the following structure in my JAR:
MyXSDs
Products.xsd
ProductCommonTypes.xsd
/com
/foo
Products.class
First, I created the catalog file and identified the schema that was being referenced.
<!DOCTYPE catalog
PUBLIC "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN"
"http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd">
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
<public
publicId="http://www.foo.com/ProductCommonTypes"
uri="ProductCommonTypes.xsd"/>
</catalog>
Then, I created an XMLCatalogResolver that uses my catalog file and used it as the ResourceResolver for my SchemaFactory. It is important to note that the catalogs must be specified as an ordered array of absolute URIs as per the constructor's documentation.
// The catalogs must be an ordered array list of *ABSOLUTE* URIs
String[] catalogs = new String[] { xmlCatalogAbsPath };
XMLCatalogResolver resourceResolver = new XMLCatalogResolver(catalogs);
schemaFactory.setResourceResolver(resourceResolver);
You must specify the relative path to the XSD file. Therefore, because I put all of mine into a folder, I set relatativeSchemaPath="MyXSDs/Products.xsd" for use with ClassLoader.getSystemResource.
StreamSource streamSource = new StreamSource(ClassLoader.getSystemResource(relatativeSchemaPath).toString());
Schema schema = schemaFactory.newSchema(streamSource);

How to custom xjc generated enum and field name?

Here is the question, our contract is XSD file. Lately we want it to support Json.But there is some tricky problem we have to solve. When I define xsd like this:
<xs:simpleType name="SomeType">
<xs:restriction base="xs:string">
<xs:enumeration value="SomeSelfDefineType" />
</xs:restriction>
</xs:simpleType>
The generated code is like this:
#XmlType(name = "SomeType")
#XmlEnum
public enum SomeType {
#XmlEnumValue("SomeSelfDefineType")
SOME_SELF_DEFINE_TYPE("SomeSelfDefineType")
}
When using XML, it's fine, because it reads the annotation info, but when we use Json, SomeSelfDefineType will be transfer into SOME_SELF_DEFINE_TYPE. Register a lot of custom Gson serializable/deserializable Interface to resovle this problem is not a good option for me.
I've checked out other's answers about how to custom some name of field or enum, but I really have a lot of enum definations. Is there any plugin or solutions for me to generate code like this:
#XmlType(name = "SomeType")
#XmlEnum
public enum SomeType {
#XmlEnumValue("SomeSelfDefineType")
SomeSelfDefineType("SomeSelfDefineType")
}
I am not familiar with JAXB or its plugins, could anyone give me some xjb settings or plugin for me to save this problem?
you can override the enum values using .xjb as below.
<?xml version="1.0"?>
<jxb:bindings version="2.1" xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" jxb:extensionBindingPrefixes="xjc">
<jxb:bindings schemaLocation="yours.xsd">
<jxb:bindings
node="//xs:simpleType[#name='SomeType']/xs:restriction/xs:enumeration[#value='SomeSelfDefineType']">
<jxb:typesafeEnumMember name="SomeSelfDefineType" />
</jxb:bindings>
</jxb:bindings>
</jxb:bindings>

Getting "compiler was unable to honor this javaType customization" with "xs:any"

I have the following xsd:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="root">
<xs:complexType>
<xs:sequence>
<xs:any processContents="skip" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
and the following bindings:
<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="format.xsd">
<jxb:bindings node="//xs:any">
<jxb:property>
<jxb:baseType>
<jxb:javaType name="org.w3c.dom.Element"
parseMethod="leif.ElementFormatter.parseElement"
printMethod="leif.ElementFormatter.printString" />
</jxb:baseType>
</jxb:property>
</jxb:bindings>
</jxb:bindings>
</jxb:bindings>
But when I run xjc...
xjc -p leif -b bindings.xml format.xsd
I get the following errors:
parsing a schema...
[ERROR] compiler was unable to honor this javaType customization. It is attached to a wrong place, or its inconsistent with other bindings.
line 9 of file:/C:/Users/leif/workspace/doughan/src/main/resources/bindings.xml
[ERROR] (the above customization is attached to the following location in the schema)
line 7 of file:/C:/Users/leif/workspace/doughan/src/main/resources/format.xsd
Failed to parse a schema.
It happens only when defining javaType for an xs:any, and when I change it to xs:element it works. But I really need it to be xs:any.
My goal is to get a class like that:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Root {
#XmlJavaTypeAdapter(Adapter1.class)
#XmlAnyElement
String any;
}

Convert xs:string to java.util.UUID in jaxb

In jaxb, how do you convert a string in xsd to java.util.UUID? Is there a built-in data type converter or do I have to create my own custom converter?
This is much easier to do if you start with Java classes and use JAXB annotations. However, to do this using schema you must use a custom bindings file. Here is an example:
Schema: (example.xsd)
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.example.com"
xmlns="http://www.example.com"
elementFormDefault="qualified">
<xs:simpleType name="uuid-type">
<xs:restriction base="xs:string">
<xs:pattern value=".*"/>
</xs:restriction>
</xs:simpleType>
<xs:complexType name="example-type">
<xs:all>
<xs:element name="uuid" type="uuid-type"/>
</xs:all>
</xs:complexType>
<xs:element name="example" type="example-type"/>
</xs:schema>
Bindings: (bindings.xjb) (Note that for brevity in printMethod and parseMethod I assumed that the UuidConverter class was in the default package. These should be fully qualified in reality. So if UuidConverter where in package com.foo.bar then the values should be like com.foo.bar.UuidConverter.parse and com.foo.bar.UuidConverter.print
<!-- Modify the schema location to be a path or url -->
<jxb:bindings version="1.0"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
node="/xs:schema"
schemaLocation="example.xsd">
<!-- Modify this XPATH to suit your needs! -->
<jxb:bindings node="//xs:simpleType[#name='uuid-type']">
<jxb:javaType name=" java.util.UUID"
parseMethod="UuidConverter.parse"
printMethod="UuidConverter.print"/>
</jxb:bindings>
</jxb:bindings>
UuidConverter.java:
import java.util.UUID;
public class UuidConverter {
public static UUID parse(String xmlValue) {
return UUID.fromString(xmlValue);
}
public static String print(UUID value) {
return value.toString();
}
}
Sadly I can't point you to a good reference because its really not documented well. There are bits and pieces of how it all works spread out in blog posts. Took me a few hours to make this work the first time. :-/
Create a simple converter yourself:
UUID.fromString(String uuid);
http://docs.oracle.com/javase/6/docs/api/java/util/UUID.html

Categories

Resources