jaxb, separate namespace for child element - java

I am trying to create XML using jaxb like below format, where child element has separate name space.
<soap:Envelope xmlns:soap="http://demo.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Header>
<element1 xmlns="http://childnamespacehere">
<att1>test</att1>
<att2>test</att2>
</element1>
</soap:Header>
<soap:Body>
<element2 xmlns="http://childnamespacehere">
<att1>test</att1>
<att2>test</att2>
</element2 >
</soap:Body>
</soap:Envelope>
my class
#XmlRootElement(name = "soap:Envelope", namespace = "http://schemas.xmlsoap.org/soap/envelope/")
public class Envelope
private Element1 element1;
private Element2 element2;
#XmlElementWrapper(name = "soap:Header")
#XmlElement(name = "Element1", namespace = "http://childelementnamespace/")
public void setElement1(Element1 element){ }
#XmlElementWrapper(name = "soap:Body")
#XmlElement(name = "Element2" , namespace = "http://childelementnamespace/")
public void setElement2(Element2 element){ }
but i am getting xml generated like below, where child schema is at root level.
<soap:Envelope xsi:schemaLocation="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns2="http://childelementnamespace/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soap:Header>
<ns2:Element1>
<att1>value</att1>
<att2>value</att2>
</ns2:Element1>
</soap:Header>
<soap:Body>
<ns2:Element2>
<att1>value</att1>
<att2>value</att2>
</ns2:Element2>
</soap:Body>
</soap:Envelope>
i have #xmlschema defined in package-info.java
#XmlSchema(namespace = "http://schemas.xmlsoap.org/soap/envelope/",
xmlns = { #javax.xml.bind.annotation.XmlNs(prefix = "Element1", namespaceURI = "http://childelementnamespace"),
#javax.xml.bind.annotation.XmlNs(prefix = "Element2", namespaceURI = "http://childelementnamespace") },
elementFormDefault = XmlNsForm.QUALIFIED)
package com.model;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
when i generate xml , name space for child elements are not getting generated , i only get namespace for root element.

i have solved by adding "xmlns" attribute to objects (childnode) Element1 and Element2.
class Elemenet1
#XmlAttribute(name="xmlns")
String xmlns = "http://childnamespacehere";
public void setXmlns(String namespace){};
public String getXmlns(){};
Output
<soap:Envelope xmlns:soap="http://demo.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Header>
<element1 xmlns="http://childnamespacehere">
<att1>test</att1>
<att2>test</att2>
</element1>
</soap:Header>
<soap:Body>
<element2 xmlns="http://childnamespacehere">
<att1>test</att1>
<att2>test</att2>
</element2 >
</soap:Body>
</soap:Envelope>

In where you say what is being generated is has xmlns:ns2="http://childelementnamespace/" up the top, this is declaring the namespace and used in this fashion <ns2:Element2> using ns2 here uses tha namspace declared previously.
So what you are expecting and what you are getting are the exact same just declared in different places, the jaxB method is more correct as it is not declaring the same namespace more than once.

This is a temporary solution. This triggers major problems when you want to unmarshall a xml document.
But you can use different packages for marshall and unmarshall process too.

Related

How to upgrade java 8 SOAP call to java 11 SOAP call using feign

