HyperJAXB: How to use always #OneToOne instead of #ManyToOne - java

HyperJAXB generates #ManyToOne Annotations for XSD 1:1-relationships like:
<xs:element name="typeName" type="otherType" />
or
<xs:element name="typeName" type="otherType" minOccurs="0" maxOccurs="1" />
This is not the expected behaviour since it should generate #OneToOne Annotations. Well, the customization guide describes that you can customize this behaviour by adding instructions to every single element definition (see http://confluence.highsource.org/display/HJ3/Making+schema-derived+classes+ready+for+JPA, paragraph "Mapping as one-to-one").
This is fine, but I need a global configuration for this. Can anybody please tell me, what to put in bindings.xjb to achieve this goal?

You can switch X:1 by default to one-to-one globaly:
<jaxb:bindings schemaLocation="schema.xsd" node="/xs:schema">
<hj:persistence>
<hj:default-to-one>
<hj:one-to-one/>
</hj:default-to-one>
</hj:persistence>
</jaxb:bindings>
However be warned, I think I've opted to #ManyToOne by default for a reason. It was safer and easier to handle.

Related

Is this offical Xml schema invalid or is error limitation of Jaxb

uPnP defines a number of Xml schemas including didl-lite.xsd, including this section:
<xsd:sequence>
<xsd:element ref="dc:title"/>
<xsd:group ref="didl-lite:allowed-under-container" minOccurs="0" maxOccurs="unbounded"/>
<xsd:group ref="upnp:class.group"/>
<xsd:group ref="didl-lite:allowed-under-container" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
When I tried to build Java classes from this using jaxb it complained
Removing the second xsd:group ref="didl-lite:allowed-under-container" minOccurs="0" maxOccurs="unbounded" line so we have
<xsd:sequence>
<xsd:element ref="dc:title"/>
<xsd:group ref="didl-lite:allowed-under-container" minOccurs="0" maxOccurs="unbounded"/>
<xsd:group ref="upnp:class.group"/>
</xsd:sequence>
fixed the issue, and seems to make more sense.
But I am not clear is the Xsd actually invalid or is this just a limitation of generating Jaxb classes from Xsd?
I think both semantically and formally the schema provided is valid.
You can, for instance, verify the schema well-formedness with Java or online, for example, in this site.
The issue you are facing could be considered a kind of limitation of JAXB.
The limitation consists in that the generator encounters a value that has been already taken into consideration in the process of generating your classes, and it has a problem, because it will be unable to generate a property and the corresponding related methods and stuff for this second value because the names are already taken.
I will use the xjc tool for code generation but the solution should be portable to the Maven or Gradle plugins too.
If you run the xjc tool like this:
xjc -d out didl-lite-v2.xsd
the error description will give you a possible solution:
[ERROR] Property "AllowedUnderItem" is already defined. Use <jaxb:property> to resolve this conflict
The mentioned term <jaxb:property> has to do with JAXB XML bindings.
JAXB XML bindings allows you to customize the JAXB Java classes generation process in different ways.
The necessary configuration is provided in a XML file with a certain information.
In this specific use case, you can define the following bindings XML file, let's name it binding.xml:
<?xml version="1.0" encoding="UTF-8"?>
<jaxb:bindings
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
version="2.1">
<jaxb:bindings schemaLocation="didl-lite-v2.xsd">
<jaxb:bindings
node="//xsd:complexType[#name='container.type']/xsd:sequence/xsd:group[#ref='didl-lite:allowed-under-container'][2]">
<jaxb:property name="allowedUnderContainerAfterUpnpClassGroup"/>
</jaxb:bindings>
<jaxb:bindings
node="//xsd:complexType[#name='item.type']/xsd:sequence/xsd:group[#ref='didl-lite:allowed-under-item'][2]">
<jaxb:property name="allowedUnderItemAfterUpnpClassGroup"/>
</jaxb:bindings>
</jaxb:bindings>
</jaxb:bindings>
As you can see, we are indicating that the second occurrence of the allowed-under-item group, represented by the XPath expression //xsd:complexType[#name='item.type']/xsd:sequence/xsd:group[#ref='didl-lite:allowed-under-item'][2], should be treated as allowedUnderItemAfterUpnpClassGroup. We need to do something similar with allowed-under-container.
Then, if you run again the xjc tool passing in this XML bindings file, your classes will be generated successfully:
xjc -d out -b binding.xml didl-lite-v2.xsd
This or this other SO questions could be of help as well.

