Jaxb: Generate constant value for fixed-value attribute - java

I'm currently working on a xsd which uses the following contruct:
<xs:attribute name="listVersionID" type="xs:normalizedString" use="required" fixed="1.0">
While not problematic per se, it is rather annoying to work with, since the fixed-value of this definition increases between releases of the xsd spec, and we need to modify the values in a seperate constants-class to keep them valid, although little if anything of interest in the xsd has changed. The xsd is maintained elsewhere, so just changing it is no option.
Thus I was asking myself wether there is a jaxb-plugin or similar to turn fixed-value attributes into constants ala
#XmlAttribute(name = "listVersionID")
#XmlJavaTypeAdapter(NormalizedStringAdapter.class)
#XmlSchemaType(name = "normalizedString")
protected final String listVersionID = "1.0";
instead of just
#XmlAttribute(name = "listVersionID")
#XmlJavaTypeAdapter(NormalizedStringAdapter.class)
#XmlSchemaType(name = "normalizedString")
protected String listVersionID;
which must be populated manually.
Does anyone know of such?

If you don't want to modify your schema, another option is to use an external binding file:
<?xml version="1.0" encoding="UTF-8"?>
<jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
version="2.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<jaxb:bindings schemaLocation="yourschema.xsd" node="/xs:schema">
<jaxb:globalBindings fixedAttributeAsConstantProperty="true" />
</jaxb:bindings>
</jaxb:bindings>
It is equivalent to what proposes #jmattheis in his answer.

Yes it is possible through custom jaxb bindings, which can be added as file at the codegen.
In the jaxb bindings, there is the fixedAttributeAsConstantProperty-attribute. Setting this to true, instructs the code generator to generate attributes with the fixed attribute as java-constants.
There are 2 options for this:
1. Through global bindings:
which then make all attributes with fixed values to constants
<schema targetNamespace="http://stackoverflow.com/example"
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
jaxb:version="2.0">
<annotation>
<appinfo>
<jaxb:globalBindings fixedAttributeAsConstantProperty="true" />
</appinfo>
</annotation>
...
</schema>
2. Through local mappings:
Which only defines the fixedAttributeAsConstantProperty property on a specific attribute.
<schema targetNamespace="http://stackoverflow.com/example"
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
jaxb:version="2.0">
<complexType name="example">
<attribute name="someconstant" type="xsd:int" fixed="42">
<annotation>
<appinfo>
<jaxb:property fixedAttributeAsConstantProperty="true" />
</appinfo>
</annotation>
</attribute>
</complexType>
...
</schema>
Both examples should result in:
#XmlRootElement(name = "example")
public class Example {
#XmlAttribute
public final static int SOMECONSTANT = 42;
}

Related

Is there a way to customize the JAXB binding for the content (itemType) of an xs:list