I'm moving from java 8 to java 11. I have integration with old style SOAP 1.2 service. Because of cutting of JEE web services stuff from java 11 extending from javax.xml.ws.Service and call super.getPort(new QName(...), SomeWebService.class, someFeatures); from generated sources is not working for me any more.
So I decided to use for this SOAP call OpenFeign https://github.com/OpenFeign/feign#soap , https://github.com/OpenFeign/feign/tree/master/soap
Service I would like to call is:
SOAP 1.2 based
charset is utf-8
Content-Type request: application/soap+xml
Content-Type response: application/xop+xml
The call I would like to do looks like this in plain xml:
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:ns="http://CIS/BIR/PUBL/2014/07">
<soap:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsa:To>https://wyszukiwarkaregontest.stat.gov.pl/wsBIR/UslugaBIRzewnPubl.svc</wsa:To>
<wsa:Action>http://CIS/BIR/PUBL/2014/07/IUslugaBIRzewnPubl/Zaloguj</wsa:Action>
</soap:Header>
<soap:Body>
<ns:Zaloguj>
<ns:pKluczUzytkownika>theUsersKey</ns:pKluczUzytkownika>
</ns:Zaloguj>
</soap:Body>
</soap:Envelope>
What I did using OpenFeign was interface for connecting:
import my.domain.schema.cis.bir.publ._2014._07.Zaloguj;
import feign.Headers;
import feign.RequestLine;
public interface MyWebServiceCallInterface {
#RequestLine("POST /")
#Headers({
"SOAPAction: http://CIS/BIR/PUBL/2014/07/IUslugaBIRzewnPubl/Zaloguj",
"Content-Type: application/soap+xml"
})
String zaloguj(Zaloguj zaloguj);
}
Zaloguj class looks like this:
import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElementRef;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"pKluczUzytkownika"
})
#XmlRootElement(name = "Zaloguj")
public class Zaloguj {
#XmlElementRef(name = "pKluczUzytkownika", namespace = "http://CIS/BIR/PUBL/2014/07", type = JAXBElement.class, required = false)
protected JAXBElement<String> pKluczUzytkownika;
public JAXBElement<String> getPKluczUzytkownika() {
return pKluczUzytkownika;
}
public void setPKluczUzytkownika(JAXBElement<String> value) {
this.pKluczUzytkownika = value;
}
}
and I have implemented service with SOAP calling:
public ResponseEntity callSOAPService() {
JAXBContextFactory jaxbFactory = new JAXBContextFactory.Builder()
.withMarshallerJAXBEncoding("UTF-8") .withMarshallerSchemaLocation("https://wyszukiwarkaregon.stat.gov.pl/wsBIR/wsdl/UslugaBIRzewnPubl-ver11-prod.wsdl")
.build();
MyWebServiceCallInterface myWebServiceCallInterface = Feign.builder()
.encoder(new SOAPEncoder(jaxbFactory))
.decoder(new SOAPDecoder(jaxbFactory))
.target(MyWebServiceCallInterface.class, "https://wyszukiwarkaregon.stat.gov.pl/wsBIR/UslugaBIRzewnPubl.svc");
ObjectFactory objectFactory = new ObjectFactory();
JAXBElement<String> userKeyElement =objectFactory.createZalogujPKluczUzytkownika("topSecretUserKey");
Zaloguj zaloguj = new Zaloguj();
zaloguj1.setPKluczUzytkownika(userKeyElement);
String result = myWebServiceCallInterface.zaloguj(zaloguj);
}
But for this call I've received:
feign.FeignException$BadRequest: [400 Bad Request] during [POST] to [https://wyszukiwarkaregon.stat.gov.pl/wsBIR/UslugaBIRzewnPubl.svc/] [MyWebServiceCallInterface#zaloguj(Zaloguj)]: []
I was trying to debug and in Feign SynchronousMethodHandler method executeAndDecode has a template field with value:
POST / HTTP/1.1
Content-Length: 511
Content-Type: application/soap+xml
SOAPAction: http://CIS/BIR/PUBL/2014/07/IUslugaBIRzewnPubl/Zaloguj
<?xml version="1.0" encoding="UTF-8" ?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header/><SOAP-ENV:Body><Zaloguj xmlns="http://CIS/BIR/PUBL/2014/07" xmlns:ns2="http://CIS/BIR/PUBL/2014/07/DataContract" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://wyszukiwarkaregon.stat.gov.pl/wsBIR/wsdl/UslugaBIRzewnPubl-ver11-prod.wsdl"><pKluczUzytkownika>b7e7df92129b4e25aeab</pKluczUzytkownika></Zaloguj></SOAP-ENV:Body></SOAP-ENV:Envelope>
and in Feign ErrorDecoder method decode has request field with value:
POST https://wyszukiwarkaregon.stat.gov.pl/wsBIR/UslugaBIRzewnPubl.svc/ HTTP/1.1
Content-Length: 511
Content-Type: application/soap+xml
SOAPAction: http://CIS/BIR/PUBL/2014/07/IUslugaBIRzewnPubl/Zaloguj
<?xml version="1.0" encoding="UTF-8" ?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header/><SOAP-ENV:Body><Zaloguj xmlns="http://CIS/BIR/PUBL/2014/07" xmlns:ns2="http://CIS/BIR/PUBL/2014/07/DataContract" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://wyszukiwarkaregon.stat.gov.pl/wsBIR/wsdl/UslugaBIRzewnPubl-ver11-prod.wsdl"><pKluczUzytkownika>b7e7df92129b4e25aeab</pKluczUzytkownika></Zaloguj></SOAP-ENV:Body></SOAP-ENV:Envelope>
Maybe some on of You know how to fix it?
Did I make something wrong in my MyWebServiceCallInterface implementation?
I'm looking forward for Your advises!

How to map XML to POJO

I have the following result:
<Result xmlns="urn:buscape" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" totalResultsAvailable="1" totalResultsReturned="1" totalPages="1" page="1" totalLooseOffers="0" xsi:schemaLocation="http://developer.buscape.com/admin/lomadee.xsd">
<details>
<applicationID>999999999999999</applicationID>
<applicationVersion>1.0</applicationVersion>
<applicationPath/>
<date>2016-09-12T23:50:19.722-03:00</date>
<elapsedTime>19</elapsedTime>
<status>success</status>
<code>0</code>
<message>success</message>
</details>
<lomadeeLinks>
<lomadeeLink>
<id>1</id>
<originalLink>link</originalLink>
<redirectLink>link2</redirectLink>
<code>0</code>
</lomadeeLink>
</lomadeeLinks>
</Result>
Looking at "2.7.4 Retrieving XML data via HTTP GET", I have to map this XML to POJO-like object in Java, here is the question, I can't find the #Root and #Element annotation and I'm not sure how to correctly map the XML into a Java object.
If you are using spring/springboot then simply you can use
(YourPOJO)getWebServiceTemplate().marshalSendAndReceive(yourSOAPService);
POJO :-
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"getOrdersResponse"
})
#XmlRootElement(name = "nameOfTag", namespace = "http://example.org/yourResource")
public class GetOrdersByDateResult {
#XmlElement(name = "GetOrdersResponse")
protected GetOrdersResponseType getOrdersResponse;
getter();
setter();
}

