Spring and CastorMarshaller: add namespace to XML root - java

My Java application tries to get information from a webservice. The XML request needs to have the namespace specified in the XML root element (class name), but the namespace of the tags (class fields) need to be empty (null), otherwise the webservice rejects the request.
I have to use Spring 3.0 and Spring WS 2.0 with CastorMarshaller (currently using Castor version 1.3.1) to marshall/unmarshall my Java objects into/from XML.
Please note the __PREFIX__ and __NAMESPACE__ locations in following code snippets.
Desired marshalled output
(i.e. the desired generated SOAP request)
<?xml version="1.0" encoding="UTF-8"?>
<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
<soap-env:Header xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/" />
<soap-env:Body xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
<__PREFIX__:className xmlns:__PREFIX__="__NAMESPACE__">
<fieldName>fieldValue</fieldName>
</__PREFIX__:className>
</soap-env:Body>
</soap-env:Envelope>
Currently marshalled output (i.e. the generated SOAP request)
Not adding the namespace
<?xml version="1.0" encoding="UTF-8"?>
<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
<soap-env:Header xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/" />
<soap-env:Body xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
<className>
<fieldName>fieldValue</fieldName>
</className>
</soap-env:Body>
</soap-env:Envelope>
or adding the namespace to all elements
<?xml version="1.0" encoding="UTF-8"?>
<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
<soap-env:Header xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/" />
<soap-env:Body xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
<__PREFIX__:className xmlns:__PREFIX__="__NAMESPACE__">
<__PREFIX__:fieldName xmlns:__PREFIX__="__NAMESPACE__">fieldValue</__PREFIX__:fieldName>
</__PREFIX__:className>
</soap-env:Body>
</soap-env:Envelope>
which are both rejected by the webservice.
My configuration
CastorMarshaller bean in applicationContext.xml
<bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller">
<property name="mappingLocation" value="classpath:castor-mapping.xml" />
<property name="ignoreExtraAttributes" value="true" />
<property name="ignoreExtraElements" value="true" />
<property name="namespaceMappings">
<map>
<entry key="__PREFIX__" value="__NAMESPACE__" />
</map>
</property>
</bean>
Castor Mapping file castor-mapping.xml
Not adding the namespace (namespace specified in the castorMarshaller bean through namespaceMappings should be added to the root)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN"
"http://castor.org/mapping.dtd">
<mapping>
<class name="some.package.ClassName">
<map-to xml="className">
<field name="fieldName" type="string">
<bind-xml name="fieldName" node="element" />
</field>
</class>
</mapping>
or adding the namespace to all elements
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN"
"http://castor.org/mapping.dtd">
<mapping>
<class name="some.package.ClassName">
<map-to xml="className" ns-uri="__NAMESPACE__" ns-prefix="__PREFIX__">
<field name="fieldName" type="string">
<bind-xml name="fieldName" node="element" />
</field>
</class>
</mapping>

Since I am facing the same problem, a solution that I am considering is the following:
Create a interceptor extending EndpointInterceptorAdapter
Override handleResponse method
Modify to soap message by directly access or using a transformer
public class MyEndpointInterceptorAdapter extends
EndpointInterceptorAdapter{
#Override
public boolean handleResponse(MessageContext msgContext, Object endpoint) throws IOException {
WebServiceMessage responseMsg = msgContext.getResponse();
SoapMessage soapMsg = (SoapMessage) responseMsg;
if(soapMsg!=null){
SoapEnvelope soapEnvelope=soapMsg.getEnvelope();
if(soapEnvelope!=null){
SoapBody soapbody=soapEnvelope.getBody();
if(soapbody!=null){
Source bodySource=soapbody.getSource();
if(bodySource instanceof DOMSource){
DOMSource bodyDomSource=(DOMSource)bodySource;
Node bodyNode=bodyDomSource.getNode();
if(bodyNode!=null){
NodeList bodyNodeList=bodyNode.getChildNodes();
if(bodyNodeList.getLength()!=0){
Element root=(Element)bodyNodeList.item(0);
root.setAttribute("xmlns:ns", "YourURI");
root.setPrefix("ns");
}
}
}
}
}
}
return true;
}
}

Related

Generating Header fields in XML file by BeanIO