Is there a way to customize the JAXB binding for xs:list? The folowing example:
<simpleType name="doubleList">
<list itemType="double" />
</simpleType>
Will be bound by xjc to: List<Double>. However, I'd like to bind it to: List<BigDecimal>.
My initial setup was to define a binding like this:
<jaxb:bindings multiple="true" node="//xs:simpleType[#name='doubleList']/xs:list/#itemType">
<jaxb:property>
<jaxb:baseType name="java.math.BigDecimal" />
</jaxb:property>
</jaxb:bindings>
However, this gives the following problem:
XPath evaluation of "//xs:simpleType[#name='doubleList']/xs:list/#itemType" needs to result in an element.
Is there a way to do this without resorting to writing your own custom adapters?
The doubleList above was used elsewhere. Applying the binding on those spots, resulting in a correct Javaclass. Supprisingly, only choosing the proper base type was sufficient.
So place where the doubleList was used elsewhere:
<complexType name="DirectPositionType">
<simpleContent>
<extension base="gml:doubleList">
<attributeGroup ref="gml:SRSReferenceGroup" />
</extension>
</simpleContent>
</complexType>
Binding
<jaxb:bindings schemaLocation="http://schemas.opengis.net/gml/3.2.1/geometryBasic0d1d.xsd" node="/xs:schema">
<jaxb:bindings multiple="true" node="//xs:complexType[#name='DirectPositionType']">
<jaxb:property>
<jaxb:baseType name="java.math.BigDecimal" />
</jaxb:property>
</jaxb:bindings>
</jaxb:bindings>
resulting Java class:
public class DirectPositionType
{
#XmlValue
protected List<BigDecimal> value;
#XmlAttribute(name = "srsName")

Adding columnDefinition property to Hyperjaxb generated #Column attribute

I am using Hyperjaxb to generate my JPA mappings. Then I use hibernate3-maven-plugin to generate the SQL Script of the database. My problem lies in the fact that I have a type that has a property defined like this:
<xsd:element name="priority" type="xsd:boolean"/>
The sql script defines the column like this
PRIORITY bit,
And the JPA entity defines it like this
/**
* Obtient la valeur de la propriété priority.
*
*/
#Basic
#Column(name = "PRIORITY")
public boolean isPriority() {
return priority;
}
/**
* Définit la valeur de la propriété priority.
*
*/
public void setPriority(boolean value) {
this.priority = value;
}
I am using MySql as a backend. The problem raises when my JPA/Hibernate entityManager tries to validate my JPA model against the database. Then I get this error
org.hibernate.HibernateException: Wrong column type in custom.sample_type for column PRIORITY. Found: bit, expected: boolean
How can I fix this error? Somewhere I read I could do something like this in java code
#Basic
#Column(name = "B", columnDefinition = "BIT", length = 1)
public boolean isB() {
return b;
}
But my JPA java code is autogenerated by Hyperjaxb, so how can I achieve something like that with Hyperjaxb?
Disclaimer: I am the author of Hyperjaxb.
I'd try customizing your property with:
<hj:basic>
<orm:column column-definition="..."/>
</hj:basic>
See the customizations schema and the ORM schema it uses.
You can also configure per-type customizations if you don't want to customize every single boolean (which you probably don't want):
<hj:default-single-property type="xsd:boolean">
<hj:basic>
<orm:column column-definition="..."/>
</hj:basic>
</hj:default-single-property>
<hj:default-collection-property type="xsd:boolean">
<hj:element-collection>
<orm:column column-definition="..."/>
</hj:element-collection>
</hj:default-collection-property>
See this example of a binding file:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<jaxb:bindings
version="2.1"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:hj="http://hyperjaxb3.jvnet.org/ejb/schemas/customizations"
xmlns:orm="http://java.sun.com/xml/ns/persistence/orm"
xmlns:annox="http://annox.dev.java.net"
jaxb:extensionBindingPrefixes="hj orm annox">
<jaxb:bindings schemaLocation="schema.xsd" node="/xs:schema">
<jaxb:schemaBindings>
<jaxb:package name="org.jvnet.hyperjaxb3.ejb.tests.pocustomized"/>
</jaxb:schemaBindings>
<hj:persistence>
<hj:default-generated-id name="MySuperId" transient="true">
<orm:column name="MY_SUPER_ID"/>
</hj:default-generated-id>
<hj:default-one-to-many>
<orm:join-table/>
</hj:default-one-to-many>
</hj:persistence>
<jaxb:bindings node="xs:complexType[#name='one']/xs:sequence/xs:element[#name='many-to-many-join-table']">
<annox:annotate>
<annox:annotate annox:class="org.hibernate.annotations.Cascade" value="DELETE_ORPHAN"/>
</annox:annotate>
</jaxb:bindings>
<jaxb:bindings node="xs:element[#name='ten']/xs:complexType">
<hj:basic name="content">
<orm:column length="1024"/>
</hj:basic>
</jaxb:bindings>
</jaxb:bindings>
</jaxb:bindings>
You'll have to place your hj:default-...-property elements inside hj:persistence. They will then override default mappings.

Provide schema for xsd:any element while importing WSDL using wsimport

