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
Related
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;
My application is calling a webservice and I have generated the Java classes from the WSDL/XSDs with the maven-jaxb2-plugin. The webservice calls worked fine for a while but recently I had a problem on marshalling an object into XML:
[org.xml.sax.SAXParseException: cvc-complex-type.2.4.d: Invalid content was found starting with element 'ns1:TheFooAndBarThing'.
No child element '{"http://www.myschemanamespace.xyz/v1":BarId}' is expected at this point.]
The XSD part looks like this:
<xs:complexType name="TheFooAndBarThing">
<xs:sequence>
<xs:element name="FooId" minOccurs="1" maxOccurs="1" type="nx:FooIdType"/>
<xs:element name="BarId" minOccurs="1" maxOccurs="100" type="nx:BarIdType"/>
</xs:sequence>
</xs:complexType>
The generated class TheFooAndBarThing looks like this (Javadoc removed):
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "TheFooAndBarThing", propOrder = {
"fooId",
"barId"
})
public class TheFooAndBarThing {
#XmlElement(name = "FooId", required = true)
protected String fooId;
#XmlElement(name = "BarId", required = true)
protected List<String> barId;
public String getFooId() {
return fooId;
}
public void setFooId(String value) {
this.fooId = value;
}
public List<String> getBarId() {
if (barId == null) {
barId = new ArrayList<String>();
}
return this.barId;
}
}
It cost me some time and coffee to find out the real problem. My mistake was that I put more than 100 BarId elements in my list.
So here's my question:
How can I get the maxOccurs/minOccurs value from the XSD into my Java code so that I can use it as a max/min value while building my list of elements?
Short answer: there is no easy way.
Schema-derived classes have no reference to the original schema anymore. Even if you use something as XSOM or whatever to parse the original schema, you will not be able to find corresponding XML Schema constructs to check.
The best way to address the issue would be writing a custom XJC plugin (I wrote quite a few of them).
When XJC compiles the schmema it first creates a model, then a so-called outline (pre-rendered code) and then renders the code. The model still has information about the original XML Schema constructs, so you can find all the relevant min/maxOccurs information there.
The problem is just that you don't always have 1:1 mapping between schema constructs and properties of schema-derived classes. Sometimes several elements are mapped onto one property. There's a huge number of exceptions and special cases. You can get it working for the straightforward cases, though. Anyway, the task is not easy.
Use could try JAXB-Facets.
Here is an example of setting specific values for minoccurs and maxoccurs:
#MinOccurs(value = 0)
#MaxOccurs(value = 100)
private List<String> test;
When generating Java beans from a XSD with XJC, I need to map xs:integer to Integer rather than BigInteger. I added a javaType tag to my JAXB customization file (as said in many answers from this site), and it worked fine.
But in the generated code I noticed that the #XmlElement tag now has a type=String.class parameter.
So now I wonder, why String?
Is it because the parse and print methods are converting from/to string objects?
I tried with xjc:javaType instead of jaxb:javaType, allowing me to replace the generated Adapter1<String, Integer> with a custom MyAdapter<BigInteger, Integer>, but exactly the same thing happened.
If this is normal XJC behavior, is it possible to tweak it to generate code without this parameter, or with another value than String?
Note that everything is working fine, but I would like to understand.
Also I'm using Enunciate to document my API and it seems to be confused by this type thing (but this is probably a bug in Enunciate).
I'm using JAXB RI 2.2.6, and here are some pieces of code, to illustrate my question:
bindings.xjb
<jaxb:bindings version="2.0" ...>
<jaxb:globalBindings>
<jaxb:javaType
name="java.lang.Integer"
xmlType="xs:integer"
parseMethod="..."
printMethod="..." />
</jaxb:globalBindings>
</jaxb:bindings>
Field definition in the XSD
<xs:complexType name="MyType">
<xs:sequence>
<xs:element name="myField" type="xs:integer" />
</xs:sequence>
</xs:complexType>
Generated Java field
#XmlElement(namespace = "...", required = true, type = String.class)
#XmlJavaTypeAdapter(Adapter1.class)
#XmlSchemaType(name = "integer")
protected Integer myField;
I know this is an old question, but for the people still looking for an answer:
using type xs:int instead of xs:integer will create a normal java int instead of the Biginteger.
Where I work, we have a policy in place that states we should try to build web services "bottom-up" (code-first).
When doing this, how can I add restrictions within my XSD <types> WSDL element? For example, in the following:
import javax.jws.WebService;
import javax.xml.ws.BindingType;
#WebService
#BindingType(javax.xml.ws.soap.SOAPBinding.SOAP12HTTP_BINDING)
public class ProofOfConcept {
public String sayHello(String guest){
return "Hello "+guest;
}
}
The output in my WSDL is as such:
...
<xs:complexType name="sayHello">
<xs:sequence>
<xs:element minOccurs="0" name="arg0" type="xs:string" />
</xs:sequence>
</xs:complexType>
...
I would like to add both minLength and maxLength restrictions to the "guest" String. Is this possible to do through code as opposed to editing the WSDL directly?
I'm aware that I can use a custom class and annotate my fields with #XmlElement or #XmlAttribute to get a few customizations (name, required etc.), but nothing specific for something like a String (length etc.); is it possible to modify / extend those annotations to add support for something like length or pattern?
Thanks.
I find it interesting that your policy is to try to build Web services bottom-up as I recommend building Web services top-down in order to cleanly define the contract. At any rate...
I'm not aware of a specific solution using annotations and I see that you haven't found one in your search either. If you want to automate the process so as to avoid overwriting your changes to the schema every time you regenerate the WSDL you can add an XSL transform to the resulting WSDL to add these attributes. While not an ideal solution it should allow you to set the attributes and continue working.
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.