generated XSD From Java use moxy - jaxb

#XmlRootElement
public class OtherClass {
#XmlAttribute
private String other;
}
#XmlRootElement
public class Simple extends OtherClass {
#XmlAttribute
private String id;
#XmlValue
public String contents;
}
JAXBContext context = JAXBContext.newInstance(OtherClass.class,Simple.class);
System.out.println(context);
System.out.println("org.eclipse.persistence.Version:"+Version.getVersionString());
context.generateSchema(new MySchemaOutputResolver());
System.out.println(sw);
Use woxy generated XSD results
org.eclipse.persistence.jaxb.JAXBContext#1292d26
org.eclipse.persistence.Version:2.5.0.v20130425-368d603
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:complexType name="otherClass">
<xsd:sequence/>
<xsd:attribute name="other" type="xsd:string"/>
</xsd:complexType>
<xsd:complexType name="simple">
<xsd:simpleContent>
<xsd:extension base="xsd:string">
<xsd:attribute name="id" type="xsd:string"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
<xsd:element name="otherClass" type="otherClass"/>
<xsd:element name="simple" type="simple"/>
</xsd:schema>
sample/other no inheritance in xsd, but there is in java
Excuse me, if to solve the problem? Here I thank you first

Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.
What the Mappings Mean
With MOXy as your JAXB provider (see: http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html) you can use the folllowing code:
import java.io.File;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Simple.class, OtherClass.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum18029865/input.xml");
Simple simple = (Simple) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(simple, System.out);
}
}
to convert the following XML to/from your Java objects:
<?xml version="1.0" encoding="UTF-8"?>
<simple id="foo" other="bar">Hello World</simple>
How the Mappings Relate to XML Schema
The classes as you have mapped them don't have a real representation in XML schema. Since you have used the #XmlValue annotation the resulting type will extend xsd:string, but you have also indicated that it should extend the complex type corresponding to OtherClass.
What the JAXB Reference Implemenetation Does
For the exact same mappings the JAXB RI will through an exception when creating the JAXBContext. Since this representation is not allowed in the XML schema, they decide not to allow it in the mappings. I prefer the option we chose in MOXy where still support the mapping.
Exception in thread "main" com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
#XmlValue is not allowed on a class that derives another class.
this problem is related to the following location:
at public java.lang.String forum18029865.Simple.contents
at forum18029865.Simple
at com.sun.xml.bind.v2.runtime.IllegalAnnotationsException$Builder.check(IllegalAnnotationsException.java:102)
at com.sun.xml.bind.v2.runtime.JAXBContextImpl.getTypeInfoSet(JAXBContextImpl.java:472)
at com.sun.xml.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:302)
at com.sun.xml.bind.v2.runtime.JAXBContextImpl$JAXBContextBuilder.build(JAXBContextImpl.java:1140)
at com.sun.xml.bind.v2.ContextFactory.createContext(ContextFactory.java:154)
at com.sun.xml.bind.v2.ContextFactory.createContext(ContextFactory.java:121)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:248)
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:235)
at javax.xml.bind.ContextFinder.find(ContextFinder.java:432)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:637)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:584)
at forum18029865.Demo.main(Demo.java:9)

Related

JAXB XmlAdapter via bindings file

Consider this XSD:
<xsd:schema targetNamespace="http://foobar" xmlns:tns="http://foobar"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:complexType name="IdAttribute">
<xsd:attribute name="id" type="xsd:token" />
</xsd:complexType>
<xsd:complexType name="FoobarType">
<xsd:sequence>
<xsd:element name="someIds" type="tns:IdAttribute" maxOccurs="unbounded" />
</xsd:sequence>
</xsd:complexType>
<xsd:element name="Foobar" type="tns:FoobarType" />
</xsd:schema>
which results in the following, generated Java class:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "FoobarType", propOrder = {"someIds"})
public class FoobarType {
#XmlElement(required = true)
protected List<IdAttribute> someIds;
// ...
}
Because IdAttribute only contains one String (id), I want to map these Strings directly into my FoobarType for easier usage. Therefore I wrote an XmlAdapter:
public class IdAttributeAdapter extends XmlAdapter<IdAttribute, String> { ... }
I've edited the generated class manually to verify my XmlAdapter works as expected (it does):
#XmlElement(required = true)
#XmlJavaTypeAdapter(IdAttributeAdapter.class)
protected List<String> someIds;
Of course I want to have this little code change done during code generation, so I've added the following bindings file (src/main/xjb/bindings.xjb):
Attempt 1:
<jaxb:bindings version="2.0" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/jaxb http://java.sun.com/xml/ns/jaxb/bindingschema_2_0.xsd">
<jaxb:bindings schemaLocation="../resources/xsd/foobar.xsd">
<jaxb:bindings node="//xsd:complexType[#name='IdAttribute']">
<xjc:javaType
name="java.lang.String"
adapter="org.foobar.IdAttributeAdapter" />
</jaxb:bindings>
</jaxb:bindings>
</jaxb:bindings>
Result
com.sun.istack.SAXParseException2; systemId: file:/C:/dev/foobar/src/main/xjb/bindings.xjb;
lineNumber: 12; columnNumber: 91;
compiler was unable to honor this conversion customization. It is attached to a wrong place, or its inconsistent with other bindings.
Attempt 2 (from here):
<jaxb:globalBindings xmlns:foo="http://foobar" xsi:schemaLocation="http://foobar ../resources/xsd/foobar.xsd">
<xjc:javaType
name="java.lang.String"
xmlType="foo:IdAttribute"
adapter="org.foobar.IdAttributeAdapter" />
</jaxb:globalBindings>
Result
com.sun.istack.SAXParseException2; systemId: file:/C:/dev/projects/luna/oasch/src/main/xjb/bindings.xjb;
lineNumber: 8; columnNumber: 112;
undefined simple type "{http://foobar}IdAttribute".
I've tried a few variations, but they all resulted in similar errors. So what's the correct way to add an XmlApender using a bindings file?
What you try to do is wrong.
You should replace fully the xml type IdAttribute with the java type String.
You will have to work with generic dom.Element type and convert it <-> String.
Here is an exemple : JAXB #XmlAdapter for arbitrary XML for your case replace the java type Bar with String.
Other solution would be to add behavior to the generated class so that you add methods to your FoobarType to work as if it has a List of String
e.g. add methods
List<String> getIds()
void setIds(List<String>)
Here is a link that explain how you can do this : "Adding behavior"

