JAXB translate element name when marshalling/un-marshalling - java

I am generating a java class from xsd which is used in to marshal/un-marshal xml.
I have an element currently defined in my xsd as
<xs:element maxOccurs="1" minOccurs="0" name="versionLabel" type="xs:string"/>
which results in a java class containing
String versionLabel
and setters and getters, setVersionLabel()/getVersionLabel().
I want the incoming/outgoing xml element to be <version> and for that to translate to/from the java class property "versionLabel". How do I do define that behavior in the xsd?

add #XmlElement annotation to the attribute and update your xsd if it used for any validation
#XmlElement(name = "version")
String versionLabel;

Related

JAXB-WS: XmlElement and WebParam

I'm trying to make a web method parameter required. I'm using JAXB2.2, so I can use the XmlElement annotation on params. The problem is that in the generated wsdl I can still have minOccurs=0.
#WebMethod(operationName = "retrieve")
#WebResult(name = "response")
public RetrieveWrapper retrieve(#WebParam(name = "name") #XmlElement(nillable=false, required=true) String name) {
And in the generated wsdl I have this:
<xs:complexType name="retrieve">
<xs:sequence>
<xs:element name="name" type="ns1:String" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
Any advice please? What I am missing?
The "name" in your complexType "retrieve" is optional.
You probably have a Class that corresponds to "retrieve" with a field "name" on which you didn't define "required=true". But that's not what you want.
I think your wsdl is correct for what you want, check your wsdl you should have and other element "name" which corresponds to your webparam and is required (no "minoccurs").

how to customize and override jaxb bindings

I am working with a set of DTDs from a third party system. Our goal is to map the XML request (which conforms to those DTDs into java and then, send an XML response back to the system).
DTDs are written in stone (I don't have any control in changing those).
So, in order to map, I converted DTDs to XML Schemas (xsd) using XMLSpy and then, created Jaxb binding classes using XJC compiler. I am using Java 7.
The problem is, the DTDs don't really have a namespace.. and I have 20 different DTDs.. 10 for request and 10 for response. When I generated the schemas, I had to do one-one mapping.. and created the same 10 request XSDs and 10 response XSDs.
Now, the jaxb xjc compiler generated binding classes.. but they are far from practical use. There is no inheritance 'cus these schemas are not related to each other (although they seem to have similar content - request types and response types).
Can someone please help me if there is a way to customize jaxb bindings to override the default bindings and create more reasonable bindings?
For example consider this simple case:
DTD:
<!ELEMENT FromDate (#PCDATA)>
<!ATTLIST FromDate
year CDATA #REQUIRED
month CDATA #REQUIRED
day CDATA #REQUIRED
>
Schema that I generated using XMLSpy:
<xs:element name="FromDate">
<xs:complexType mixed="true">
<xs:attribute name="year" use="required"/>
<xs:attribute name="month" use="required"/>
<xs:attribute name="day" use="required"/>
</xs:complexType>
</xs:element>
The binding classes that generated out of XJC compiler (java 1.7):
public class FromDate {
#XmlValue
protected String content;
#XmlAttribute(name = "year", required = true)
#XmlSchemaType(name = "anySimpleType")
protected String year;
#XmlAttribute(name = "month", required = true)
#XmlSchemaType(name = "anySimpleType")
protected String month;
#XmlAttribute(name = "day", required = true)
#XmlSchemaType(name = "anySimpleType")
protected String day;
...
...
If you look at how fromDate finally evolved, it doesn't make any sense 'cus just to get the date from this request, I need to do
setMyDate(request.getFromDate().getMonth() + request.getFromDate().getDay() + request.getFromDate().getYear());
which obviously doesn't make sense. Plus, the types are way off.
How can I customize/override jaxb bindings to achieve these two things:
1. inheritance (some kind of abstraction to reduce redundancy)
2. appropriate types
Please help.
OMG someone tries to compile DTDs in 2014. :)
Few links for you:
https://jaxb.java.net/guide/Compiling_DTD.html
http://xml.coverpages.org/jaxb0530spec.pdf - see ยง6 for customizations syntax
https://svn.java.net/svn/ogc~svn/ogc-schemas/trunk/wms/1.1.0/ - Maven project that compiles a DTD
As another approach I'd suggest converting DTDs to schemas an processing schemas. Will be better long-term. DTD support is quite limited

schemagen: How to share classes, but not their namespaces?

I have two top-level classes which share a third class by composition. Example:
#XmlRootElement
#XmlType(namespace = "http://example.com/foo")
public class Foo {
public Shared shared;
}
#XmlRootElement
#XmlType(namespace = "http://example.com/bar")
public class Bar {
public Shared shared;
}
public class Shared {
public String string;
}
Each of these classes is assigned to a different package in a different compilation unit (module).
Now when I use schemagen on each top level class, I would like the Shared class to have the same name space than the top level class. So the output for Foo should look like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="foo" type="Foo"/>
<xs:complexType name="Foo">
<xs:sequence>
<xs:element name="shared" type="Shared" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="Shared">
<xs:sequence>
<xs:element name="string" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
However, it doesn't work like this. Instead the Shared class has the default namespace and so I get two schema files, one for the namespace of Foo and one for the namespace of Shared.
Is there a way to fix this without the obvious solution to duplicate the Shared class and thus, not sharing it anymore?
If the shared class should have the same name space as the top level class you have to duplicate it. If you really want to share it, it must be defined in a third XSD and imported into the two top-level XSDs. So the result for Foo should rather look like:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://www.example.org/schema/foo"
xmlns:shared="http://www.example.org/schema/shared"
targetNamespace="http://www.example.org/schema/foo">
<xs:import namespace="http://www.example.org/schema/shared" schemaLocation="http://www.example.org/schema/shared/shared.xsd"/>
<xs:element name="foo" type="Foo"/>
<xs:complexType name="Foo">
<xs:sequence>
<xs:element name="shared" type="shared:Shared" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
The XSD for Shared can then be imported into both top level XSDs. If your Shared XSD is located in a separate project you might need a catalog file to specify its location:
PUBLIC "http://www.example.org/schema/shared" "../../../../shared/src/main/xsd/shared.xsd"
I am always using contract-first, i.e. create the XSD and let JAXB generate the classes. You are using schemagen to generate the XSD based on the classes. Just in case you are using the jaxb2-maven-plugin I found a Parameter transformSchemas which sounds like it is doing what you need. It lets you specify schema mappings and writes xs:import statements into the resulting XSD. I did not try it, but I hope it helps.
After investigating the issue and elaborating the options, I have decided to change the design and use one and only one namespace for all my classes. Here's the rationale:
The relationship between a class and a namespace is naturally one to one. Even if I manually mock-up an XSD so that my instance document properly validates, the JAXB unmarshaller ignores elements which belong to a name space which doesn't match, so hacking the XSD doesn't help at all.
I can easily reuse the same namespace over multiple packages and compilation units. The class path just needs to be set up correctly, which Maven will do for me when using the jaxb2-maven-plugin.
I can easily associate all my classes with one namespace and still have different XSD files for each top-level element. The advantage is that each output XSD file contains only the classes (i.e. complex types) which are referenced from the included root element classes when running schemagen.
After making this change, I get one XSD file per compilation unit. Each compilation unit contains exactly one root element (i.e. class). Each root element references only the complex types which are strongly reachable through the class representing the root element. This is exactly what I wanted.

How can we have minOccurs="1" for a String?

I am using Apache CXF for Web service development . We have written Java code and the WSDL will be automatically generated by the CXF Engine
I have a String named xmlMessage which must have minoccurs set to 1
For this I used:
private String xmlMessage ;
#XmlElement(name = "xmlMessage", required = true)
public String getXmlMessage()
{
return xmlMessage;
}
But when the WSDL File got generated , it still showed as
<xs:element minOccurs="0" name="xmlMessage" type="xs:string"/>
Please tell me how can i have minOccurs="1" for a Input Message .
This seems to be a bug.
The sun api defines required as:
Customize the element declaration to be required.
If required() is true, then Javabean property is mapped to an XML schema element declaration with minOccurs="1". maxOccurs is "1" for a
single valued property and "unbounded" for a multivalued property.
If required() is false, then the Javabean property is mapped to XML Schema element declaration with minOccurs="0". maxOccurs is "1"
for a single valued property and "unbounded" for a multivalued
property.
Default: false
Might be this bug, don't know if your version is a new one.

Creating a custom JAXB annotation

Do people have any recommendations on how i could write my own custom JAXB annotation handling class to support the generation of xs:annotation/xs:documentation elements in the xsd schema?. I'd like to create a new java annotation "#XmlAnnotation" which would include a "documentation" attribute. I'd then make these classes available to the JAXB schema generator via the classpath. The schema generator would then take this sample java code
#XmlRootElement(name="ClientData")
public class ClientData {
/**
* The first address field of the person
*/
#XmlAnnotation(documentation="The first address field of the client")
private String address1 = null;
}
and create this xsd schema
<xs:complexType name="clientData">
<xs:sequence>
<xs:element minOccurs="0" name="address1" type="xs:string">
<xs:annotation>
<xs:documentation>The first address field of the client</xs:documentation>
</xs:annotation>
Would it be easier to extend from the existing #XmlElement annotation class, and just add support of an extra documentation attribute?
This XmlRootElement is almost empty ( http://docjar.org/src/api/javax/xml/bind/annotation/XmlRootElement.java, there is not 'active' code inside
The main modification would be to change the code using this annotation and generating the xsd file.
That would only allow the construct for the root element. It is valid in just about ALL the xs namespace elements.
I don't understand why it wasn't supported as standard.

Categories

Resources