I have a WSDL that uses an xsd:any element in a return type for one of the methods, like this:
<xs:element name="Method_XMLResponse">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="1" name="Method_XMLResult">
<xs:complexType mixed="true">
<xs:sequence>
<xs:any/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
When I run the WSDL through the wsimport tool, I get a generated class that has this xs:any field mapped as a list of objects:
public static class MethodXMLResult {
#XmlMixed
#XmlAnyElement(lax = true)
protected List<Object> content;
}
When invoking the service using the generated code, I get instances of org.w3c.dom.Node in the content list (com.sun.org.apache.xerces.internal.dom.ElementNSImpl to be precise) that I would need to parse myself. I was, however, provided with a separate, external schema document for the objects actually returned - and I'm trying to somehow feed it to wsimport so it generates the classes for them as well.
I'm trying to accomplish that through JAX-WS / JAXB customization file like this:
<jaxws:bindings xmlns:s="http://www.w3.org/2001/XMLSchema"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
xmlns:jaxws="http://java.sun.com/xml/ns/jaxws" xmlns:a="http://www.w3.org/2001/XMLSchema"
wsdlLocation="wsdlLocation.wsdl">
<jaxws:bindings node="wsdl:definitions">
<jaxws:bindings node="wsdl:types" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb">
<jaxws:bindings node="//s:schema[#targetNamespace='wsNamespace']">
<jaxb:bindings node="//s:element[#name='Method_XMLResponse']//s:any">
...
</jaxb:bindings>
</jaxws:bindings>
</jaxws:bindings>
</jaxws:bindings>
</jaxws:bindings>
Looks like wsimport picks the right location to customize (gave me numerous error meesages with properly designated line number in the WSDL), but I can't figure out how to fill the <jaxb:bindings> element to make wsimport generate classes from the external schema. Is it even possible? Any help would be much appreciated.
I see you are use mixed type with xs:any in your XSD. I think it usefull custimization for a mixed type following JAXB adjust:
<?xml version="1.0" encoding="UTF-8"?>
<jaxb:bindings
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" jaxb:version="2.0"
xmlns:xjc= "http://java.sun.com/xml/ns/jaxb/xjc" jaxb:extensionBindingPrefixes="xjc">
<jaxb:globalBindings generateMixedExtensions="true"/>
</jaxb:bindings>
You can add external JAXB binding files to wsimport whith -b parameter.
I think you can adjust xs:any with following ways:
Skip shema:
<xs:any processContents="skip" maxOccurs="unbounded" minOccurs="0" />
Skip binding:
#XmlAnyElement
public List<Element> getAny();
Strict schema:
<xs:any maxOccurs="unbounded" minOccurs="0" />
Strict binding:
#XmlAnyElement(lax=true)
public List<Object> getAny();
and:
with processContents=lax means any XML elements can be
placed here, but if their element names match those defined in the
schema, they have to be valid. XJC actually handles this exactly like
processContents='strict', since the strict binding allows unknown
elements anyway.
You can read more about in this link.
May be help this answer to accomplish your JAX-WS / JAXB customization file.

specify type for IDREF in XML schema