Jaxb: Generating XML with different root element included in class which is being marshalled?

I am trying to create Companies House XML using JAXB which has following format
<GovtTalkMessage schemaLocation="schema1" xlmns="" xlmns:bs= "" xlmns:gt="">
<Header> .... </Header>
<Body>
<FormSubmission schemaLocation="schema2" xlmns="" xlmns:xx="">
.....
<CompanyIncorporation schemaLocation="schema3" xlmns="" xlmns:yy="">
...
</CompanyIncorporation>
</FormSubmission>
</Body>
</GovtTalkMessage>
XML structure has been generated correctly apart from schemalocations and xlmns, schemalocation are not generation for any of the element where it should be and all xmlns of are visible in <GovtTalkMessage> like
<GovtTalkMessage schemaLocation="schema1" xlmns="" xlmns:bs= "" xlmns:gt="" xlmns:xx="" xlmns:yy="">
FormSubmission and CompanyCorporation are generated as #XmlRootElement by xjc.
Relevant #XmlSchema properties for xmlns and schemalocation value are added in package-info.java , also tried #XmlElementDecl as suggested here but it did not help me.
CompanyIncorportion package-info.java :
#XmlSchema(namespace = "",
xmlns = {
#XmlNs(namespaceURI = "http://xmlgw.companieshouse.gov.uk", prefix = ""),
#XmlNs(namespaceURI = "http://www.w3.org/2001/XMLSchema-instance" , prefix="xsi")
},
location = "http://xmlgw.companieshouse.gov.uk http://xmlgw.companieshouse.gov.uk/v2-1/schema/forms/CompanyIncorporation-v2-6.xsd",
elementFormDefault = javax.xml.bind.annotation.XmlNsForm.UNSET)
package com.xx.ch;
import javax.xml.bind.annotation.XmlNs;
import javax.xml.bind.annotation.XmlSchema;
Gateway package-info.java :
#XmlSchema(namespace = "",
xmlns = {
#XmlNs(namespaceURI = "http://www.w3.org/2000/09/xmldsig#", prefix = "dsig"),
#XmlNs(namespaceURI = "http://www.govtalk.gov.uk/schemas/govtalk/core", prefix = "gt"),
#XmlNs(namespaceURI = "http://www.w3.org/2001/XMLSchema-instance" , prefix="xsi")
},
location = "http://www.govtalk.gov.uk/CM/envelope http://xmlgw.companieshouse.gov.uk/v1-0/schema/Egov_ch-v2-0.xsd",
elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package com.xx.gateway;
import javax.xml.bind.annotation.XmlNs;
import javax.xml.bind.annotation.XmlSchema;
FormSubmission package-info.java :
#XmlSchema(namespace = "",
xmlns = {
#XmlNs(namespaceURI = "http://xmlgw.companieshouse.gov.uk", prefix = "bs"),
#XmlNs(namespaceURI = "http://xmlgw.companieshouse.gov.uk/Header", prefix = ""),
#XmlNs(namespaceURI = "http://www.w3.org/2001/XMLSchema-instance" , prefix="xsi")
},
// location ="http://xmlgw.companieshouse.gov.uk/Header http://xmlgw.companieshouse.gov.uk/v2-1/schema/forms/FormSubmission-v2-7.xsd" ,
//#javax.xml.bind.annotation.XmlSchema(namespace = "http://xmlgw.companieshouse.gov.uk/Header",
elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package com.xx.formsubmission;
import javax.xml.bind.annotation.XmlNs;
How can I generate schemalocations and xmlns where they are required by Gateway?
You need to use the #XmlSchema annotation on your package.
You can do this by adding package-info.java to the same package as your JAXB-annotated classes.
See the javadoc for examples:
http://docs.oracle.com/javaee/6/api/javax/xml/bind/annotation/XmlSchema.html
You can set the Marshaller.JAXB_SCHEMA_LOCATION on the Marshaller to output the schemaLocation:
marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, "http://www.example.com/address address.xsd")
For More Information
http://blog.bdoughan.com/2011/08/jaxb-and-java-io-files-streams-readers.html
This problem have been resolved by adding #XmlAttribute in corresponding #XmlRootElement classes.
#XmlAttribute(name="namespace_name")
public String namespace_value="xxxxxxxxxx";