How to make JAXB unmarshaller use getters rather than fields

I have some classes generated automatically using maven-jaxb2-plugin and jaxbfx. The latter generates JAXB classes with getters and setters that should be called when marshalling and unmarshalling respectively. However, the JAXB marshaller and unmarshaller methods use fields instead of the getters and setters.
The following code shows an example of a class generated with jaxbfx.
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "MyType")
public class MyType{
#XmlAttribute(name = "id", required = true)
protected int id;
private final transient IntegerProperty idProxy = new SimpleIntegerProperty();
public void setId(int value) {
this.id = value;
this.idProxy.set(value);
}
public short getId() {
return this.idProxy.get();
}
public IntegerProperty idProperty() {
return this.idProxy;
}
}
Therefore, I would like to know whether it is possible to make the marshaller and unmarshaller use the getters and setters instead of the fields. Please note that I cannot change the JAXB annotations manually, since they are generated automatically.
A working solution follows:
Modify the jaxbfx to clear all JAXB annotations from generated classes: this is achieved by invoking method clearAllAnnotations(implClass) for every class to be generated
Install the the jaxb2-basics-annotate plugin.
Modify the xml schema (file.xsd) to add the #XmlElement annotation to any getter and setter method.
For example:
<xs:complexType name="MyType">
<xs:attribute name="id" type="xs:int" use="required">
<xs:annotation>
<xs:appinfo>
<annox:annotate target="setter">#javax.xml.bind.annotation.XmlAttribute(required=true,name="id")
</annox:annotate>
</xs:appinfo>
</xs:annotation>
</xs:attribute>
</xs:complexType>

Equivalent to #XmlElement.required in #XmlPath in EclipseLink MOXy

How to implement #XmlElement.required flag using #XmlPath annotation in EclipseLink MOXy 2.4.1 version?
You can use the #XmlElement(required=true) along with the #XmlPath annotation to specify that the leaf element is required.
Customer
Below is a sample domain model with two fields mapped with #XmlPath on one of them I've also used #XmlElement(required=true).
package forum13854920;
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlPath;
#XmlAccessorType(XmlAccessType.FIELD)
public class Customer {
#XmlPath("personal-info/first-name/text()")
private String firstName;
#XmlPath("personal-info/last-name/text()")
#XmlElement(required=true)
private String lastName;
}
jaxb.properties
To use MOXy as your JAXB provider you need to include a file called jaxb.properties in the same package as your domain model with the following entry:
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
XML Schema
Below is the XML schema that corresponds to the domain model. Note how the last-name element does not have minOccurs="0".
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:complexType name="customer">
<xsd:sequence>
<xsd:element name="personal-info" minOccurs="0">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="first-name" type="xsd:string" minOccurs="0"/>
<xsd:element name="last-name" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
Demo
The following demo code can be used to generate the XML schema.
package forum13854920;
import java.io.IOException;
import javax.xml.bind.*;
import javax.xml.transform.Result;
import javax.xml.transform.stream.StreamResult;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Customer.class);
jc.generateSchema(new SchemaOutputResolver() {
#Override
public Result createOutput(String namespaceURI, String suggestedFileName) throws IOException {
StreamResult result = new StreamResult(System.out);
result.setSystemId(suggestedFileName);
return result;
}
});
}
}
Currently EclipseLink JAXB (MOXy) does not have the equivalent of the required property on the #XmlElement annotation for the other segments of the path. If you are interested in this behaviour please enter an enhancement request using the link below:
https://bugs.eclipse.org/bugs/enter_bug.cgi?product=EclipseLink