I'm trying to generate the following xml file which has 2 fields as Header and the Repeating section "rec" node :
<?xml version="1.0" encoding="UTF-8"?>
<transaction>
<createDate>20160708</createDate>
<dlrCode>100<dlrCode/>
<rec>
<processDate>20190108</processDate>
<srcID/>10<srcID/>
</rec>
<rec>
<processDate>20190108</processDate>
<srcID/>11<srcID/>
</rec>
<rec>
<processDate>20190108</processDate>
<srcID/>12<srcID/>
</rec>
</transaction>
This is the mapping file which I created:
<?xml version="1.0" encoding="UTF-8"?>
<beanio xmlns="http://www.beanio.org/2012/03"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.beanio.org/2012/03 http://www.beanio.org/2012/03/mapping.xsd">
<stream name="dist" format="xml" xmlName="transaction" >
<record name="HeaderRecord" class="com.myPackage.HeaderRecord" minOccurs="1" maxOccurs="1" order="1" >
<field name="createDate" format="yyyyMMdd" />
<field name="dlrCode" />
</record>
<record name="DisRecord" class="com.myPackage.Record" minOccurs="0" maxOccurs="unbounded" xmlName="rec" order="2">
<field name="processDate" format="yyyyMMdd"/>
<field name="srcID"/>
</record>
</stream>
</beanio>
But the problem is, it generates the header fields inside the HeaderRecord node like this:
<?xml version="1.0" encoding="UTF-8"?>
<transaction>
<HeaderRecord>
<createDate>20160708</createDate>
<dlrCode>100<dlrCode/>
</HeaderRecord>
<rec>
<processDate>20190108</processDate>
<srcID/>10<srcID/>
</rec>
<rec>
<processDate>20190108</processDate>
<srcID/>11<srcID/>
</rec>
<rec>
<processDate>20190108</processDate>
<srcID/>12<srcID/>
</rec>
</transaction>
Is there something misconfigured in the mapping file? How to achieve the desired output?
By using the xmlType="none" attribute you can control if an xml element should be produced or not. The xmlName is by default equal to the record name when you don't specify a xmlName attribute, see here. A record will always be mapped to an xml element and with the use of segments, you might be able to get the desired output.
Try this mapping file:
<stream name="dist" format="xml" xmlType="none" >
<record name="HeaderRecord" class="com.mypackage.HeaderRecord" minOccurs="1" maxOccurs="1" xmlName="transaction">
<segment name="dummy" xmlType="none">
<field name="createDate" format="yyyyMMdd" />
<field name="dlrCode" />
</segment>
</record>
I don't think it is 100% what you are looking for though.

Can't unmarshall REST response Spring-Jibx

I have a problem unmarshalling a RESTful request body using Spring and Jibx.
This is the request body I'm sending through Postman:
<?xml version="1.0" encoding="utf-8"?>
<locationRequest xmlns="urn:ietf:params:xml:ns:geopriv:held" responseTime="30000">
<locationType exact="true">
geodetic
civic
locationURI
</locationType>
<device xmlns="urn:ietf:params:xml:ns:geopriv:held:id">
<uri>tel:123456789;phone-context=+1</uri>
</device>
</locationRequest>
This is my binding.xml
...
<mapping name="locationRequest" class="com.example.integrations.models.LocationRequest" ordered="true">
<namespace uri="urn:ietf:params:xml:ns:geopriv:held" default="elements" />
<value name="responseTime" field="responseTime" style="attribute" usage="optional"/>
<structure name="locationType" field="locationType" map-as="locationType" usage="required"/>
<structure field="device" usage="required"/>
</mapping>
<mapping name="device" class="com.example.integrations.models.Device" >
<namespace uri="urn:ietf:params:xml:ns:geopriv:held:id" default="elements" />
<value name="uri" field="uri" />
</mapping>
<mapping abstract="true" type-name="locationType" class="com.example.integrations.models.LocationType">
<value name="exact" field="exact" style="attribute"/>
<value field="types" style="text"
serializer="com.example.integrations.ParseUtil.serializeStringList"
deserializer="com.example.integrations.ParseUtil.deserializeStringList" />
</mapping>
...
When I run the Jibx compiler everything is fine and all classes are detected and modified by the compiler correctly
This is the method that receive the web service call:
The request its unmarshalled correctly if I use a .xml file as the input, but if I go through the web service its missing some data:
...
<locationType exact="true">
geodetic
civic
locationURI
</locationType>
...
The "exact" attribute is parsed correctly, but the content, while on the xml file was parsed ok, is missing in the web service object... and for the love of me I can't figure out why.
(Note: Also the response object (LocationResponse) is not marshalled correctly when returning to Postman)
This is my Spring-servlet configuration relevant to jibx:
...
<beans:bean id="unmarshaller" class="org.springframework.oxm.jibx.JibxMarshaller">
<beans:property name="targetClass" value="org.dellroad.jibxbindings.pidf.held.LocationRequest"/>
<beans:property name="bindingName" value="locationRequest"/>
</beans:bean>
<beans:bean id="marshaller" class="org.springframework.oxm.jibx.JibxMarshaller">
<beans:property name="targetClass" value="org.dellroad.jibxbindings.pidf.held.LocationRequest"/>
<beans:property name="bindingName" value="locationRequest"/>
</beans:bean>
...
What am I missing here? I suspect is a missconfiguration in the Spring side

