JAX-WS service implementation class name customization not working - java

I'm using Maven to generate the implementation code for a web service. Originally, this code was generated from a WSDL and schema using something else (probably a wizard in Eclipse). The service implementation class name that jaxws-maven-plugin generates is MyService_MyServieSOAPImpl. When this was originally generated, the implementation class was named MyService_SOAPImplementation. I'm guessing that the wizard that Eclipse uses allows the user to choose the name of the implementation class. I tried using the sei element, but it does not work. Here's a snippet of the wsimport plugin in my POM:
<plugin>
<groupId>org.jvnet.jax-ws-commons</groupId>
<artifactId>jaxws-maven-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<phase>generate-sources</phase>
<id>generateMyServiceFromWSDL</id>
<goals>
<goal>wsimport</goal>
</goals>
<configuration>
<genJWS>true</genJWS>
<bindingDirectory>${basedir}/src/main/bindings</bindingDirectory>
<bindingFiles>
<bindingFile>otherSchema.episode</bindingFile>
</bindingFiles>
<wsdlDirectory>${basedir}/src/main/resources/wsdl</wsdlDirectory>
<wsdlFiles>
<wsdlFile>MyService.wsdl</wsdlFile>
</wsdlFiles>
<wsdlLocation>${project.basedir}/src/main/resources/wsdl/MyService.wsdl</wsdlLocation>
<sourceDestDir>${project.basedir}/src/main/java</sourceDestDir>
<sei>com.myCompany.MyService_SOAPImplementation</sei>
<xdonotoverwrite>true</xdonotoverwrite>
<xnocompile>true</xnocompile>
<xdebug>true</xdebug>
<verbose>true</verbose>
<target>2.0</target>
</configuration
</execution>
...
From some of the documents I've read, it looks like sei is only applicable for wsgen, not wsimport. If that is so, is there any way to force a name for the implementation class name?
UPDATE
Ok, so from my reading, it should be possible to do this with a JAX-WS binding file, not directly in the POM file.
I've created my binding file like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<jaxws:bindings version="2.1" xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xmlns:jaxws="http://java.sun.com/xml/ns/jaxws"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
jaxws:wsdlLocation="src/main/webapp/wsdl/MyService.wsdl">
<jaxws:bindings node="wsdl:definitions/wsdl:portType[#name='MyService']">
<!-- change the generated SEI class -->
<jxb:class name="MyServiceSOAPImpl"></jxb:class>
</jaxws:bindings>
</jaxws:bindings>
But this still doesn't seem to have any effect - wsimport is still producing the implementation as MyService_MyServiceSOAPImpl.

Try changing your
<jaxws:bindings node="wsdl:definitions/wsdl:portType[#name='MyService']">
to
<jaxws:bindings node="wsdl:definitions/wsdl:service[#name='MyServiceService']">
Note that the second part of the node path is service and not portType. You would use portType to customize the service interface, not the implementation.
As an aside it's important to note that JAX-WS bindings (seemingly) need to be in their own XML file (per WSDL) and not included with JAXB bindings.
Someone may find the list of JAX-WS bindings here to be useful: http://docs.oracle.com/cd/E13222_01/wls/docs103/webserv/data_types.html#wp227312

In case this helps someone, two changes are required in OPs bindings.xml file to get it to work:
The first change was already suggested by MGE - changing the wsdl:portType in the Xpath to wsdl:service
The namespace for class name has to be 'jaxws', so
change to this:
<jaxws:class name="MyServiceSOAPImpl"/>
from
<jxb:class name="MyServiceSOAPImpl"></jxb:class>

Related

JAXB/Maven JAX-WS: global bindings.xml references particular WSDL

