【问题标题】:Marshal JAXB element into SOAP handling escape characters将 JAXB 元素编入 SOAP 处理转义字符
【发布时间】:2018-11-01 20:24:26
【问题描述】:

我正在尝试将 JAXB 元素编组到 SOAPBody 包装器中,我能够转义 JAXB 中的编码字符,但是当我将其编组到 SOAP 文档中时,它并没有转义这些 xml 字符。任何帮助。提前致谢。

而且我的项目很小,我们没有使用任何外部包,尝试在开放 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>&lt;![CDATA[Hel..&lt;..lo]]&gt;</payload><age>29</age><name>Hel..&lt;..lo</name></customer>
    </SOAP-ENV:Body></SOAP-ENV:Envelope>

【问题讨论】:

    标签: java soap encoding jaxb saaj


    【解决方案1】:

    Marshaller.JAXB_ENCODINGcom.sun.xml.internal.bind.characterEscapeHandler 属性仅在编组到流时有效,但在编组到 DOM 时无效。如果您希望 CDATA 部分出现在最终结果中,最好让 JAXB 正常编组数据,然后对 DOM 进行后处理,将文本节点更改为所需的 CDATA 部分。

    【讨论】:

      【解决方案2】:

      你可以使用 apache StringEscapeUtils。由于我不知道您的客户类是什么样的,所以我只是构建了一个简单的示例,请参见下面的类。结果如下所示:

      soapMessage.writeTo(System.out);

      <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
          <SOAP-ENV:Header/>
          <SOAP-ENV:Body>&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;yes&amp;quot;?&amp;gt;
                  &amp;lt;customer&amp;gt;
                  &amp;lt;id&amp;gt;123&amp;amp;lt;&amp;amp;gt;&amp;amp;amp;g&amp;lt;/id&amp;gt;
                  &amp;lt;name&amp;gt;Hello&amp;lt;/name&amp;gt;
                  &amp;lt;lastname&amp;gt;World*+;:-&amp;amp;lt;&amp;amp;gt;&amp;amp;amp;%$&amp;lt;/lastname&amp;gt;
                  &amp;lt;/customer&amp;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&lt;&gt;&amp;g</id>
          <name>Hello</name>
          <lastname>World*+;:-&lt;&gt;&amp;%$</lastname>
      </customer>
      

      行家

      <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;
          }
      }
      

      【讨论】:

      • 感谢您的回复,很遗憾我无法使用 Apache 字符串工具。
      【解决方案3】:

      好吧,如果没有 apache 转义工具,那么(丑陋的)解决方法怎么样。 基本上你将它编组两次,然后剪下你需要的部分并将它直接放在你的肥皂体上,见下面的例子。

      soapMessage.writeTo(System.out);

      <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
          <SOAP-ENV:Header/>
          <SOAP-ENV:Body>&amp;lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&amp;gt;
              &amp;lt;customer&amp;gt;
              &amp;lt;id&amp;gt;Hello &amp;amp;lt;&amp;amp;gt;&amp;amp;amp;g World*+;:-&amp;amp;lt;&amp;amp;gt;&amp;amp;amp;%$&amp;lt;/id&amp;gt;
              &amp;lt;/customer&amp;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;
          }
      }
      

      【讨论】:

        【解决方案4】:

        我使用下面的 jaxbMarshaller 解决了这个问题

         jaxbMarshaller.marshal(elem, soapBody);
        

        elemJAXBElement

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-05-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多