CXF JAXB JAXBEncoderDecoder unmarshalling error : unexpected element when having qualified elements - web-services

I have the following problem and cannot find a solution:
The WSDL has elementFormDefault="qualified", in the response that I receive in my CXF client all the elements are prefixed with namespace but JAXB throws an exception
org.apache.cxf.interceptor.Fault: Unmarshalling Error: unexpected element (uri:"unm:ENTSCWS", local:"searchReturn"). Expected elements are
at org.apache.cxf.jaxb.JAXBEncoderDecoder.unmarshall(JAXBEncoderDecoder.java:661)
at org.apache.cxf.jaxb.JAXBEncoderDecoder.unmarshall(JAXBEncoderDecoder.java:533)
at org.apache.cxf.jaxb.io.DataReaderImpl.read(DataReaderImpl.java:128) ...
If i change in the WSDL elementFormDefault="unqualified" it is working, but I am not allowed to change the WSDL, it should have the elements prefixed with the namespace.
The package-info.java contains the annotaction:
#javax.xml.bind.annotation.XmlSchema(namespace = "unm:ENTSCWS", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package entscws;
The response class contains the annotation:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"searchReturn"
})
#XmlRootElement(name = "searchResponse")
public class SearchResponse {
Do you have any idea why I get this error?

Are you running in OSGi? I've seen some similar issues with package-info's not being picked up properly there.
Another option could be to add the -xjc-npa flag to the wsdl2java command to have it not use the package-info at all and stick the namespaces in all the other places.

Related

SoapUI REST mock service give errors when mocking to handle dynamic responses depending on request values (But the same method works for SOAP mocks)

I was trying to mock the following REST web-service using soapUI
Sample Request:
<Request>
<HistoricTxn>
<reference>E1</reference>
<method>txn</method>
</HistoricTxn>
</Request>
SampleResponse1
<Response>
<reason>ACCEPTED</reason>
<status>1</status>
<time>10:12</time>
</Response>
SampleResponse2
<Response>
<information>Failure on invalid request details</information>
<reason>fails Luhn check</reason>
<status>3</status>
<time>10:15</time>
</Response>
Usually I use this kind of a groovy script to evaluate the request and out put a dynamic response. (When using soapUI to mock SOAP web services)
groovy Script:
def groovyUtils = new com.eviware.soapui.support.GroovyUtils(context);
def holder = groovyUtils.getXmlHolder(mockRequest.getRequestContent());
def reference = holder.getNodeValue("//reference");
if(reference == "Success"){
return "SampleResponse1";
} else {
return "SampleResponse2";
}
Unfortunately when I try to hit a request to this REST mock service end point it returns an error.
Error:
com.eviware.soapui.impl.wsdl.mock.DispatchException: Failed to
dispatch using script; java.lang.NullPointerException: Cannot invoke
method getRequestContent() on null object
I understand that the error message says getRequestContent() has returned a null value and because of that I am getting this exception. But the same works with the SOAP mock services, with out returning null values or causing exceptions. Appreciate any workarounds to overcome this issue.
I just figured that mockRequest.getRequestContent() returns null for all the POST, PUT, DELETE requests sent to REST web-services mocked using soapUI (version 5.2.1)
def holder = groovyUtils.getXmlHolder(mockRequest.getRequestContent());
Since the above (RequestContent) returns null, soap UI can not evaluate the value of the following tag.
def reference = holder.getNodeValue("//reference");
SoapUIOfficial References for this bug in soapUI(version 5.2.1):
https://community.smartbear.com/t5/SoapUI-NG/SoapUI-5-0-requestContent-is-null-for-Rest-Mock-service/td-p/40458
https://community.smartbear.com/t5/SoapUI-NG/Mock-Service-mockRequest-requestContent-is-NULL-HTTP-PUT/td-p/42138
I just found a workaround to overcome the aforesaid bug in soapUI(version 5.2.1).
By this point it is clear to me that I can use mockRequest.getRequest().getReader().readLine() script to read a single line in the request body. (though mockRequest.getRequestContent() returned a null object)
I would simply access the request body using the following groovy script.
def requestBody="";
try {
while ((line = mockRequest.getRequest().getReader().readLine()) != null){
requestBody = requestBody+line;
}
} catch (Exception e) {
log.error("exception:"+e)
}
def groovyUtils = new com.eviware.soapui.support.GroovyUtils(context);
def holder = groovyUtils.getXmlHolder(requestBody);
def reference = holder.getNodeValue("//reference");
According to the above script, it will have to read the request body line by line and then merge all the lines to have the whole request body.
Since the request body is not null anymore following script can evaluate the value inside reference tag.
def reference = holder.getNodeValue("//reference");
eventually i was able to mock my REST mock service with dynamic responses according to following conditions.
if(reference == "Success"){
return "SampleResponse1";
} else {
return "SampleResponse2";
}
Hope you could save a lot of time by following this method.

Domino: Webservice: Class do not have a property of the name

I have the following Problem.
I tried to create a web service a standard cmis Webservice Interface on IBM, Domino with wsdl2java (with cxf). After creating all java classes I tried to get answers from the webservice with the eclipse Java Client. It works find. After this test I import the generated java classes into a Domino Database.
Now I have the problem to run the webservice, because the following error message:
class org.oasis_open.docs.ns.cmis.messaging._200908.GetTypeDefinition
do not have a property of the name {URL..}repositoryId
In the JAVA Class the following code:
public class GetTypeDefinition {
#XmlElement(required = true)
protected String repositoryId;
#XmlElement(required = true)
protected String typeId;
#XmlElementRef(name = "extension", namespace = "http://docs.oasis-open.org/ns/cmis/messaging/200908/", type = JAXBElement.class)
protected JAXBElement<CmisExtensionType> extension;
The Domino JAVA Env. does not understand the Tag #XmlElement(required = true) without the name, namespace and the type definition.
If I add in the same line the following code:
#XmlElement(required = true, name = "repositoryId", namespace = "http://docs.oasis-open.org/ns/cmis/messaging/200908/", type = String.class)
protected String repositoryId;
it works (error then in the next line:
GetTypeDefinition do not have a property of the name {URL}typeId
Now the question is: why? Can I generate the java classes with an other tool (not with cxf wsdl2java) or do I need other parameters to get the complete code?
In the generated JAVA Classes are round about 170 lines with the problematic code.
Have somebody an Idea to solve the problem on the Domino Server (x64 9.0)?

How can I add characters at the end of my xml response?

I have a restful web service that's returning results like this:
<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">Some Text</string>
However, the people on the receiving end need this text to be terminated w/ a special character such as "\r". How can I add that text to the end of my serialized response?
I'm sending this response from inside of a WCF service in C# like this:
[WebGet(UriTemplate = "/MyMethod?x={myId}"), OperationContract]
string GetSomeText(Guid myId);
I can think of three solutions:
1. Http Module (least code but most confusing for maintenance)
Assuming you're hosting your WCF in ASP.Net, you can create an Http module to add a \r to the end of all responses in your application.
This could be the code of the Http module. I've used 'End' as a suffix here because it's easier to read in a browser than \r, but for \r you would change the "End" in context_PostRequestHandlerExecute to "\r".
public class SuffixModule : IHttpModule
{
private HttpApplication _context;
public void Init(HttpApplication context)
{
_context = context;
_context.PostRequestHandlerExecute += context_PostRequestHandlerExecute;
}
void context_PostRequestHandlerExecute(object sender, EventArgs e)
{
// write the suffix if there is a body to this request
string contentLengthHeaderValue = _context.Response.Headers["Content-length"];
string suffix = "End";
if (!String.IsNullOrEmpty(contentLengthHeaderValue))
{
// Increase the content-length header by the length of the suffix
_context.Response.Headers["Content-length"] =
(int.Parse(contentLengthHeaderValue) + suffix.Length)
.ToString();
// and write the suffix!
_context.Response.Write(suffix);
}
}
public void Dispose()
{
// haven't worked out if I need to do anything here
}
}
Then you need to set up your module up in your web.config. The below assumes you have IIS running in Integrated Pipeline mode. If you haven't, you need to register the modules in the <system.web><httpModules> section.
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<!-- 'type' should be the fully-qualified name of the type,
followed by a comma and the name of the assembly-->
<add name="SuffixModule" type="WcfService1.SuffixModule,WcfService1"/>
</modules>
</system.webServer>
This option has the problems that it would affect all requests in your application by default and it would probably fall over if you decided to use chunked encoding.
2. Use ASP.NET MVC (changes technology but good maintainability)
Use MVC instead of WCF. You'd have far better control over your output.
3. Custom Serializer (lots of code, but less hacky than option 1)
You could write your own custom serializer. This StackOverflow question gives you pointers on how to do this. I didn't write a prototype for this because it looked as though there were many, many methods which needed to be overridden. I daresay most of them would be pretty simple delegations to the standard serializer.

Add SOAP header object using pure JAX-WS

I'm trying to implement simple web service client for PayPal Express Checkout API using JAX WS. PayPal Express Checkout API provides WSDL file, from which I was able to generate Java classes using CXF's wsdl2java utility.
From authentication reasons, it demands adding SOAP Header to each request. This header is quite simple and should look like here:
https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_api_ECSOAPAPIBasics#id09C3I0CF0O6
Generated from WSDL classes include ebay.apis.eblbasecomponents.CustomSecurityHeaderType class which represents header which I need to add to each request.
So the question is: how can I add manually created instance of CustomSecurityHeaderType class to SOAP request's header taking into account following conditions:
I'm not very eager to use classes from com.sun.* package as mentioned in answer here: JAX-WS - Adding SOAP Headers (mainly because of possible portability issues between different JDK's)
I don't want to manually marshal that object into nested javax.xml.soap.SOAPElement instances as mentioned in answer here:
How do I add a SOAP Header using Java JAX-WS
So, it looks like I've found possible answer while combining JAX-WS & JAXB related answers from SO (I would really appreciate if somebody experienced in these technologies can check whether following is correct):
The obvious thing for me is to add SOAP message handler and alter header of SOAPMessage instance in it:
import javax.xml.ws.Binding;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.handler.Handler;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Marshaller;
import javax.xml.soap.SOAPHeader;
import ebay.api.paypalapi.ObjectFactory; // class generated by wsdl2java
// following class is generated by wsdl2java utility Service class
final PayPalAPIInterfaceService payPalService = new PayPalAPIInterfaceService();
final PayPalAPIAAInterface expressCheckoutPort = payPalService.getPayPalAPIAA();
final Binding binding = ((BindingProvider) expressCheckoutPort).getBinding();
List<Handler> handlersList = new ArrayList<Handler>();
// now, adding instance of Handler to handlersList which should do our job:
// creating header instance
final CustomSecurityHeaderType headerObj = new CustomSecurityHeaderType();
final UserIdPasswordType credentials = new UserIdPasswordType();
credentials.setUsername("username");
credentials.setPassword("password");
credentials.setSignature("signature");
headerObj.setCredentials(credentials);
// bookmark #1 - please read explanation after code
final ObjectFactory objectFactory = new ObjectFactory();
// creating JAXBElement from headerObj
final JAXBElement<CustomSecurityHeaderType> requesterCredentials = objectFactory.createRequesterCredentials(headerObj);
handlersList.add(new SOAPHandler<SOAPMessageContext>() {
#Override
public boolean handleMessage(final SOAPMessageContext context) {
try {
// checking whether handled message is outbound one as per Martin Strauss answer
final Boolean outbound = (Boolean) context.get("javax.xml.ws.handler.message.outbound");
if (outbound != null && outbound) {
// obtaining marshaller which should marshal instance to xml
final Marshaller marshaller = JAXBContext.newInstance(CustomSecurityHeaderType.class).createMarshaller();
// adding header because otherwise it's null
final SOAPHeader soapHeader = context.getMessage().getSOAPPart().getEnvelope().addHeader();
// marshalling instance (appending) to SOAP header's xml node
marshaller.marshal(requesterCredentials, soapHeader);
}
} catch (final Exception e) {
throw new RuntimeException(e);
}
return true;
}
// ... default implementations of other methods go here
});
// as per Jean-Bernard Pellerin's comment setting handlerChain list here, after all handlers were added to list
binding.setHandlerChain(handlersList);
Explanation of bookmark #1:
one should marshal not the header object itself, but JAXBElement representing that object, because otherwise one will get an exception. One should use one of ObjectFactory classes which are generated from WSDL for creating needed JAXBElement instances from original objects.
(Thanks #skaffman for answer: No #XmlRootElement generated by JAXB )
One should also refer to Martin Straus answer which extends this one
This solution works great, but there's a catch. It generates this error when the inbound message is processed:
dic 19, 2012 7:00:55 PM com.sun.xml.messaging.saaj.soap.impl.EnvelopeImpl addHeader
SEVERE: SAAJ0120: no se puede agregar una cabecera si ya hay una
Exception in thread "main" javax.xml.ws.WebServiceException: java.lang.RuntimeException: com.sun.xml.messaging.saaj.SOAPExceptionImpl: Can't add a header when one is already present.
at com.sun.xml.ws.handler.ClientSOAPHandlerTube.callHandlersOnResponse(ClientSOAPHandlerTube.java:167)
at com.sun.xml.ws.handler.HandlerTube.processResponse(HandlerTube.java:174)
at com.sun.xml.ws.api.pipe.Fiber.__doRun(Fiber.java:1074)
at com.sun.xml.ws.api.pipe.Fiber._doRun(Fiber.java:979)
at com.sun.xml.ws.api.pipe.Fiber.doRun(Fiber.java:950)
at com.sun.xml.ws.api.pipe.Fiber.runSync(Fiber.java:825)
at com.sun.xml.ws.client.Stub.process(Stub.java:443)
at com.sun.xml.ws.client.sei.SEIStub.doProcess(SEIStub.java:174)
at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:119)
at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:102)
at com.sun.xml.ws.client.sei.SEIStub.invoke(SEIStub.java:154)
at $Proxy38.wsRdyCrearTicketDA(Unknown Source)
at ar.com.fit.fides.remedy.api.ws.ServicioCreacionTickets.crearTicket(ServicioCreacionTickets.java:55)
at ar.com.fit.fides.remedy.api.ws.ConectorRemedyWS.crearTicket(ConectorRemedyWS.java:43)
at ar.com.fit.fides.remedy.api.ws.ConectorRemedyWS.main(ConectorRemedyWS.java:90)
Caused by: java.lang.RuntimeException: com.sun.xml.messaging.saaj.SOAPExceptionImpl: Can't add a header when one is already present.
at ar.com.fit.fides.remedy.api.ws.AuthenticationHandler.handleMessage(AuthenticationHandler.java:50)
at ar.com.fit.fides.remedy.api.ws.AuthenticationHandler.handleMessage(AuthenticationHandler.java:23)
at com.sun.xml.ws.handler.HandlerProcessor.callHandleMessageReverse(HandlerProcessor.java:341)
at com.sun.xml.ws.handler.HandlerProcessor.callHandlersResponse(HandlerProcessor.java:214)
at com.sun.xml.ws.handler.ClientSOAPHandlerTube.callHandlersOnResponse(ClientSOAPHandlerTube.java:161)
... 14 more
Caused by: com.sun.xml.messaging.saaj.SOAPExceptionImpl: Can't add a header when one is already present.
at com.sun.xml.messaging.saaj.soap.impl.EnvelopeImpl.addHeader(EnvelopeImpl.java:128)
at com.sun.xml.messaging.saaj.soap.impl.EnvelopeImpl.addHeader(EnvelopeImpl.java:108)
at ar.com.fit.fides.remedy.api.ws.AuthenticationHandler.handleMessage(AuthenticationHandler.java:45)
So, the solution is to check whether the message being handled if the outbound message, like this:
public boolean handleMessage(SOAPMessageContext context) {
try {
Boolean outbound = (Boolean) context.get("javax.xml.ws.handler.message.outbound");
if (outbound != null && outbound) {
// obtaining marshaller which should marshal instance to xml
final Marshaller marshaller = JAXBContext.newInstance(AuthenticationInfo.class).createMarshaller();
// adding header because otherwise it's null
final SOAPHeader soapHeader = context.getMessage().getSOAPPart().getEnvelope().addHeader();
// marshalling instance (appending) to SOAP header's xml node
marshaller.marshal(info, soapHeader);
}
} catch (final Exception e) {
throw new RuntimeException(e);
}
return true;
}
I created a web service exposing method with params user and password as header like this:
#WebService(serviceName="authentication")
public class WSAuthentication {
String name = null;
String password = null;
public WSAuthentication() {
super();
}
public WSAuthentication(String name, String password) {
this.name = name;
this.password = password;
}
private static String getData(WSAuthentication sec) {
System.out.println("********************* AUTHENTICATION ********************" + "\n" +
"**********USER: " + sec.name + "\n" +
"******PASSWORD: " + sec.password + "\n" +
"******************************** AUTHENTICATION ****************************");
return sec.name + " -- " + sec.password;
}
#WebMethod(operationName="security", action="authenticate")
#WebResult(name="answer")
public String security(#WebParam(header=true, mode=Mode.IN, name="user") String user, #WebParam(header=true, mode=Mode.IN, name="password") String password) {
WSAuthentication secure = new WSAuthentication(user, password);
return getData(secure);
}
}
Try compiling it and testing generated from WSDL class. I hope this helps.
I found this answer:
JAX-WS - Adding SOAP Headers
Basically you add -XadditionalHeaders to the compiler options and objects in the headers also appear in your generated code as parameters of the method.
If you are using maven, and the jaxws-maven-plugin all you have to do is add the xadditionalHeaders flag to true and the client will be generated with the methods that have the headers as input.
https://jax-ws-commons.java.net/jaxws-maven-plugin/wsimport-mojo.html#xadditionalHeaders

Groovy MarkupBuilder causing java.lang.NoClassDefFoundError on closure in soapUI

I am not able to get the Groovy MarkupBuilder to work with soapUI. I am very new to Groovy and I am just following one of the user guides on creating XML.
Testing a very simple method:
public String Example(){
def writer = new StringWriter()
def root = new MarkupBuilder(writer)
root.mkp.xmlDeclaration(version:"1.0", encoding:"UTF-8")
root.Root{
Example("A")
}
return writer.toString()
}
I get the following error in soapUI: ava.lang.NoClassDefFoundError: MockXML$_Example_closure2
I have no error when I run from Groovy Console.
In the same class I have:
public String Hello(){
return "Hello"
}
Which works fine in soapUI.
Is there something I would need setup/imported/configured in soapUI that I am not thinking about to handle MarkupBuilder/closures?
Thanks
I believe you have a syntax error in your markup. I think:
root.Root {
should be:
root.Root() {
I think the Groovy evaluating your Root element as a closure instead of a new element in the markup.