Prevent XXE Attack with JAXB

Recently, we had a security audit on our code, and one of the problem is that our application is subject to the Xml eXternal Entity (XXE) attack.
Basically, the application is a calculator that receives inputs as XML, through a Web-Service.
Here is an example of such an XXE attack on our application:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header/>
<soapenv:Body>
<foo:calculateStuff>
<!--Optional:-->
<xmlInput><![CDATA[<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!DOCTYPE currency [
<!ENTITY include SYSTEM "file:///d:/" >]>
<calcinput>...</calcinput>
]]></xmlInput>
</foo:calculateStuff>
</soapenv:Body>
</soapenv:Envelope>
As you can see, we can refer to an entity that points to an external file ("file:///d:/").
Regarding the XML input itself (the <calcinput>...</calcinput> part) is unmarshalled with JAXB (v2.1). The web-service part is based on jaxws-rt (2.1).
What do I need to do to secure my web-service?
JAXB
You can prevent the Xml eXternal Entity (XXE) attack by unmarshalling from an XMLStreamReader that has the IS_SUPPORTING_EXTERNAL_ENTITIES and/or XMLInputFactory.SUPPORT_DTD properties set to false.
JAX-WS
A JAX-WS implementation should take care of this for you. If it doesn't I would recommend opening a bug against the specific implmententation.
EXAMPLE
Demo
package xxe;
import javax.xml.bind.*;
import javax.xml.stream.*;
import javax.xml.transform.stream.StreamSource;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Customer.class);
XMLInputFactory xif = XMLInputFactory.newFactory();
xif.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
xif.setProperty(XMLInputFactory.SUPPORT_DTD, false);
XMLStreamReader xsr = xif.createXMLStreamReader(new StreamSource("src/xxe/input.xml"));
Unmarshaller unmarshaller = jc.createUnmarshaller();
Customer customer = (Customer) unmarshaller.unmarshal(xsr);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(customer, System.out);
}
}
input.xml
This XML document contains an entity that has been setup to get the listing of files I used to create this example.
<?xml version="1.0"?>
<!DOCTYPE customer
[
<!ENTITY name SYSTEM "/Users/bdoughan/Examples/src/xxe/">
]
>
<customer>
<name>&name;</name>
</customer>
Customer
package xxe;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class Customer {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Output - Default Configuration
By default the entity will be resolved.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<customer>
<name>Customer.java
Demo.java
input.xml
</name>
</customer>
Output when XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES property is set to false
When this property is set the entity is not resolved.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<customer>
<name></name>
</customer>
Output when XMLInputFactory.SUPPORT_DTD property is set to false
When this property is set an exception is thrown trying to resolve the entity.
Exception in thread "main" javax.xml.bind.UnmarshalException
- with linked exception:
[javax.xml.stream.XMLStreamException: ParseError at [row,col]:[8,15]
Message: The entity "name" was referenced, but not declared.]
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.handleStreamException(UnmarshallerImpl.java:436)
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:342)
at xxe.Demo.main(Demo.java:18)
Caused by: javax.xml.stream.XMLStreamException: ParseError at [row,col]:[8,15]
Message: The entity "name" was referenced, but not declared.
at com.sun.org.apache.xerces.internal.impl.XMLStreamReaderImpl.next(XMLStreamReaderImpl.java:598)
at com.sun.xml.bind.v2.runtime.unmarshaller.StAXStreamConnector.bridge(StAXStreamConnector.java:196)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:370)
... 2 more

From list of key values to attribute key=value

I have a question about JAXB. Basically what I have are these two classes:
Element {
String name
List<Attribute> attributes;
}
Attribute {
String key
String value
}
Of course with getters and setters, and with JAXB XmlRootElement.
The XML generated from this is:
<element>
<attributes>
<key>id</key>
<value>1</value>
</attributes>
<name>My Element</name>
</element>
But what I'm looking for is something more like this:
<element id="1">
<name>My Element</name>
</element>
That is, for each instance of Attribute, I want key=value (as an attribute)
Is this possible in JAXB?
Regards,
Morten
I do not think that it will work with a List. But there is an alternative using a
Map and
#XmlAnyAttribute
Your example:
#XmlRootElement
public static class Element
{
#XmlElement
String name;
#XmlAnyAttribute
Map<QName, Object> map;
}
{
//
Element element = new Element();
element.name = "a wonderful name";
element.map = new HashMap<QName, Object>();
element.map.put( new QName( "id" ), "1" );
element.map.put( new QName( "other" ), "2" );
}
Result of that:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<element id="1" other="2">
<name>a wonderful name</name>
</element>
Best regards!

Categories