jaxb adding namespace to element - web-services

According to my task I have to invoke SOAP service. So, I have generated java classes from wsdl using xjc. But I have a problem invoking SOAP service. My application generates this request:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"/><soap:Body>
<typ:SendMessage xmlns:ns4="http://test.user.kz/UserInfo" xmlns:q1="http://test.user.kz/CustomerInfo" xmlns:typ="http://test.user.kz/MyChannel/v1/Types">
<request>
<requestInfo>
<messageId>26e96b11-8f82-421e-829a</messageId>
</requestInfo>
<requestData>
<data xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="q1:PaymentPackageRequestType">
<q1:methodName>testMethod</q1:methodName>
</data>
</requestData>
</request>
</typ:SendMessage></soap:Body></soap:Envelope>
But I need in my SOAP request I need to specify namespace in data tag, lik this:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"/><soap:Body>
<typ:SendMessage xmlns:ns4="http://test.user.kz/UserInfo" xmlns:q1="http://test.user.kz/CustomerInfo" xmlns:typ="http://test.user.kz/MyChannel/v1/Types">
<request>
<requestInfo>
<messageId>26e96b11-8f82-421e-829a</messageId>
</requestInfo>
<requestData>
<data xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="q1:PaymentPackageRequestType" **xmlns:q1="http://payments.bee.kz/PaymentPackage"**>
<q1:methodName>testMethod</q1:methodName>
</data>
</requestData>
</request>
</typ:SendMessage></soap:Body></soap:Envelope>
Otherwise target SOAP service gives me error:
XML namespace prefix 'q1' is not defined.
How it possible to specify namespace in data tag?
This is my current package-info:
#javax.xml.bind.annotation.XmlSchema(
xmlns = {
#javax.xml.bind.annotation.XmlNs(prefix = "typ",
namespaceURI = "http://test.user.kz/MyChannel/v1/Types"),
#javax.xml.bind.annotation.XmlNs(prefix = "q1",
namespaceURI = "http://test.user.kz/CustomerInfo")
},
elementFormDefault = javax.xml.bind.annotation.XmlNsForm.UNQUALIFIED,
attributeFormDefault = javax.xml.bind.annotation.XmlNsForm.UNSET
)
package kz.uni.gen;
So I couldn't add namespace xmlns:q1="http://test.user.kz/CustomerInfo" to data tag in SOAP request. How can I add this namespace declaration or move namespace declaration from SendMessage tag?

so using JAXB it is not possible. Therefore I am manually added namespace in required element. This is full snippet:
Document document = null;
try {
document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
Marshaller marshaller = JAXBContext.newInstance(SendMessage.class).createMarshaller();
marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.setProperty("com.sun.xml.bind.characterEscapeHandler", new CharacterEscapeHandler() {
#Override
public void escape(char[] buf, int start, int len, boolean b, Writer out) throws IOException {
out.write(buf, start, len);
}
});
QName name = new QName(NAMESPACE_URI, SendMessage.class.getSimpleName());
JAXBElement<SendMessage> root = new JAXBElement<SendMessage>(name, SendMessage.class, from);
StringWriter writer1 = new StringWriter();
marshaller.marshal(root, writer1);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
Element node = dbf
.newDocumentBuilder()
.parse(new ByteArrayInputStream(writer1.toString().getBytes(StandardCharsets.ISO_8859_1)))
.getDocumentElement();
Attr attr1 = document.createAttribute("xmlns:q1");
attr1.setValue("http://test.user.kz/CustomerInfo");
node.getElementsByTagName("data").item(0).getAttributes().setNamedItem(node.getOwnerDocument().importNode(attr1, true));
return node;
} catch (Exception e) {
throw new Exception("Unable to transform POJO to XML SOAP message ", e);
}

Related

500 Internal Server Error error in Webservice request