I'm using Maven JAXWS plugin and bindings.xml file to override a Java type for a JAXB class field generated from a WSDL, but have a problem when generating Java classes from multiple WSDLs with the JAX-WS Maven plugin.
My project structure is:
- src
- jaxws
- bindings.xml
- main
- resources
- wsdl
- Wsdl1.wsdl
- Wsdl1.xsd
- Wsdl2.wsdl
- Wsdl2.xsd
Wsdl1.wsdl references Wsdl1.xsd, Wsdl2.wsdl references Wsdl2.xsd, the two WSDLs and XSD have nothing in common. The WSDLs and XSDs cannot be modified by me.
I want to override the Java type of a particular field (departureDate) in a particular type (Flight) in Wsdl2.xsd.
My bindings.xml is
<bindings version="2.0" extensionBindingPrefixes="xjc"
xmlns="http://java.sun.com/xml/ns/jaxb"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<globalBindings>
<xjc:javaType name="org.joda.time.LocalDate" xmlType="xs:date"
adapter="my.LocalDateAdapter"/>
<xjc:javaType name="org.joda.time.DateTime" xmlType="xs:dateTime"
adapter="my.DateTimeAdapter"/>
</globalBindings>
<bindings schemaLocation="../main/resources/wsdl/Wsdl2.xsd" node="/xs:schema">
<bindings node="//xs:complexType[#name='Flight']//xs:element[#name='departureDate']">
<xjc:javaType name="org.joda.time.LocalDateTime"
adapter="my.LocalDateTimeAdapter"/>
</bindings>
</bindings>
</bindings>
My Maven configuration is
<plugin>
<groupId>org.jvnet.jax-ws-commons</groupId>
<artifactId>jaxws-maven-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<goals>
<goal>wsimport</goal>
</goals>
<configuration>
<wsdlDirectory>${basedir}/src/main/resources/wsdl</wsdlDirectory>
</configuration>
</execution>
</executions>
</plugin>
When I build the module with that configuration, JAX-WS processes the WSDLs one by one, but uses the same bindings.xml for each of them. That way, it fails during processing of Wsdl1 due to the reference to Wsdl2.xsd in bindings.xml.
[INFO] --- jaxws-maven-plugin:2.2:wsimport (default) # my-backend ---
[INFO] Processing: file:/D:/dev/Projects/my-api/my-backend/src/main/resources/wsdl/Wsdl1.wsdl
[INFO] jaxws:wsimport args: [-keep, -s, D:\dev\Projects\my-api\my-backend\target\generated-sources\wsimport, -encoding, UTF-8, -Xnocompile, -b, D:\dev\Projects\my-api\my-backend\src\jaxws\bindings.xml, file:/D:/dev/Projects/my-api/my-backend/src/main/resources/wsdl/Wsdl1.wsdl]
parsing WSDL...
[ERROR] "file:/D:/dev/Projects/my-api/my-backend/src/main/resources/wsdl/Wsdl2.xsd"
is not a part of this compilation. Is this a mistake for "file:/D:/dev/Projects/my-api/my-backend/src/main/resources/wsdl/Wsdl1.wsdl#types?schema1"?
line 11 of file:/D:/dev/Projects/my-api/my-backend/src/jaxws/bindings.xml
If I select just Wsdl2.wsdl for processing by the JAX-WS plugin, then all works fine.
<configuration>
<wsdlDirectory>${basedir}/src/main/resources/wsdl</wsdlDirectory>
<wsdlFiles>
<wsdlFile>Wsdl2.wsdl</wsdlFile>
</wsdlFiles>
</configuration>
How can I solve this issue?
Create one execution of wsimport for all the WSDLs except Wsdl2.wsdl and another execution for Wsdl2.wsdl. This way you can have different configurations for each execution and specify the jaxb bindings for each differently.

Getting a list of JAXBElement where I want a list of predefined java objects