I am generating Java objects from an XML schema using xjc. I would like to reference the same element multiple times within the document using IDREF. I would also like to constrain the objects referenced by IDREF to a specific type. I'd like to do this for the purposes of schema validation, but also so that in the Java code, the referenced object is returned as a specific type instead of type Object. For example, say I want a schema to describe the following:
<teams>
<team id="team1">
<coach>coachz</coach>
<player>homestar</player>
<player>marzipan</player>
<player>strongsad</player>
<player>strongbad</player>
</team>
<team id="team2">
<coach>bubs</coach>
<player>homesar</player>
<player>thecheat</player>
<player>poopsmith</player>
<player>bubs</player>
</team>
<team id="allstars">
<coach>poopsmith</coach>
<player>coachz</player>
<player>bubs</player>
<player>kingoftown</player>
<player>strongbad</player>
</team>
</teams>
<people>
<person id="coachz">Coach Z</person>
<person id="homesar">Homesar</person>
<person id="homestar">Homestar</person>
<person id="strongbad">Strong Bad</person>
<person id="strongsad">Strong Sad</person>
<person id="marzipan">Marzipan</person>
<person id="bubs">Bubs</person>
<person id="kingoftown">King of Town</person>
<person id="poopsmith">The Poopsmith</person>
<person id="thecheat">The Cheat</person>
</people>
I can define player like this:
<xs:element name="player" type="xs:IDREF" maxOccurs="unbounded"/>
but then in the Java code, when I try to retrieve a player it will come back as type object, and I have to cast it to a person. At that point, if someone has mistakenly referenced a Team object, I have errors to deal with that could have been caught at validation. I want to specify something like this:
<xs:element name="player" type="xs:IDREF"reftype="person"maxOccurs="unbounded" />
But as far as I can tell, there is no way to specify a type as I have done here with the contrived attribute 'reftype'. Can this be done, using IDREF? If not, is there another method?
You can simply apply baseType binding to your player element. Something like:
<jaxb:bindings node="xsd:element[#name='player']">
<jaxb:property>
<jaxb:baseType name="....Person"/>
</jaxb:property>
</jaxb:bindings>
You may need to figure out the correct binding location for your schema.
Example from my code:
Schema:
<xsd:complexType name="HJIII-53-A">
<xsd:sequence>
<xsd:element name="b" type="xsd:IDREF"/>
<xsd:element name="b1" type="test:HJIII-53-B"/>
<xsd:element name="c" type="xsd:IDREFS"/>
<xsd:element name="c1" type="test:HJIII-53-C" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
Bindings:
<jaxb:bindings schemaLocation="schema.xsd" node="/xsd:schema">
<jaxb:globalBindings localScoping="toplevel">
<jaxb:serializable/>
</jaxb:globalBindings>
<jaxb:bindings node="xsd:complexType[#name='HJIII-53-A']//xsd:element[#name='b']">
<jaxb:property>
<jaxb:baseType name="org.jvnet.hyperjaxb3.ejb.tests.issuesjpa2.HJIII53B"/>
</jaxb:property>
</jaxb:bindings>
<jaxb:bindings node="xsd:complexType[#name='HJIII-53-A']//xsd:element[#name='c']">
<jaxb:property>
<jaxb:baseType name="org.jvnet.hyperjaxb3.ejb.tests.issuesjpa2.HJIII53C"/>
</jaxb:property>
</jaxb:bindings>
</jaxb:bindings>
Generated code:
#XmlElement(required = true, type = Object.class)
#XmlIDREF
#XmlSchemaType(name = "IDREF")
protected org.jvnet.hyperjaxb3.ejb.tests.issuesjpa2.HJIII53B b;
#XmlElement(required = true)
protected org.jvnet.hyperjaxb3.ejb.tests.issuesjpa2.HJIII53B b1;
#XmlList
#XmlElement(required = true, type = Object.class)
#XmlIDREF
protected List<org.jvnet.hyperjaxb3.ejb.tests.issuesjpa2.HJIII53C> c;
protected List<org.jvnet.hyperjaxb3.ejb.tests.issuesjpa2.HJIII53C> c1;
See: https://svn.java.net/svn/hj3~svn/trunk/ejb/tests/issues-jpa2/src/main/resources/
lexicore's answer gave me what I need (and I suggest voting up his answer over mine). However I am using inline annotations instead of a separate bindings file. This is what it looks like with inline annotations, using my Homestar example:
<xs:element name="player" type="xs:IDREF" maxoccurs="unbounded">
<xs:annotation>
<xs:appinfo>
<jaxb:property>
<jaxb:baseType name="Person"/>
</jaxb:property>
</xs:appinfo>
</xs:annotation>
</xs:element>

How to generate classes from XSD that implements serializable?

I need to generate many classes from my XML Schema (XSD) in a package (.jar).
How can I configure these classes to be serializable?
(I'm using Eclipse and JAX-B)
If you are using XJC, I recomend you to read this reference: JavaTM Architecture for XML Binding: JAXB RI Vendor Extensions Customizations :
You have to add in your schema aditional namespaces definition to add xjc aditional markup:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
jaxb:extensionBindingPrefixes="xjc"
jaxb:version="1.0">
Then, including an <xjc:serializable> node within <jaxb:globalBindings>:
<xs:annotation>
<xs:appinfo>
<jaxb:globalBindings generateIsSetMethod="true">
<xjc:serializable uid="12343"/>
</jaxb:globalBindings>
</xs:appinfo>
</xs:annotation>
This will cause that all the concrete classes implement the Serializable interface. Also, you can define the UUID value of the resulting classes (that's an optional attribute).
I've found
<schema
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
jaxb:extensionBindingPrefixes="xjc"
jaxb:version="1.0"
>
<!-- FORCE ALL CLASSES IMPLEMENTS SERIALIZABLE -->
<annotation>
<appinfo>
<jaxb:globalBindings generateIsSetMethod="true">
<xjc:serializable uid="1"/>
</jaxb:globalBindings>
</appinfo>
</annotation>
....
</schema>

Categories