Hello,
I would like to configure cxf in order to avoid:
- using @XmlSeeAlso annotation particularly to allow inheritance
- using @XmlRootElement for marshalling/unmarsahlling.
In accordance with what I found in the cxf documentation and the cxd users
forum, I have to :
- use a single JAXBContext
- update an existing ObjectFactory with methods returning JAXBElements or
simply set an 'unmarshalFromJaxbElement' property for JAXB
First, I am trying to do it for a SOAP web service at the client and the
server sides.
In order to use a single JAXBContext, I did the following:
- I created a GlobalContext class:
public class GlobalContext {
public static JAXBContext getJAXBContext(){
try {
// the name of my package is "test"
return JAXBContext.newInstance("test");
} catch (JAXBException e) {
e.printStackTrace();
}
return null;
}
}
- I changed my beans.xml file as follows:
-- at the server
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<jaxws:endpoint xmlns:tns="http://test/" id="service"
implementor="test.Service" wsdlLocation="wsdl/service.wsdl"
endpointName="tns:ServicePort" serviceName="tns:ServiceService"
address="/ServicePort">
<jaxws:properties>
<entry key="schema-validation-enabled" value="false" />
</jaxws:properties>
<jaxws:features>
<bean class="org.apache.cxf.feature.LoggingFeature" />
</jaxws:features>
<jaxws:dataBinding>
<bean class="org.apache.cxf.jaxb.JAXBDataBinding" >
<constructor-arg index="0" ref="globalContext"/>
</bean>
</jaxws:dataBinding>
</jaxws:endpoint>
<bean id= "globalContext" class="test.GlobalContext"
factory-method="getJAXBContext"/>
</beans>
-- at the client
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
<jaxws:client createdFromAPI="false">
<jaxws:dataBinding>
<bean class="org.apache.cxf.jaxb.JAXBDataBinding" >
<constructor-arg index="0" ref="globalContext"/>
</bean>
</jaxws:dataBinding>
</jaxws:client>
<bean id= "globalContext" class="test.GlobalContext"
factory-method="getJAXBContext"/>
</beans>
and the web.xml file at the client is:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID"
version="2.5">
<display-name>SOAP-test2Client</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/cxf-beans.xml</param-value>
</context-param>
</web-app>
In my "test" package, I have two classes A and B, B inherits A, and a
service operation void op(A a).
I don't have any annotations in these classes at the client or the server
sides.
If my above cxf configuration is correct, it should run as if I do the
following code in JAXB:
try {
JAXBContext jc = JAXBContext.newInstance("test");
// for marshalling a b instance used to call "op" at
the client side
Marshaller marshaller = jc.createMarshaller();
B b = new B();
b.setX("hello");
b.setY(32);
Op op = new Op();
op.setArg0(b);
JAXBElement<Op> op2 = new JAXBElement<Op>(new
QName("http://test/", "op"), Op.class, op);
marshaller.marshal(op2, System.out);
// for unmarshalling at the server side
File out = new File("src/test/output.xml");
marshaller.marshal(op2, out);
Unmarshaller unmarshaller =
jc.createUnmarshaller();
StreamSource xml2 = new
StreamSource("src/test/output.xml");
JAXBElement<Op> op3 =
unmarshaller.unmarshal(xml2, Op.class);
System.out.println( op3.getValue().getArg0());
} catch (JAXBException e) {
e.printStackTrace();
}
However, tests shows that its is not correct.
For instance, I have the following exception when I run my client with my
spring configuration:
Mar 4, 2014 2:27:52 PM
org.apache.cxf.service.factory.ReflectionServiceFactoryBean
buildServiceFromWSDL
INFO: Creating Service {http://test/}ServiceService from WSDL:
http://localhost:8080/SOAP-test2/services/ServicePort?wsdl
Exception in thread "main" javax.xml.ws.WebServiceException:
org.apache.cxf.service.factory.ServiceConstructionException
at org.apache.cxf.jaxws.ServiceImpl.getPort(ServiceImpl.java:347)
at org.apache.cxf.jaxws.ServiceImpl.getPort(ServiceImpl.java:336)
at javax.xml.ws.Service.getPort(Service.java:92)
at test.ServiceService.getServicePort(ServiceService.java:58)
at
test.ServiceInterface_ServicePort_Client.main(ServiceInterface_ServicePort_Client.java:50)
Caused by: org.apache.cxf.service.factory.ServiceConstructionException
at
org.apache.cxf.jaxb.JAXBDataBinding.initialize(JAXBDataBinding.java:341)
at
org.apache.cxf.service.factory.AbstractServiceFactoryBean.initializeDataBindings(AbstractServiceFactoryBean.java:86)
at
org.apache.cxf.service.factory.ReflectionServiceFactoryBean.buildServiceFromWSDL(ReflectionServiceFactoryBean.java:446)
at
org.apache.cxf.service.factory.ReflectionServiceFactoryBean.initializeServiceModel(ReflectionServiceFactoryBean.java:548)
at
org.apache.cxf.service.factory.ReflectionServiceFactoryBean.create(ReflectionServiceFactoryBean.java:265)
at
org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean.create(JaxWsServiceFactoryBean.java:215)
at
org.apache.cxf.frontend.AbstractWSDLBasedEndpointFactory.createEndpoint(AbstractWSDLBasedEndpointFactory.java:102)
at
org.apache.cxf.frontend.ClientFactoryBean.create(ClientFactoryBean.java:91)
at
org.apache.cxf.frontend.ClientProxyFactoryBean.create(ClientProxyFactoryBean.java:157)
at
org.apache.cxf.jaxws.JaxWsProxyFactoryBean.create(JaxWsProxyFactoryBean.java:142)
at org.apache.cxf.jaxws.ServiceImpl.createPort(ServiceImpl.java:478)
at org.apache.cxf.jaxws.ServiceImpl.getPort(ServiceImpl.java:345)
... 4 more
Caused by: com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 2 counts
of IllegalAnnotationExceptions
Two classes have the same XML type name "{http://test/}op". Use
@XmlType.name and @XmlType.namespace to assign different names to them.
this problem is related to the following location:
at test.jaxws_asm.Op
this problem is related to the following location:
at test.Op
at public javax.xml.bind.JAXBElement
test.ObjectFactory.createOp(test.Op)
at test.ObjectFactory
Two classes have the same XML type name "{http://test/}opResponse". Use
@XmlType.name and @XmlType.namespace to assign different names to them.
this problem is related to the following location:
at test.jaxws_asm.OpResponse
this problem is related to the following location:
at test.OpResponse
at public test.OpResponse test.ObjectFactory.createOpResponse()
at test.ObjectFactory
at
com.sun.xml.bind.v2.runtime.IllegalAnnotationsException$Builder.check(IllegalAnnotationsException.java:106)
at
com.sun.xml.bind.v2.runtime.JAXBContextImpl.getTypeInfoSet(JAXBContextImpl.java:471)
at
com.sun.xml.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:303)
at
com.sun.xml.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:142)
at
com.sun.xml.bind.v2.runtime.JAXBContextImpl$JAXBContextBuilder.build(JAXBContextImpl.java:1174)
at
com.sun.xml.bind.v2.ContextFactory.createContext(ContextFactory.java:162)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:202)
at javax.xml.bind.ContextFinder.find(ContextFinder.java:363)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:574)
at
org.apache.cxf.common.jaxb.JAXBContextCache$2.run(JAXBContextCache.java:329)
at
org.apache.cxf.common.jaxb.JAXBContextCache$2.run(JAXBContextCache.java:327)
at java.security.AccessController.doPrivileged(Native Method)
at
org.apache.cxf.common.jaxb.JAXBContextCache.createContext(JAXBContextCache.java:327)
at
org.apache.cxf.common.jaxb.JAXBContextCache.getCachedContextAndSchemas(JAXBContextCache.java:228)
at
org.apache.cxf.jaxb.JAXBDataBinding.createJAXBContextAndSchemas(JAXBDataBinding.java:482)
at
org.apache.cxf.jaxb.JAXBDataBinding.initialize(JAXBDataBinding.java:339)
... 15 more
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Even if I use a normal client, generated from the service WSDL file (which
contains all necessary annotations ), I have the following error at the
server when the client calls to void op(A a with a B instance:
ID: 8
Address: http://localhost:8080/SOAP-test2/services/ServicePort
Encoding: UTF-8
Http-Method: POST
Content-Type: text/xml; charset=UTF-8
Headers: {Accept=[*/*], cache-control=[no-cache], connection=[keep-alive],
Content-Length=[258], content-type=[text/xml; charset=UTF-8],
host=[localhost:8080], pragma=[no-cache], SOAPAction=[""],
user-agent=[Apache CXF 2.7.10]}
Payload: <soap:Envelope
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:op
xmlns:ns2="http://test/"><arg0
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:type="ns2:b"><x>salut</x><y>2014</y></arg0></ns2:op></soap:Body></soap:Envelope>
--------------------------------------
Mar 4, 2014 2:37:51 PM org.apache.cxf.phase.PhaseInterceptorChain
doDefaultLogging
WARNING: Interceptor for {http://test/}ServiceService#{http://test/}op has
thrown exception, unwinding now
org.apache.cxf.interceptor.Fault: Unmarshalling Error: unrecognized type
name: {http://test/}b. Did you mean b?
at
org.apache.cxf.jaxb.JAXBEncoderDecoder.unmarshall(JAXBEncoderDecoder.java:881)
at
org.apache.cxf.jaxb.JAXBEncoderDecoder.unmarshall(JAXBEncoderDecoder.java:702)
at org.apache.cxf.jaxb.io.DataReaderImpl.read(DataReaderImpl.java:160)
at
org.apache.cxf.interceptor.DocLiteralInInterceptor.handleMessage(DocLiteralInInterceptor.java:107)
at
org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:272)
at
org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:121)
at
org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:239)
at
org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:248)
at
org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:222)
at
org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:153)
at
org.apache.cxf.transport.servlet.CXFNonSpringServlet.invoke(CXFNonSpringServlet.java:167)
at
org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:286)
at
org.apache.cxf.transport.servlet.AbstractHTTPServlet.doPost(AbstractHTTPServlet.java:206)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:646)
at
org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:262)
at
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
at
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at
org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
at
org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
at
org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501)
at
org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
at
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
at
org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950)
at
org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
at
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
at
org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1040)
at
org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607)
at
org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:315)
at
java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
at
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
at java.lang.Thread.run(Thread.java:695)
Caused by: javax.xml.bind.UnmarshalException
- with linked exception:
[javax.xml.bind.UnmarshalException: unrecognized type name: {http://test/}b.
Did you mean b?]
at
com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.handleStreamException(UnmarshallerImpl.java:435)
at
com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:372)
at
com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:349)
at
org.apache.cxf.jaxb.JAXBEncoderDecoder.doUnmarshal(JAXBEncoderDecoder.java:842)
at
org.apache.cxf.jaxb.JAXBEncoderDecoder.access$100(JAXBEncoderDecoder.java:101)
at
org.apache.cxf.jaxb.JAXBEncoderDecoder$2.run(JAXBEncoderDecoder.java:870)
at java.security.AccessController.doPrivileged(Native Method)
at
org.apache.cxf.jaxb.JAXBEncoderDecoder.unmarshall(JAXBEncoderDecoder.java:868)
... 30 more
%%%%%%%%%%%%%%%%%%%%%%%%
What I am missing exactly in my configuration?
It seems that my ObjectFactory class does not work as it should be.
Maybe it would be better to set 'unmarshalFromJaxbElement" to true in my
cxf-beans.xml file.
But how to do it?
Maybe also my spring configuration is not correct at the client.
How to correct it and How to do the same thing in a Java code, without
spring?
Here is my ObjectFactory class:
@XmlRegistry
public class ObjectFactory {
private final static QName _A_QNAME = new QName("http://test/", "a");
private final static QName _OpResponse_QNAME = new QName("http://test/",
"opResponse");
private final static QName _B_QNAME = new QName("http://test/", "b");
private final static QName _Op_QNAME = new QName("http://test/", "op");
/**
* Create a new ObjectFactory that can be used to create new instances
of schema derived classes for package: test
*
*/
public ObjectFactory() {
}
/**
* Create an instance of {@link Op }
*
*/
public Op createOp() {
return new Op();
}
/**
* Create an instance of {@link B }
*
*/
public B createB() {
return new B();
}
/**
* Create an instance of {@link OpResponse }
*
*/
public OpResponse createOpResponse() {
return new OpResponse();
}
/**
* Create an instance of {@link A }
*
*/
public A createA() {
return new A();
}
/**
* Create an instance of {@link JAXBElement }{@code <}{@link A }{@code
>}}
*
*/
@XmlElementDecl(namespace = "http://test/", name = "a")
public JAXBElement createA(A value) {
return new JAXBElement (_A_QNAME, A.class, null, value);
}
/**
* Create an instance of {@link JAXBElement }{@code <}{@link OpResponse
}{@code >}}
*
*/
@XmlElementDecl(namespace = "http://test/", name = "opResponse")
public JAXBElement<OpResponse> createOpResponse(OpResponse value) {
return new JAXBElement<OpResponse>(_OpResponse_QNAME,
OpResponse.class, null, value);
}
/**
* Create an instance of {@link JAXBElement }{@code <}{@link B }{@code
>}}
*
*/
@XmlElementDecl(namespace = "http://test/", name = "b")
public JAXBElement createB(B value) {
return new JAXBElement(_B_QNAME, B.class, null, value);
}
/**
* Create an instance of {@link JAXBElement }{@code <}{@link Op }{@code
>}}
*
*/
@XmlElementDecl(namespace = "http://test/", name = "op")
public JAXBElement<Op> createOp(Op value) {
return new JAXBElement<Op>(_Op_QNAME, Op.class, null, value);
}
}
Kind regards,
Diana
--
View this message in context:
http://cxf.547215.n5.nabble.com/How-to-configure-CXF-for-a-single-JAXBContext-and-for-an-automatic-JAXBElement-conversion-tp5740782.html
Sent from the cxf-user mailing list archive at Nabble.com.