Customize element for abstract complexType with HyperJaxb3

I'm converting an XSD schema to a Java annotated bean for Hibernate with HyperJaxb3.
So far I managed to generate the Java objects, but I need to customize the remark field of the OperableType because the default generated length is 255 and I need to extend it to 4000.
Here's the fragment of the relevent xsd schema:
<xs:complexType name="OperableType" abstract="true">
<xs:annotation>
<xs:documentation xml:lang="en">OperableType contains all the elements and attributes common to all the operables. This is an abstract type, so no element of this type will be present in the XML.
The logical ID is a unique logical identifier of a sanctioned entity, of a regulation or of a detail of a sanction entity. This information is also provided to external actors for help, especially when entity multiple aliases make it difficult the identification task. For entities imported from previous database, the old value is retained.</xs:documentation>
</xs:annotation>
<xs:sequence>
<xs:element name="remark" type="fsdexport:UnlimitedTextType" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="additionalInformation" type="fsdexport:AdditionalInfoType" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="logicalId" type="xs:long" use="required"/>
</xs:complexType>
<xs:simpleType name="UnlimitedTextType">
<xs:restriction base="xs:string"/>
</xs:simpleType>
I can't modify the XSD schema nor the XML file I receive, so I need to customize the bindings for it to work.
I tried using this binding
<jxb:bindings node="xs:complexType[#name='OperableType']">
<jxb:bindings node="xs:sequence//xs:element[#name='remark']">
<hj:basic>
<orm:column length="4000" />
</hj:basic>
</jxb:bindings>
</jxb:bindings>
but it doesn't modify the length in the generated code.
#ElementCollection
#OrderColumn(name = "HJINDEX")
#Column(name = "HJVALUE", length = 255)
#CollectionTable(name = "OPERABLE_TYPE_REMARK", joinColumns = {
#JoinColumn(name = "HJID")
})
public List<String> getRemark() {
I also tried to use 'hj:default-single-property' to customized the UnlimitedTextType but I didn't managed to make it work either.
After asking from help from the source,
https://github.com/highsource/hyperjaxb3/issues/54, I have the answer:
<jxb:bindings node="xs:complexType[#name='OperableType']">
<jxb:bindings node="xs:sequence//xs:element[#name='remark']">
<hj:element-collection>
<orm:column length="4000" />
</hj:element-collection>
</jxb:bindings>
</jxb:bindings>
The key is tu use hj:element-collection instead of hj:basic for an xml sequence.

CXF not adding superclass to generated class

I try to add a superclass definition to a generated class based on an incoming XML complexType. When I make the mapping generic, like this, it works:
<jaxb:globalBindings generateElementProperty="false">
<xjc:superClass name="nl.ilent.bpo.interceptor.Hashable" />
</jaxb:globalBindings>
Now I want only one type to subclass this class. I tried many selectors, but this is the only one that finds exactly one type:
<jaxb:bindings schemaLocation="../xsd/OrganisatieTypes.xsd" node="//xs:complexType[#name='DatumIncompleetType']">
<xjc:superClass name="nl.ilent.bpo.interceptor.Hashable" />
</jaxb:bindings>
Even though many alternatives gave a "0 nodes" result, and this one does not, the generated class does not subclass Hashable. What am I doing wrong?
This is the XSD defining the complexType in ../xsd/OrganisatieTypes.xsd:
<xsd:complexType name="DatumIncompleetType">
<xsd:choice minOccurs="0">
<xsd:element name="datum" type="xsd:date"/>
<xsd:element name="jaarMaand" type="xsd:gYearMonth"/>
<xsd:element name="jaar" type="xsd:gYear"/>
</xsd:choice>
</xsd:complexType>
We are using CXF 2.7.18
Try this way
<jaxb:bindings schemaLocation="../xsd/OrganisatieTypes.xsd" node="/xs:schema">
<jaxb:bindings>
<jaxb:bindings node="//xs:complexType[#name='DatumIncompleetType']">
<xjc:superClass name="nl.ilent.bpo.interceptor.Hashable" />
</jaxb:bindings>
</jaxb:bindings>
</jaxb:bindings>
Edit
Ok, sorry, that won't work: according to https://docs.oracle.com/cd/E17802_01/webservices/webservices/docs/2.0/jaxb/vendorCustomizations.html#superclass this is only possible for global bindings, i.e. for all generated classes, not for single generated classes

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>

Categories