I use Apache Camel + JAXB for Soap processing. The java glasses are generated by a maven plugin called cxf-codegen-plugin.
The Problem I am facing is that when I want to use a property which is a list. In that case I will always get a list of JAXBElement instead of objects of the correct class.
Assume this given xml snipped:
<domainObjects avqxsi:type="avqsq:AssetAllocation" id="100" name="Some Name">
<nodes>101</nodes>
<nodes>102</nodes>
</domainObjects>
Now all the "nodes" are ids of different domain objects of type AANode. So in the xsd it is defined like so:
<xsd:complexType name="AssetAllocation">
<xsd:complexContent>
<xsd:extension base="avqsq:DomainObject">
<xsd:sequence>
<xsd:element ecore:reference="avqsq:AANode" maxOccurs="unbounded" name="nodes" type="xsd:IDREF"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
And I have defined some bindings.xml:
<jaxb:bindings node="xsd:complexType[#name='AssetAllocation']//xsd:element[#name='nodes']">
<jaxb:property>
<jaxb:baseType name="my.api.xsd.AANode"/>
</jaxb:property>
</jaxb:bindings>
What I want is a POJO property like this:
#XmlElementRef(name = "nodes")
protected List<AANode> nodes;
But what I actually get at runtime is a List<JAXBElement<AANode>> which leads into a ClassCastException.
EDIT 1:
I have missed the fact that the cxf-codegen framework is generating a class where you clearly can see that the property is annotated with JAXBElement.class which i think is wrong. Interestingly changing the annotation by hand to AANode.class will fail with an IllegalAnnotationException: AANode" or any of its subclasses are not known to this context.
public class AssetAllocation
extends DomainObject
implements Serializable, Equals, HashCode, ToString
{
#XmlElementRef(name = "nodes", type = JAXBElement.class)
protected List<AANode> nodes;
apache CXF code gen plugin will always generate codes with JAXBElement until you set the generate element property flag.
Please create Jaxb binding.xml and refer that binding xml in your code gen plugin section from pom file as below
binding.xml
<?xml version="1.0" encoding="UTF-8"?>
<jaxb:bindings version="2.0"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb">
<jaxb:bindings>
<jaxb:globalBindings generateElementProperty="false"/>
</jaxb:bindings>
</jaxb:bindings>
code gen plugin
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-codegen-plugin</artifactId>
<version>3.1.1</version>
<executions>
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase>
<goals>
<goal>wsdl2java</goal>
</goals>
<configuration>
<wsdlOptions>
<wsdlOption>
<wsdl>${basedir}/src/main/resources/META-INF/wsdl/CxfExampleService.wsdl</wsdl>
<bindingFiles>
<bindingFile>${basedir}/src/main/resources/META-INF/wsdl/binding/bindings.xml</bindingFile>
</bindingFiles>
</wsdlOption>
</wsdlOptions>
</configuration>
</execution>
</executions>
</plugin>
This will resolve the issue
In fact the wsdl2java generates classes with wrong annotations. Instead of
#XmlElementRef(name = "nodes", type = JAXBElement.class)
protected List<AANode> nodes;
One would expect to have:
#XmlIDREF
protected List<AANode> nodes;
I was not able to manage this by bindings.xml. So my final solution is that I use a Byte-Code manipulation to fix the annotations. That way I do not have to mess around with the generated classes or with the generator itself.

Enunciate reporting - How to Exclude few APIs and include few APIs from a same class

I would like to exclude few API methods in a class from Enunciate documentation.
Is there a way to achieve it using enunciate ?
Thanks in Advance
Enunciate 1.27 has a feature "Facet"(http://docs.codehaus.org/display/ENUNCIATE/Enunciate+API+Facets) which helps in achieving the above.
Requires following changes
1.) pom.xml
Added the plugin
<plugin>
<groupId>org.codehaus.enunciate</groupId>
<artifactId>maven-enunciate-plugin</artifactId>
<version>1.27</version>
<executions>
<execution>
<goals>
<goal>assemble</goal>
</goals>
</execution>
</executions>
</plugin>
2.) In the API Method you want to exclude, add Facet annotation like below
#GET
#Path("/{memberId}")
#Produces(APPLICATION_JSON)
#Facet(name = "external")
3.) Change enunciate xml to refer to 1.27 enunciate xsd
4.) Add Facets tag in your enunciate xml
<facets>
<exclude name ="external"/>
</facets>
Result - Enunciate report excludes selected APIs methods in class "A" and includes the rest.

