Reputation: 21
I am trying to Marshal the JAXB element into SOAPBody wrappers, i was able to escape the encoded characters in JAXB, but when i marshal it into SOAP document it's not escaping these xml characters.Any help.Thanks in advance.
And My project is small we are not utilizing any external packages,trying to do this in open jdk.
package test;
import java.io.File;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import com.sun.xml.internal.bind.marshaller.CharacterEscapeHandler;
public class JAXBExample {
public static void main(String[] args) throws SOAPException, IOException {
Customer customer = new Customer();
customer.setId(100);
customer.setName("Hel..<..lo");
customer.setAge(29);
try {
MessageFactory messageFactory = MessageFactory.newInstance();
SOAPMessage soapMessage = messageFactory.createMessage();
SOAPPart soapPart = soapMessage.getSOAPPart();
SOAPEnvelope soapEnvelope = soapPart.getEnvelope();
SOAPBody soapBody = soapEnvelope.getBody();
JAXBContext jaxbContext = JAXBContext.newInstance(Customer.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
// jaxbMarshaller.setProperty(CharacterEscapeHandler.class.getName(), new CustomCharacterEscapeHandler());
jaxbMarshaller.setProperty("com.sun.xml.internal.bind.characterEscapeHandler",
new CharacterEscapeHandler() {
public void escape(char[] ch, int start, int length, boolean isAttVal, Writer writer)
throws IOException {
writer.write(ch, start, length);
}
});
// output pretty printed
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
jaxbMarshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
jaxbMarshaller.marshal(customer, System.out);
jaxbMarshaller.marshal(customer, soapBody);
soapMessage.saveChanges();
soapMessage.writeTo(System.out);
}
catch (JAXBException e) {
e.printStackTrace();
}
}
}
// result just with jaxb ***
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<customer id="100">
<payload><![CDATA[Hel..<..lo]]></payload>
<age>29</age>
<name>Hel..<..lo</name>
</customer>
// result jaxb wrapped into SOAPbody***
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header/>
<SOAP-ENV:Body>
<customer id="100">
<payload><![CDATA[Hel..<..lo]]></payload><age>29</age><name>Hel..<..lo</name></customer>
</SOAP-ENV:Body></SOAP-ENV:Envelope>
Upvotes: 1
Views: 11724
Reputation: 71
I fixed this by using the jaxbMarshaller as below
jaxbMarshaller.marshal(elem, soapBody);
where elem is JAXBElement
Upvotes: 2
Reputation: 9
Well, without the apache escape utils, how about an (ugly) workaround. Basically you marshall it twice, then cut out the part you need and set it directly to your soap body, see example below.
soapMessage.writeTo(System.out);
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<SOAP-ENV:Body>&lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&gt;
&lt;customer&gt;
&lt;id&gt;Hello &amp;lt;&amp;gt;&amp;amp;g World*+;:-&amp;lt;&amp;gt;&amp;amp;%$&lt;/id&gt;
&lt;/customer&gt;
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Main.java
public class Main {
private static final Logger log = LogManager.getLogger(Main.class);
public static void main(String[] args) {
try {
Customer customer = new Customer().setID("Hello <>&g World*+;:-<>&%$");
String xml = marshall(new Workaround().setID(marshall(customer)));
xml = xml.substring(0, xml.indexOf("</id>"));
xml = xml.substring(xml.indexOf("<id>") + 4);
System.out.println("\r\n\r\nxml:\r\n" + xml);
MessageFactory messageFactory = MessageFactory.newInstance();
SOAPMessage soapMessage = messageFactory.createMessage();
SOAPPart soapPart = soapMessage.getSOAPPart();
SOAPEnvelope soapEnvelope = soapPart.getEnvelope();
SOAPBody soapBody = soapEnvelope.getBody();
soapBody.setValue(xml);
System.out.println("\r\n\r\nsoap:");
soapMessage.writeTo(System.out);
} catch (Exception e) {
log.error("no! ", e);
}
log.info("stop");
}
public static String marshall(Object o) throws Exception {
System.out.println("-------------------");
StringWriter sw = new StringWriter();
JAXBContext jaxbContext = JAXBContext.newInstance(o.getClass());
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
jaxbMarshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
jaxbMarshaller.marshal(o, System.out);
jaxbMarshaller.marshal(o, sw);
return sw.toString();
}
}
Customer.java
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name="customer")
@XmlAccessorType(XmlAccessType.FIELD)
public class Customer {
@XmlElement(name="id")
private String id;
public String getID() {
return this.id;
}
public Customer setID(String value) {
this.id = value;
return this;
}
}
Workaround.java
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name="workaround")
@XmlAccessorType(XmlAccessType.FIELD)
public class Workaround {
@XmlElement(name="id")
private String id;
public String getID() {
return this.id;
}
public Workaround setID(String value) {
this.id = value;
return this;
}
}
Upvotes: 0
Reputation: 9
You could use apache StringEscapeUtils. Since I do not know how your customer class looks like, I just build a quick example, see classes below. The result looks like this:
soapMessage.writeTo(System.out);
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<SOAP-ENV:Body>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;yes&quot;?&gt;
&lt;customer&gt;
&lt;id&gt;123&amp;lt;&amp;gt;&amp;amp;g&lt;/id&gt;
&lt;name&gt;Hello&lt;/name&gt;
&lt;lastname&gt;World*+;:-&amp;lt;&amp;gt;&amp;amp;%$&lt;/lastname&gt;
&lt;/customer&gt;
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
System.out.println(StringEscapeUtils.unescapeXml(soapBody.getValue()));
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<customer>
<id>123<>&g</id>
<name>Hello</name>
<lastname>World*+;:-<>&%$</lastname>
</customer>
maven
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>1.6</version>
</dependency>
Main.java
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import java.io.*;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import org.apache.commons.text.StringEscapeUtils;
public class Main {
private static final Logger log = LogManager.getLogger(Main.class);
public static void main(String[] args) {
try {
Customer customer = new Customer().setID("123<>&g").setName("Hello").setLastname("World*+;:-<>&%$");
MessageFactory messageFactory = MessageFactory.newInstance();
SOAPMessage soapMessage = messageFactory.createMessage();
SOAPPart soapPart = soapMessage.getSOAPPart();
SOAPEnvelope soapEnvelope = soapPart.getEnvelope();
SOAPBody soapBody = soapEnvelope.getBody();
JAXBContext jaxbContext = JAXBContext.newInstance(Customer.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
// output pretty printed
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
jaxbMarshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
StringWriter sw = new StringWriter();
jaxbMarshaller.marshal(customer, sw);
soapBody.setValue(StringEscapeUtils.escapeXml11(sw.toString()));
soapMessage.saveChanges();
soapMessage.writeTo(System.out);
System.out.println("\r\n\r\n-----\r\n\r\n");
System.out.println(StringEscapeUtils.unescapeXml(soapBody.getValue()));
} catch(Exception e) {
log.error("no! ", e);
}
log.info("stop");
}
}
Customer.java
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name="customer")
@XmlAccessorType(XmlAccessType.FIELD)
public class Customer {
@XmlElement(name="id")
private String id;
@XmlElement(name="name")
private String name;
@XmlElement(name="lastname")
private String lastname;
public String getID() {
return this.id;
}
public Customer setID(String value) {
this.id = value;
return this;
}
public String getName() {
return this.name;
}
public Customer setName(String value) {
this.name = value;
return this;
}
public String getLastname() {
return this.lastname;
}
public Customer setLastname(String value) {
this.lastname = value;
return this;
}
}
Upvotes: 0
Reputation: 9154
The Marshaller.JAXB_ENCODING
and com.sun.xml.internal.bind.characterEscapeHandler
properties only have effect when marshalling to a stream, but not when marshalling to DOM. If you want CDATA sections in the final result, it's probably better to just let JAXB marshal the data normally and then to post-process the DOM, changing text nodes to CDATA sections where you want them.
Upvotes: 1