Unable to Load Key Value Pair XML as java preferences

I am new to XML. I am trying to define key value pairs in XML so that this file can be used as configuration file for my project. I am getting errors while I am loading this xml file in java. Please let me know how to fix this issue.
XML file (data.xml):
<?xml version="1.0"?>
<object>
<field name="property1" value="1">
<field name="property2" value="2">
<field name="property3" value="3">
<field name="property4" value="4">
</object>
</xml>
Java Code:
import java.io.*;
import java.util.*;
import java.util.prefs.Preferences;
public class PreferencesExample {
public static void main(String args[]) throws FileNotFoundException {
Preferences ps = Preferences.userNodeForPackage(PreferencesExample.class);
// Load file object
File fileObj = new File("data.xml");
try {
FileInputStream fis = new FileInputStream(fileObj);
ps.importPreferences(fis);
System.out.println("Prefereces:"+ps);
System.out.println("Get property1:"+ps.getInt("property1",10));
} catch (Exception err) {
err.printStackTrace();
}
}
}
I got below error while I load this xml in java.
>
java.util.prefs.InvalidPreferencesFormatException: org.xml.sax.SAXParseException;
lineNumber: 2; columnNumber: 9; Document root element "object", must match DOCTYPE root "null".
at java.util.prefs.XmlSupport.importPreferences(XmlSupport.java:216)
at java.util.prefs.Preferences.importPreferences(Preferences.java:1259)
What would be possible root cause? I am suspecting XML file format but I don't have expertise in XML
Your xml file should be in the below format
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE preferences SYSTEM 'http://java.sun.com/dtd/preferences.dtd'>
<preferences EXTERNAL_XML_VERSION="1.0">
<root type="user">
<map />
<node name="com">
<map />
<node name="mypack">
<map />
<node name="test">
<map>
<entry key="property1" value="80" />
<entry key="property2" value="Red" />
</map>
</node>
</node>
</node>
</root>
</preferences>
and the node names are the package name of the class PreferencesExample. In this example, it is com/mypack/test.
this link might be helpful for java preferences

CXF WADL2Java does not produce the right input parameters

I went through the documentation, which helped me figure out several issues I had, but not the following two problems:
1) I have got a get(GET) method: get(#Context Request request, #PathParam("isbn")String isbn)
How do I formulate the WADL for it so that I get the #Context in the produced Java code?
2) I have got a update (PUT) method: update(#PathParam("isbn") String isbn, BookState st)
How do I formuate the WADL to get the BookState in the produced Java code?
Here is my current WADL, which does not do it:
<resource path="/{isbn}">
....
<method name="GET" id="get" >
<request />
<response>
<representation mediaType="application/xml" element="prefix1:book" />
</response>
</method>
<method name="PUT" id="update" >
<request>
<representation mediaType="application/xml" element="prefix1:book" />
</request>
<response>
<representation mediaType="application/octet-stream" />
</response>
</method>
</resource>

How to disable namespace validation in JiBX?

I have a JiBX binding file that specifies namespaces. However, I want to turn off namespace validation so that even an XML message with invalid namespace could be unmarshalled.
I have a binding file like the following:
<binding name="test_binding">
<namespace prefix="soapenv" uri="http://www.w3.org/2003/05/soap-envelope" />
<!-- Envelope -->
<mapping name="Envelope" ns="http://www.w3.org/2003/05/soap-envelope"
class="com.test.data.Envelope">
<structure get-method="getHeader" set-method="setHeader"
ns="http://www.w3.org/2003/05/soap-envelope" usage="optional" />
<structure get-method="getBody" set-method="setBody"
ns="http://www.w3.org/2003/05/soap-envelope" usage="optional" />
</mapping>
...
I pass the following message to JiBX unmarshaller (with different namespace for Envelope element):
<?xml version="1.0" encoding="UTF-8" ?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope">
<soapenv:Header>
<MyElement>
....
The following shows the error message when JiBX unmarshalls the message:
[Time:2011-10-04 17:39:29,802][Level:FATAL]org.jibx.runtime.JiBXException: No unmarshaller for element "{http://schemas.xmlsoap.org/soap/envelope}Envelope" (line 2, col 76)
...
Is there a way to disable namespace validation in JiBX? Thanks.

Categories

Resources