JAXB generated classes: Ignore intermediate classes

Here is a extract from my XML schema:
<xsd:complexType name="MyType">
<xsd:sequence>
<xsd:element name="Numbers">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Number" minOccurs="1" maxOccurs="5" type="xsd:decimal"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
JAXB generates me the following class:
public class MyType {
protected MyType.Numbers numbers;
public static class Numbers {
protected List<BigDecimal> number;
}
}
But I'd like to ignore this intermediate class and have something like:
public class MyType {
protected List<BigDecimal> number;
}
Is that somehow possible?
Yes, that is possible with JAXB only with the help of external plugins, as this modification is actually change of the model. Have a look at #XmlElementWrapper plugin.
Note: The same question was already asked on this forum (How generate XMLElementWrapper annotation, Dealing with JAXB Collections, JAXB List Tag creating inner class). Please, use search first.

JAXB and validation against parts of a schema with schemagen?

A very generalized and simplified scenario description:
Application builds JAXB instances through UI,
The JAXB instances are built in different steps are composed in the end,
As this is done, I must perform validation of the JAXB instances created in each step against the XSD to verify that the UI tier does not build nonsense.
Now the schema defines complex types A, B and C. The schema specifies that XML document must have top level element A and this can contain multiple B and this can optionally include C. I create JAXB instance for B and absolutely want to validate this against the complex type definition in the XSD before nesting it under A. However validation of this will fail if I validate against the entire XSD.
Questions: How to validate JAXB instance against only a part of the XSD from which its class has been generated from?
How about using schemagen to generate schema from the JAXB class which instance I want to validate and then validate against that? Do you think that can work? Any other ideas?
I have no previous experience with schemagen and will start prototyping of this solution soon.
Note: in reality, the schemas are not as simple as in the above example and the solution of creating some always-valid mock of A is not feasible option. Not to mention that this kind of validation will be on hundred places to say the least.
create separate schema for element you want to validate, where this element is on root level.
to workaround missing #xmlRoottag see 101 ways to marshal objects with JAXB
Well it turns out that using xsi:type let's one accomplish this.
http://www.w3.org/TR/xmlschema-1/#xsi_type
While working with xjc and schemagen tools please consider same concept which we use in java. In java, every class is a skeleton and object is an instance. Same as we need to consider XSD as skeleton and XML as instance.
xjc tool:- Xsd to Java Class Or Unmarshaling
Consider the below XSD with namespaces for example. The xjc tool will generate the java class along with package-info and object-factory.
<?xml version="1.0" encoding="utf-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ir="http://irctc.org/service" targetNamespace="http://irctc.org/service">
<xsd:element name="Customer" type="ir:CustomerType"/>
<xsd:complexType name="CustomerType">
<xsd:sequence>
<xsd:element name="name" type="xsd:string"/>
<xsd:element name="src" type="xsd:string"/>
<xsd:element name="dest" type="xsd:string"/>
<xsd:element name="price" type="xsd:float" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
Use below command
D:\>xjc Customer.xsd
parsing a schema...
compiling a schema...
org\irctc\service\CustomerType.java
org\irctc\service\ObjectFactory.java
org\irctc\service\package-info.java
Note :- If you have multiple java class then you can use jaxb.index file instead of using ObjectFactory.java.
schemagen tool:- Java Class to Xsd Or Marshaling
Let us suppose we want to generate the Xsd file using java class then first we need to create the ObjectFactory.java Or jaxb.index file and package-info.java in the same package where we have the CustomerType.java.
package org.irctc.service;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
#XmlRootElement("Customer")
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "CustomerType", propOrder = {
"name",
"src",
"dest",
"price"
})
public class CustomerType {
#XmlElement(required = true)
protected String name;
#XmlElement(required = true)
protected String src;
#XmlElement(required = true)
protected String dest;
protected Float price;
public String getName() {
return name;
}
public void setName(String value) {
this.name = value;
}
public String getSrc() {
return src;
}
public void setSrc(String value) {
this.src = value;
}
public String getDest() {
return dest;
}
public void setDest(String value) {
this.dest = value;
}
public Float getPrice() {
return price;
}
public void setPrice(Float value) {
this.price = value;
}
}
Use below command
D:\>schemagen org.irctc.service.CustomerType
Note: Writing D:\schema1.xsd
The above command will generate the xsd file. The package of java class will considered as xsd namespaces.
The above details are only for understanding marshaling and unmarshaling process using tools in Jax-B API.
For more details , check below examples
Jax-B Hello World Example
Java-XML mapping with Jax-B 2.0

Resources