I have an existing jar which sends web-service request from one of our application server to another. Below is the code for sending the request
public IUsbMessage executeOutboundRequest(IUsbMessage paramIUsbMessage)
{
IUsbMessage localIUsbMessage = UsbMessageFactory.createUbusMessage();
try
{
LogManager.logDebug("ServiceProvider:- Enter executeOutboundRequest");
Object[] arrayOfObject = (Object[])paramIUsbMessage.getPayload();
NVPVO localNVPVO = (NVPVO)arrayOfObject[1];
String str1 = (String)localNVPVO.getHashmap().get("endPointUrl");
String str2 = (String)localNVPVO.getHashmap().get("respTag");
String str3 = (String)localNVPVO.getHashmap().get("body");
str3 = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><FIXML xsi:schemaLocation=\"http://www.oracle.com/fixml AcctInq.xsd\" xmlns=\"http://www.oracle.com/fixml\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">" + str3.trim();
LogManager.logDebug("ServiceProvider:- RequestXMLMsg" + str3);
MessageFactory localMessageFactory = MessageFactory.newInstance();
SOAPMessage localSOAPMessage1 = localMessageFactory.createMessage();
SOAPFactory localSOAPFactory = SOAPFactory.newInstance();
SOAPBody localSOAPBody = localSOAPMessage1.getSOAPBody();
SOAPElement localSOAPElement1 = localSOAPBody.addChildElement(localSOAPFactory.createName("executeService"));
SOAPElement localSOAPElement2 = localSOAPElement1.addChildElement(localSOAPFactory.createName("arg_0_0"));
localSOAPElement2.addTextNode(str3);
localSOAPMessage1.saveChanges();
localSOAPMessage1.writeTo(System.out);
SOAPConnectionFactory localSOAPConnectionFactory = SOAPConnectionFactory.newInstance();
SOAPConnection localSOAPConnection = localSOAPConnectionFactory.createConnection();
LogManager.logDebug("ServiceProvider:- endPointUrl" + str1);
LogManager.logDebug("ServiceProvider:- respTag" + str2);
URL localURL = new URL(str1);
SOAPMessage localSOAPMessage2 = localSOAPConnection.call(localSOAPMessage1, localURL);
DocumentBuilderFactory localDocumentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder localDocumentBuilder = localDocumentBuilderFactory.newDocumentBuilder();
Document localDocument = localDocumentBuilder.newDocument();
Element localElement1 = null;
Element localElement2 = null;
Text localText = null;
Element localElement3 = null;
Iterator localIterator = localSOAPMessage2.getSOAPBody().getChildElements();
Object localObject2;
Object localObject3;
while (localIterator.hasNext())
{
localObject1 = (SOAPElement)localIterator.next();
localElement1 = localDocument.createElement(((SOAPElement)localObject1).getNodeName());
localObject2 = ((SOAPElement)localObject1).getAttributes();
Object localObject4;
if (((NamedNodeMap)localObject2).getLength() > 0) {
for (int i = 0; i < ((NamedNodeMap)localObject2).getLength(); i++)
{
localObject4 = ((NamedNodeMap)localObject2).item(i);
localElement1.setAttribute(((Node)localObject4).getNodeName(), ((Node)localObject4).getNodeValue());
}
}
localElement3 = localElement1;
localObject3 = ((SOAPElement)localObject1).getChildElements();
while (((Iterator)localObject3).hasNext())
{
localObject4 = (SOAPElement)((Iterator)localObject3).next();
localElement1 = localDocument.createElement(((SOAPElement)localObject4).getNodeName());
NamedNodeMap localNamedNodeMap = ((SOAPElement)localObject1).getAttributes();
if (localNamedNodeMap.getLength() > 0) {
for (int j = 0; j < localNamedNodeMap.getLength(); j++)
{
Node localNode = localNamedNodeMap.item(j);
localElement1.setAttribute(localNode.getNodeName(), localNode.getNodeValue());
}
}
localElement2 = localElement1;
localText = localDocument.createTextNode(((SOAPElement)localObject4).getValue());
localElement2.appendChild(localText);
localElement3.appendChild(localElement2);
}
The data which is being passed to the class file is as below containing the request XML and other details
respTag=AcctInqRs,
body=<Header>
<RequestHeader>
<MessageKey>
<RequestUUID>Req_159538426</RequestUUID>
<ServiceRequestId>AcctInq</ServiceRequestId>
<ServiceRequestVersion>10.2</ServiceRequestVersion>
<ChannelId>OR</ChannelId>
<LanguageId></LanguageId>
</MessageKey>
<RequestMessageInfo>
<BankId>54</BankId>
<TimeZone></TimeZone>
<EntityId></EntityId>
<EntityType></EntityType>
<ArmCorrelationId></ArmCorrelationId>
<MessageDateTime>2020-02-23T14:27:22.627</MessageDateTime>
</RequestMessageInfo>
<Security>
<Token>
<PasswordToken>
<UserId></UserId>
<Password></Password>
</PasswordToken>
</Token>
<FICertToken></FICertToken>
<RealUserLoginSessionId></RealUserLoginSessionId>
<RealUser></RealUser>
<RealUserPwd></RealUserPwd>
<SSOTransferToken></SSOTransferToken>
</Security>
</RequestHeader>
</Header>
<Body>
<AcctInqRequest>
<AcctInqRq>
<AcctId>
<AcctId>1101614</AcctId>
</AcctId>
</AcctInqRq>
</AcctInqRequest>
</Body>
</FIXML>,
reqhdr.requestuuid=FINCORE240716215711,
endPointUrl=https://ORPREPROD.domain.com:20322/fiwebservice/FIWebService,
reqhdr.messagedatetime=2020-04-21T21:57:11.000,
reqhdr.servicerequestversion=10.2,
reqhdr.origchannelid=COR,
reqhdr.bankid=54,
reqhdr.servicerequestid=AcctInq
Now the issue is that the request is being sent from server A to server B. Once the request reaches server B it is throwing error "HTTP/1.1 500 Internal Server Error" and the below xml is seen in the logs
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Header/>
<env:Body>
<env:Fault xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<faultcode>SOAP-ENV:Client</faultcode>
<faultstring>**Failed to get operation name from incoming request**</faultstring>
</env:Fault>
</env:Body>
</env:Envelope>
On both the servers our application is deployed on Weblogic and the above errors are from weblogic logs. Can anyone please help me to determine the exact cause of this error, I am totally stuck and clueless about what to do.
The same request XML when sent through SOAP UI works perfectly.
The below request XML works in SOAPUI
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:web="http://webservice.fiusb.ci.ibm.com/">
<soapenv:Header/>
<soapenv:Body>
<web:executeService>
<arg_0_0><![CDATA[<FIXML xsi:schemaLocation="http://www.finacle.com/fixml AcctInq.xsd" xmlns="http://www.finacle.com/fixml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><Header><RequestHeader><MessageKey><RequestUUID>Req_158495384262711</RequestUUID><ServiceRequestId>AcctInq</ServiceRequestId><ServiceRequestVersion>10.2</ServiceRequestVersion><ChannelId>COR</ChannelId><LanguageId></LanguageId></MessageKey><RequestMessageInfo><BankId>54</BankId><TimeZone></TimeZone><EntityId></EntityId><EntityType></EntityType><ArmCorrelationId></ArmCorrelationId><MessageDateTime>2020-02-23T14:27:22.627</MessageDateTime></RequestMessageInfo><Security><Token><PasswordToken><UserId></UserId><Password></Password></PasswordToken></Token><FICertToken></FICertToken><RealUserLoginSessionId></RealUserLoginSessionId><RealUser></RealUser><RealUserPwd></RealUserPwd><SSOTransferToken></SSOTransferToken></Security></RequestHeader></Header><Body><AcctInqRequest><AcctInqRq><AcctId><AcctId>1100161916154</AcctId></AcctId></AcctInqRq></AcctInqRequest></Body></FIXML>
]]></arg_0_0>
</web:executeService>
</soapenv:Body>
</soapenv:Envelope>
The below XML throws the same error "Failed to get operation name from incoming request"
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:web="http://webservice.fiusb.ci.ibm.com">
<soapenv:Header/>
<soapenv:Body>
<web:executeService>
<arg_0_0><![CDATA[<FIXML xsi:schemaLocation="http://www.finacle.com/fixml AcctInq.xsd" xmlns="http://www.finacle.com/fixml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><Header><RequestHeader><MessageKey><RequestUUID>Req_158495384262711</RequestUUID><ServiceRequestId>AcctInq</ServiceRequestId><ServiceRequestVersion>10.2</ServiceRequestVersion><ChannelId>COR</ChannelId><LanguageId></LanguageId></MessageKey><RequestMessageInfo><BankId>54</BankId><TimeZone></TimeZone><EntityId></EntityId><EntityType></EntityType><ArmCorrelationId></ArmCorrelationId><MessageDateTime>2020-02-23T14:27:22.627</MessageDateTime></RequestMessageInfo><Security><Token><PasswordToken><UserId></UserId><Password></Password></PasswordToken></Token><FICertToken></FICertToken><RealUserLoginSessionId></RealUserLoginSessionId><RealUser></RealUser><RealUserPwd></RealUserPwd><SSOTransferToken></SSOTransferToken></Security></RequestHeader></Header><Body><AcctInqRequest><AcctInqRq><AcctId><AcctId>1100161916154</AcctId></AcctId></AcctInqRq></AcctInqRequest></Body></FIXML>
]]></arg_0_0>
</web:executeService>
</soapenv:Body>
</soapenv:Envelope>
Notice the forward slash(/) at the end of namespace. If the slash is not there in the namespace it throws the error in SOAP UI.
Please help me to understand how can I change namespace in my java code

Having trouble parsing SOAP webservice using the library ksoap2

Here is the structure of my SOAP webservice which I need to get the TxRefNum:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:tem="http://tempuri.org/" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header/>
<soap:Body>
<tem:MakeCreditCardPayment>
<tem:objCreditCardBookingPaymentRow>
<tem:ProfessionalUserMappingStudioID>18</tem:ProfessionalUserMappingStudioID>
<tem:ConsumerUserMappingStudioID>5</tem:ConsumerUserMappingStudioID>
<tem:Cost>5</tem:Cost>
<tem:CardNumber>4111111111111111</tem:CardNumber>
<tem:CardHolderName>Shyam</tem:CardHolderName>
<tem:ExpirationDate>042020</tem:ExpirationDate>
<tem:CVV>123</tem:CVV>
<tem:ProfessionalSessionID>320</tem:ProfessionalSessionID>
<tem:TxRefNum></tem:TxRefNum>
</tem:objCreditCardBookingPaymentRow>
</tem:MakeCreditCardPayment>
</soap:Body>
</soap:Envelope>
I am using ksoap2 library to parse the following data, but am unable to find a proper solution to it. Here's what I am doing:
final String NAMESPACE = "http://tempuri.org/";
final String URL = NewURLs.BASE_URL + "api/PaymentService.asmx";
final String SOAP_ACTION = "http://tempuri.org/MakeCreditCardPayment";
final String METHOD_NAME = "MakeCreditCardPayment";
final String INNER_METHOD_NAME = "tem:objCreditCardBookingPaymentRow";
// the above parameter can be taken from the users web service
// (?WSDL)
// url
SoapObject request = new SoapObject(NAMESPACE,METHOD_NAME);
SoapObject innerRequest = new SoapObject(NAMESPACE,INNER_METHOD_NAME);
innerRequest.addProperty("tem:ProfessionalUserMappingStudioID", bookingDetailsList.get(0).getUserMappingStudioID());
innerRequest.addProperty("tem:ConsumerUserMappingStudioID",loginCredentials.getUserMappingStudioId());
innerRequest.addProperty("tem:Cost",bookingDetailsList.get(0).getCost());
innerRequest.addProperty("tem:CardNumber", creditCardNo);
innerRequest.addProperty("tem:CardHolderName", creditCardHolder);
innerRequest.addProperty("tem:ExpirationDate", expirationDate);
innerRequest.addProperty("tem:CVV", cvv);
innerRequest.addProperty("tem:ProfessionalSessionID",bookingDetailsList.get(0).getProfessionalSessionID());
innerRequest.addProperty("tem:TxRefNum", "");
request.addProperty("tem:objCreditCardBookingPaymentRow",innerRequest);
utils.sysOut("some text", "" + request);
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.dotNet = true;
envelope.setOutputSoapObject(request);
HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
androidHttpTransport.call(SOAP_ACTION, envelope);
SoapObject resultsRequestSOAP = (SoapObject) envelope.bodyIn;
String str = resultsRequestSOAP.toString();
Log.v("TAG_SOAP_ACTION", str);
Try like this:
SoapObject res=(SoapObject)envelope.bodyIn;
SoapObject t=(SoapObject)res.getProperty("MakeCreditCardPayment");
for(int i=0; i<t.getPropertyCount(); i++){
SoapObject carditCard=(SoapObject)t.getProperty(i);
String userID = carditCard.getProperty("ProfessionalUserMappingStudioID").toString();
}

Modify response of web service with JAX-WS

How can I modify the namespace of the response like this:
old response:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns2:GetAmountResponse xmlns:ns2="http://ws.dsi.otn.com/dab">
<etat>0</etat>
<montant>500.0</montant>
</ns2:GetAmountResponse>
</soap:Body>
</soap:Envelope>
new response wanted :
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<GetAmountResponse xmlns="http://ws.dsi.otn.com/dab">
<etat>0</etat>
<montant>500.0</montant>
</GetAmountResponse>
</soap:Body>
</soap:Envelope>
I want to remove the ns2 namespce prefix.
In the first case, the GetAmountResponse is in namespace http://ws.dsi.otn.com/dab while etat and montant are in a default (empty) namespace.
In the new message you want, GetAmountResponse, etat and montant are all in namespace http://ws.dsi.otn.com/dab.
The namespaces can be controlled from the namespaces of your classes. Use the same namespace in all and you will have them in the same namespace, leave classes with defaults and they default to empty namespace.
For example, if you were to have something like this in your web service class:
#WebMethod
public
#WebResult(name = "getAmountResponse", targetNamespace = "http://ws.dsi.otn.com/dab")
AmountResponse getAmount(
#WebParam(name = "getAmountRequest", targetNamespace = "http://ws.dsi.otn.com/dab") AmountRequest request) {
AmountResponse response = new AmountResponse();
response.setEtat(0);
response.setMontant(500.0);
return response;
}
with a response class like this:
#XmlRootElement
public class AmountResponse {
private int etat;
private double montant;
// getter and setters omitted
}
you will end up with the first type of soap message.
But if you change the response class to look like this instead:
#XmlRootElement(namespace = "http://ws.dsi.otn.com/dab")
#XmlAccessorType(XmlAccessType.NONE)
public class AmountResponse {
#XmlElement(namespace = "http://ws.dsi.otn.com/dab")
private int etat;
#XmlElement(namespace = "http://ws.dsi.otn.com/dab")
private double montant;
// getters and setter omitted
}
you will bring all tags in the same namespace and you get something equivalent to the new type of message you want. I said equivalent because I don't think you will get exactly this:
<GetAmountResponse xmlns="http://ws.dsi.otn.com/dab">
<etat>0</etat>
<montant>500.0</montant>
</GetAmountResponse>
It's more likely to get something like this instead:
<ns2:getAmountResponse xmlns:ns2="http://ws.dsi.otn.com/dab">
<ns2:etat>0</ns2:etat>
<ns2:montant>500.0</ns2:montant>
</ns2:getAmountResponse>
It's the same "XML meaning" for both messages although they don't look the same.
If you absolutely want it to look like that, I think you will have to go "low level" and use something like a SOAP handler to intercept the response and modify it. But be aware that it won't be a trivial task to change the message before it goes on the wire.
logical handler are enough to transform to the message as expected :
package com.ouertani.slim;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.ws.LogicalMessage;
import javax.xml.ws.handler.LogicalHandler;
import javax.xml.ws.handler.LogicalMessageContext;
import javax.xml.ws.handler.MessageContext;
/**
*
* #author ouertani
*/
public class MyLogicalHandler implements LogicalHandler<LogicalMessageContext> {
#Override
public boolean handleMessage(LogicalMessageContext messageContext) {
/// extract state and amount
int state = 0;
double amount = 200.0;
transform(messageContext, state, amount);
return false;
}
public boolean handleFault(LogicalMessageContext messageContext) {
return true;
}
public void close(MessageContext context) {
}
private void transform( LogicalMessageContext messageContext, int etat, double montant){
LogicalMessage msg = messageContext.getMessage();
String htom = "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"+
"<soap:Body>"+
"<GetAmountResponse xmlns=\"http://ws.dsi.otn.com/dab\">"+
"<etat>"+etat+"</etat>"+
"<montant>"+montant+"</montant>"+
"</GetAmountResponse>"+
"</soap:Body>"+
"</soap:Envelope>";
InputStream is = new ByteArrayInputStream(htom.getBytes());
Source ht = new StreamSource(is);
msg.setPayload(ht);
}
}
This is a very old question, still it is yet to be effectively answered. This week I faced a very similar problem. My application is invoking a Soap web-service provided by a legacy system whose XML is response syntactically wrong with some empty characters (line break, or tabs or white spaces) before XML declaration. In my scenario I could not change the legacy system to fix its response so changing the response before parsing was the only alternative I was left with.
Here is my solution:
I have added the following maven dependencies to my application:
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>javax.xml.ws</groupId>
<artifactId>jaxws-api</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.ws</groupId>
<artifactId>jaxws-rt</artifactId>
<version>2.3.0</version>
</dependency>
Then I have registered a Java SPI custom implementation of “com.oracle.webservices.impl.internalspi.encoding.StreamDecoder”. This class is invoked immediately before the XML parse with the corresponding response InputStream, so at this point you can read the response InputStream or wrap/proxy it and make any change to jax-ws response before parsing. In my case I just remove some invisible characters before first visible character.
My StreamDecoder SPI implementation:
package sample.streamdecoder;
import com.oracle.webservices.impl.encoding.StreamDecoderImpl;
import com.oracle.webservices.impl.internalspi.encoding.StreamDecoder;
import com.sun.xml.ws.api.SOAPVersion;
import com.sun.xml.ws.api.message.AttachmentSet;
import com.sun.xml.ws.api.message.Message;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
public class MyStreamDecoder implements StreamDecoder {
//JAX-WS default implementation
private static final StreamDecoderImpl streamDecoder = new StreamDecoderImpl();
#Override
public Message decode(InputStream inputStream, String charset, AttachmentSet attachmentSet, SOAPVersion soapVersion) throws IOException {
//Wrapping inputStream
InputStream wrapped = wrapInputStreamStrippingBlankCharactersBeforeXML(inputStream, charset);
//Delegating further processing to default StreamDecoder
return streamDecoder.decode(wrapped, charset, attachmentSet, soapVersion);
}
private InputStream wrapInputStreamStrippingBlankCharactersBeforeXML(InputStream inputStream, String charset) throws IOException {
int WHITESPACE = (int) Charset.forName(charset).encode(" ").get();
int LINE_BREAK = (int) Charset.forName(charset).encode("\n").get();
int TAB = (int) Charset.forName(charset).encode("\t").get();
return new InputStream() {
private boolean xmlBegin = true;
#Override
public int read() throws IOException {
int read = inputStream.read();
if (!xmlBegin) {
return read;
} else {
while (WHITESPACE == read
|| LINE_BREAK == read
|| TAB == read) {
read = inputStream.read();
}
xmlBegin = false;
}
return read;
}
};
}
}
In order to register it, just create a file “META-INF/services/ com.oracle.webservices.impl.internalspi.encoding.StreamDecoder” named “” and write the fully qualified name of your SPI implementation on the first line like that:
Content of file META-INF/services/ com.oracle.webservices.impl.internalspi.encoding.StreamDecoder :
sample.streamdecoder.MyStreamDecoder
Now every response will be passed to you implementation before parse.

xalan and custom function for xslt

I'm using Apache FOP with the IKVM from my c# code. I generate the pdf by using the xslt stylesheet to get the result as xsl fo. I have one problem, that is usingthe custom functions.
My stylesheet declaration:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:cal="xalan://m.test"
extension-element-prefixes="cal"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.w3.org/2001/XMLSchema-instance http://www.xmlblueprint.com/documents/fop.xsd">
The custom function:
namespace m
{
public class test
{
public static string zzz(ExpressionContext x, object d)
{
return "test";
}
}
}
And calling this from the xslt:
<xsl:value-of select="cal:zzz(1)"/>
Code to compile it:
FopFactory fopFactory = FopFactory.newInstance();
fopFactory.ignoreNamespace("http://www.w3.org/2001/XMLSchema-instance");
fopFactory.setUserConfig(new File("fop.xconf"));
OutputStream o = new DotNetOutputMemoryStream();
try
{
Fop fop = fopFactory.newFop("application/pdf", o);
TransformerFactory factory = TransformerFactory.newInstance();
Source xsltSrc = new StreamSource(new File("data.xsl"));
Transformer transformer = factory.newTransformer(xsltSrc);
var bytes = System.IO.File.ReadAllBytes("data.xml"); //"HR_CV.fo");
var stream = new DotNetInputMemoryStream(new System.IO.MemoryStream(bytes));
Source src = new StreamSource(stream);
Result res = new SAXResult(fop.getDefaultHandler());
transformer.transform(src, res);
}
finally
{
o.close();
}
Exception I got is:
java.lang.NoSychMethodExtension: For extension function, could not find method org.apache.xml.utils.NodeVector.zzz([ExpressionContext,])
What I'm doing wrong?
You're calling the zzz function with a single argument (1). But your function expects two arguments. If you provide both arguments, chances are it will work just fine.

null values for java.util.Date input/output in web service methods

I have a webservice created with jax-ws and netbeans 7's wizard (this is my first time) .
to use java.util.Date instead of XmlGregorianCalendar, I have modified the client's webservice with this xml :
<?xml version="1.0" encoding="UTF-8"?>
<jaxws:bindings node="wsdl:definitions/wsdl:types/xsd:schema"
xmlns:jaxws="http://java.sun.com/xml/ns/jaxws"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<jaxb:globalBindings>
<jaxb:serializable/>
<jaxb:javaType name="java.util.Date" xmlType="xsd:dateTime"/>
</jaxb:globalBindings>
</jaxws:bindings>
Date is now used instead of XmlGregorianCalendar and an Adapter1 is generated :
public class Adapter1
extends XmlAdapter<String, Date>
{
public Date unmarshal(String value) {
return new Date(value);
}
public String marshal(Date value) {
if (value == null) {
return null;
}
return value.toString();
}
}
When i add a system.out.println in the adapter i see that the Date is received/sent to the server but if i use ws's methods i get always null on Date field/parameters .
Thanks .
The XmlAdapter that is generated is not going to perform the desired conversions. The default XmlAdapter expects the following to work:
Foo foo1 = new Foo(foo2.toString());
Which is not valid in this case:
Date date1 = new Date(date2.toString());
You will need to write some conversion code and reference it from an external bindings file:
<jxb:bindings xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb" version="2.1">
<jxb:bindings schemaLocation="format.xsd">
<jxb:bindings node="//xs:element[#name='my-date']">
<jxb:property>
<jxb:baseType>
<jxb:javaType name="java.util.Date"
parseMethod="org.example.DateFormatter.parseInt"
printMethod="org.example.DateFormatter.printInt" />
</jxb:baseType>
</jxb:property>
</jxb:bindings>
</jxb:bindings>
</jxb:bindings>
For More Information
http://blog.bdoughan.com/2011/08/xml-schema-to-java-generating.html