Why does JAXB say "xxx is an interface, and JAXB can't handle interfaces". Even though the generated class is not an interface

I used JAXB to bind my xsd's and then tried creating the JAXBContext:
JAXBContext jaxbContext = JAXBContext.newInstance("my package name");
But JAXB gives 180 IllegalAnnotationsException.
Most of the exceptions have the following messages:
XXX is an interface, and JAXB can't handle interfaces
XXX does not have a no-arg default constructor
#XmlAttribute/#XmlValue need to reference a Java type that maps to text in XML.
When I look at the classes generated none of them are interfaces and I can't understand why JAXB is interpreting them as interfaces.
Here's is the stack trace of one of the errors reported by JAXB :
com.sc.md.datatypes.schemas.csemessage.EnvelopeType is an interface, and JAXB can't handle interfaces.
this problem is related to the following location:
at com.sc.md.datatypes.schemas.csemessage.EnvelopeType
at protected com.sc.md.datatypes.schemas.csemessage.EnvelopeType com.sc.md.datatypes.schemas.csemessage.cseMessage.envelope
at com.sc.md.datatypes.schemas.csemessage.cseMessage
com.sc.md.datatypes.schemas.csemessage.EnvelopeType does not have a no-arg default constructor.
this problem is related to the following location:
at com.sc.md.datatypes.schemas.csemessage.EnvelopeType
at protected com.sc.md.datatypes.schemas.csemessage.EnvelopeType com.sc.md.datatypes.schemas.csemessage.cseMessage.envelope
at com.sc.md.datatypes.schemas.csemessage.cseMessage
And this is how the type is defined in xsd :
<xs:complexType name="EnvelopeType">
<xs:sequence>
<xs:element name="Sent" type="DateTimeType"/>
<xs:element name="Identifier" type="String_1_14"/>
<xs:element name="AcknowledgementCode" type="AcknowledgementCodeType"/>
</xs:sequence>
<xs:simpleType name="AcknowledgementCodeType">
<xs:restriction base="xs:string">
<xs:enumeration value="m"/>
<xs:enumeration value="p"/>
</xs:restriction>
</xs:simpleType>
Here is the pom.xml I have used to generate the binding :
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.cs</groupId>
<artifactId>cs-jaxb</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.2.4-1</version>
</dependency>
</dependencies>
<name>cs jaxb</name>
<version>1.0.0</version>
<parent>
<artifactId>hip-jaxb-parent</artifactId>
<groupId>com.cs</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<build>
<defaultGoal>install</defaultGoal>
<plugins>
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<version>0.8.0</version>
<executions>
<execution>
<id>CS</id>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<schemaDirectory>src/main/resources/</schemaDirectory>
<schemaIncludes>
<include>**/*.xsd</include>
</schemaIncludes>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<inherited>true</inherited>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>
Please be patient with me since its the first time I'm asking a question on the web :)
Thanks to all, it was as usual a big mistake on my part, but anyways I enjoyed using stackoverflow for the first time and will make a point to snoop around here.
The problem was with my classpath.I was referring to a xmlbeans binding project, which had the java source with the same package and classes as the ones generated by jaxb, which were included as a jar on my classpath.
So I had 2 classes with same name and package, but to my misery JAXB was picking the Xmlbeans class and I didn't realise that for 2 days.This is one of the oldest errors in Java and I apologise for the blunder.If anyone needs any clarification please drop a comment.
Have you annotated all root classes with the #XmlRootElement annotation?
See: Unofficial JAXB Guide - Mapping interfaces - Java.net
Second, I would recommend you not to create your JAXBContext via JAXBContext.newInstance("my package name");. It is better to specify the root classes explicitly. Therefore if you have two root classes named ClassA and ClassB use it this way:
JAXBContext.newInstance(new Class[] {ClassA.class, ClassB.class});
I suspect that you are trying to use a JAXB 1 (JSR-31) model with a JAXB 2 (JSR-222) runtime. In JAXB 1 implementations generated spec defined interfaces backed by implementation specific impl clases. In JAXB 2 this became spec defined classes with standard annotations that are compatible with all implementations. Most JAXB 2 implementations support their own JAXB 1 models, but some additional config may be necessary, if you try to use a JAXB 1 model with a difference JAXB 2 provider you may see this type of error.

WADL Generation Tool

Is there a tool which takes a Java File what describes a REST service as a parameter and generates a wadl file out of that.
I had the same problem: was using RESTeasy and wanted to find a way to generate the WADL automatically.
Did some research and came to the solution below.
1. Add this to your pom.xml:
<build>
<plugins>
<plugin>
<groupId>com.sun.jersey.contribs</groupId>
<artifactId>maven-wadl-plugin</artifactId>
<version>1.17</version>
<executions>
<execution>
<id>generate</id>
<goals>
<goal>generate</goal>
</goals>
<phase>${javadoc-phase}</phase>
</execution>
</executions>
<configuration>
<wadlFile>${project.build.outputDirectory}/application.wadl
</wadlFile>
<formatWadlFile>true</formatWadlFile>
<baseUri>http://example.com:8080/rest</baseUri>
<packagesResourceConfig>
<param>com.example.rs.resource</param>
</packagesResourceConfig>
<wadlGenerators>
<wadlGeneratorDescription>
<className>com.sun.jersey.server.wadl.generators.WadlGeneratorApplicationDoc
</className>
<properties>
<property>
<name>applicationDocsFile</name>
<value>${basedir}/src/main/doc/application-doc.xml</value>
</property>
</properties>
</wadlGeneratorDescription>
<wadlGeneratorDescription>
<className>com.sun.jersey.server.wadl.generators.WadlGeneratorGrammarsSupport
</className>
<properties>
<property>
<name>grammarsFile</name>
<value>${basedir}/src/main/doc/application-grammars.xml</value>
</property>
</properties>
</wadlGeneratorDescription>
</wadlGenerators>
</configuration>
</plugin>
</plugins>
</build>
Pay attention to the buildUri and packagesResourceConfig elements. You have to change them to reflect your project's configuration. You may also want to change the plugin's version (I used 1.17).
2. Create a /doc folder and add some files.
Create the src/main/doc/ folder and create the two files below.
File: application-doc.xml
Content:
<?xml version="1.0" encoding="UTF-8"?>
<applicationDocs targetNamespace="http://wadl.dev.java.net/2009/02">
<doc xml:lang="en" title="A message in the WADL">This is added to the start of the generated application.wadl</doc>
</applicationDocs>
File: application-grammars.xml
Content:
<?xml version="1.0" encoding="UTF-8" ?>
<grammars xmlns="http://wadl.dev.java.net/2009/02" />
3. Run the maven command.
Go to the project folder and run the following command:
$ mvn compile com.sun.jersey.contribs:maven-wadl-plugin:generate
The files \target\classes\application.wadl (the WADL itself) and \target\classes\xsd0.xsd (the schema of the resources - it's used by the application.wadl) should be generated.
Edit and use them as you wish.
PS.: Bear in mind that this is a very simple use of the maven-wadl-plugin. It can do a lot more. To know it better, please refer to the zip file mentioned in the other answer (by Pavel Bucek).
Yes, please see gerenate-wadl [1] sample from Jersey samples (look for maven-wadl-plugin).
[1] http://search.maven.org/remotecontent?filepath=com/sun/jersey/samples/generate-wadl/1.12/generate-wadl-1.12-project.zip

Categories

Resources