Is there's a way to have extra methods in an class generated with JAXB ... To be more specific I would like make changes in my .xsd files and not code some methods in a "first.java" class and then make my .xsd generated classes inherit from "first.java" .. My goal is to modify only my .jaxb file .. so can we create methods with .xsd ?
I have an ".xsd" file that generates a class. And I want to know if it's possible to add to this generated class some other methods besides the getters and setters.
I search around tutorials and some StackOverflow topics but I didn't find instructions on how can I add custom methods to a generated class described on XML Schema.
Here's my .xsd file :
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb" jxb:version="2.1">
<xs:element name="Myclass" />
<xs:complexType name="Myclass">
<xs:complexContent>
</xs:complexContent>
</xs:complexType>
</xs:schema>
And here's the class generated with this .xsd file :
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "Myclass")
public class Myclass
{
}
Here's an example of a class that I want to generate with
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "Myclass")
public class Myclass
{
public String method(){
return "Hello";
}
}
Thank's in advance :)
If you receive the XSDs from a client and they can change often, I would recommend not making changes to the XSDs as a design decision. I would recommend the java route as mentioned on the JAXB documentation:
https://javaee.github.io/jaxb-v2/doc/user-guide/ch03.html#compiling-xml-schema-adding-behaviors
Related
I am using JAXB, I have xsd files which I cannot modify which has elements with
minOccurs="0" nillable="true"
Which results that in the generated ObjectFactory class I have a lot of code like:
JAXBElement<SomeObject>
Then the code, that I have to write to both marshall and unmarshall is boilerplate and ugly.
Is there a way to generate somehow automaticaly another layer of abstraction so that I would have some other ObjectFactory class as well, but it would not operate on JAXBElement but instead would have it wrapped in some methods? Like it is when in the binding.xjb you specify the following:
<jaxb:globalBindings localScoping="toplevel" generateElementProperty="false">
which is unfortunately not an option for me.
I have xsd schema and my classes are generated from that schema.
I need XmlAdapter for correct marshaling/unmarshalling of some types.
I created such adapter (e.g MyAdapter), but I can't just add it via #XmlJavaTypeAdapter(MyAdapter.class) because my classes are generated from the scheme.
Is it possible to generate class from scheme with adapter defined ?
e.g I have scheme - > I want
#XmlType(name = "someName")
#XmlEnum
#XmlJavaTypeAdapter(MyAdapter.class)
public enum MyGeneratedClass {
// ...
}
XJC is used to create Java classes from scheme.
Try to use <xs:annotation>
For instance :
<xs:simpleType name="myType">
<xs:annotation>
<xs:appinfo>
<xjc:javaType name="com.seriouscompany.seriousproduct.MyType"
adapter="com.seriouscompany.seriousproduct.MyAdapter" />
</xs:appinfo>
</xs:annotation>
....
This should help.
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.
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.