2

I have a Java class to generate the following XML:

<v:Envelope xmlns:v="http://schemas.xmlsoap.org/soap/envelope/">
    <v:Header>
        <b>LGE Nexus 5</b>
        <c>ANDROID</c>
        <d>6.0.1</d>
        <e>4.1.5</e>
        <f>127.0.0.1</f>
        <g/>?<g>
        <h>0.0</h>
        <i>0.0</i>
        <j"/>
        <k>8320738e-8634-4f73-a4dd-874a5d79e336</k>
        <l>2017-08-14 13:24:01</l>
        <m>8797e74f0d6eb7b1ff3dc114d4aa12d3</m>
    </v:Header>
    <v:Body>
        <ns2:getStatus xmlns:ns2="http://soap.ws.placa.service.sinesp.serpro.gov.br/">
            <a>ABC1234</a>
        </ns2:getStatus>
    </v:Body>
</v:Envelope>

But my current result is:

<v:Envelope xmlns:v="http://schemas.xmlsoap.org/soap/envelope/">
    <v:Header>
        <b xmlns="http://schemas.xmlsoap.org/soap/envelope/">LGE Nexus 5</b>
        <c xmlns="http://schemas.xmlsoap.org/soap/envelope/">ANDROID</c>
        <d xmlns="http://schemas.xmlsoap.org/soap/envelope/">6.0.1</d>
        <e xmlns="http://schemas.xmlsoap.org/soap/envelope/">4.1.5</e>
        <f xmlns="http://schemas.xmlsoap.org/soap/envelope/">127.0.0.1</f>
        <g xmlns="http://schemas.xmlsoap.org/soap/envelope/">?</g>
        <h xmlns="http://schemas.xmlsoap.org/soap/envelope/">0.0</h>
        <i xmlns="http://schemas.xmlsoap.org/soap/envelope/">0.0</i>
        <j xmlns="http://schemas.xmlsoap.org/soap/envelope/" />
        <k xmlns="http://schemas.xmlsoap.org/soap/envelope/">8320738e-8634-4f73-a4dd-874a5d79e336</k>
        <l xmlns="http://schemas.xmlsoap.org/soap/envelope/">2017-08-14 13:24:01</l>
        <m xmlns="http://schemas.xmlsoap.org/soap/envelope/">8797e74f0d6eb7b1ff3dc114d4aa12d3</m>
    </v:Header>
    <v:Body>
        <ns2:getStatus xmlns:ns2="http://soap.ws.placa.service.sinesp.serpro.gov.br/">
            <a>ABC1234</a>
        </ns2:getStatus>
    </v:Body>
</v:Envelope>

My class is the following:

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Iterator;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPMessage;
import org.w3c.dom.Document;

@XmlRootElement(name = "getStatus", namespace = "http://soap.ws.placa.service.sinesp.serpro.gov.br/")
public class Request {

  private String plate;

  private String device;
  private Double latitude;
  private String operationalSystem;
  private String majorVersion;
  private String minorVersion;
  private String ip;
  private String token;
  private String uuid;
  private Double longitude;
  private String date;
  private String hash;

  public Request() {
    this.device = "LGE Nexus 5";
    this.operationalSystem = "ANDROID";
    this.majorVersion = "6.0.1";
    this.minorVersion = "4.1.5";
    this.ip = "127.0.0.1";
    this.hash = "8797e74f0d6eb7b1ff3dc114d4aa12d3";
  }

  @XmlElement(name = "a")
  public String getPlate() {
    return plate;
  }

  public void setPlate(String plate) {
    this.plate = plate;
  }

  @XmlTransient
  public String getDevice() {
    return device;
  }

  public void setDevice(String device) {
    this.device = device;
  }

  @XmlTransient
  public Double getLatitude() {
    return latitude;
  }

  public void setLatitude(Double latitude) {
    this.latitude = latitude;
  }

  @XmlTransient
  public String getOperationalSystem() {
    return operationalSystem;
  }

  public void setOperationalSystem(String operationalSystem) {
    this.operationalSystem = operationalSystem;
  }

  @XmlTransient
  public String getMajorVersion() {
    return majorVersion;
  }

  public void setMajorVersion(String majorVersion) {
    this.majorVersion = majorVersion;
  }

  @XmlTransient
  public String getMinorVersion() {
    return minorVersion;
  }

  public void setMinorVersion(String minorVersion) {
    this.minorVersion = minorVersion;
  }

  @XmlTransient
  public String getIp() {
    return ip;
  }

  public void setIp(String ip) {
    this.ip = ip;
  }

  @XmlTransient
  public String getToken() {
    return token;
  }

  public void setToken(String token) {
    this.token = token;
  }

  @XmlTransient
  public String getUuid() {
    return uuid;
  }

  public void setUuid(String uuid) {
    this.uuid = uuid;
  }

  @XmlTransient
  public Double getLongitude() {
    return longitude;
  }

  public void setLongitude(Double longitude) {
    this.longitude = longitude;
  }

  @XmlTransient
  public String getDate() {
    return date;
  }

  public void setDate(String date) {
    this.date = date;
  }

  @XmlTransient
  public String getHash() {
    return hash;
  }

  public void setHash(String hash) {
    this.hash = hash;
  }

  public String toXML() {
    Document document;
    Marshaller marshaller;
    SOAPMessage soapMessage;
    ByteArrayOutputStream outputStream;
    String output;

    try {
      document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
      marshaller = JAXBContext.newInstance(Request.class).createMarshaller();
      marshaller.marshal(this, document);
      soapMessage = MessageFactory.newInstance().createMessage();
      this.fillEnvelope(soapMessage.getSOAPPart().getEnvelope());
      this.fillBody(soapMessage.getSOAPBody(), document);
      this.fillHeaders(soapMessage.getSOAPHeader());
      outputStream = new ByteArrayOutputStream();
      soapMessage.writeTo(outputStream);
      output = new String(outputStream.toByteArray());
    } catch (IOException | JAXBException | ParserConfigurationException | SOAPException ex) {
      throw new RuntimeException(ex);
    }

    return output;
  }

  private void fillEnvelope(SOAPEnvelope envelope) {
    Iterator prefixes;
    envelope.setPrefix("v");

    prefixes = envelope.getNamespacePrefixes();

    while (prefixes.hasNext()) {
      String prefix = (String) prefixes.next();

      envelope.removeNamespaceDeclaration(prefix);
    }
  }

  private void fillHeaders(SOAPHeader soapHeader) throws SOAPException {
    soapHeader.setPrefix("v");

    soapHeader.addHeaderElement(new QName(soapHeader.getNamespaceURI(), "b")).setValue(this.device);
    soapHeader.addHeaderElement(new QName(soapHeader.getNamespaceURI(), "c")).setValue(this.operationalSystem);
    soapHeader.addHeaderElement(new QName(soapHeader.getNamespaceURI(), "d")).setValue(this.majorVersion);
    soapHeader.addHeaderElement(new QName(soapHeader.getNamespaceURI(), "e")).setValue(this.minorVersion);
    soapHeader.addHeaderElement(new QName(soapHeader.getNamespaceURI(), "f")).setValue(this.ip);
    soapHeader.addHeaderElement(new QName(soapHeader.getNamespaceURI(), "g")).setValue(this.token);
    soapHeader.addHeaderElement(new QName(soapHeader.getNamespaceURI(), "h")).setValue(String.valueOf(this.longitude));
    soapHeader.addHeaderElement(new QName(soapHeader.getNamespaceURI(), "i")).setValue(String.valueOf(this.latitude));
    soapHeader.addHeaderElement(new QName(soapHeader.getNamespaceURI(), "j")).setValue("");
    soapHeader.addHeaderElement(new QName(soapHeader.getNamespaceURI(), "k")).setValue(this.uuid);
    soapHeader.addHeaderElement(new QName(soapHeader.getNamespaceURI(), "l")).setValue(this.date);
    soapHeader.addHeaderElement(new QName(soapHeader.getNamespaceURI(), "m")).setValue(this.hash);
  }

  private void fillBody(SOAPBody soapBody, Document document) throws SOAPException {
    soapBody.addDocument(document);
    soapBody.setPrefix("v");
  }
}

The test method is:

public static void main(String[] args) {
  Request request = new Request();

  request.setToken("?");
  request.setLatitude(0.0);
  request.setLongitude(0.0);
  request.setUuid(UUID.randomUUID().toString()); // RFC 4122 Class 4 random UUID    
  request.setDate("2017-08-14 13:24:01");
  request.setPlate("ABC1234");

  System.out.println(request.toXML());
}

What I need to do in order to remove the namespace attribute of SOAPHeaderElement?

Sorack
  • 319
  • 1
  • 5
  • 18
  • 2
    Your expected output is impossible. `HeaderElements must be namespace qualified`. – aristotll Aug 17 '17 at 05:43
  • 1
    I can't vote to close, since there is an open bounty on this question, but it is more or less a duplicate of https://stackoverflow.com/questions/41067832/adding-soap-header-elements-without-namespace. As aristotll points out, your intended XML would violate the SOAP specification and cannot be created with the JAX-RS library. – jarnbjo Aug 21 '17 at 12:49
  • @jarnbjo can you put this as a answer so I can close the question? – Sorack Aug 21 '17 at 12:51
  • @Sorack Yeah, sure. – jarnbjo Aug 21 '17 at 12:58

3 Answers3

2

You could use regular expressions to remove the namespaces:

xml.replaceAll(" xmlns=\".*?\"", "");

where variable xml is your XML as a string.

Andrew Bedford
  • 176
  • 1
  • 7
2

Each SOAP header block (immediate child of the Header element) must according to the SOAP specification be namespace qualified. Your intended XML, will hence violate the SOAP specification.

You can of course use other means or plain XML libraries to create the XML you want, but when using soapHeader.addHeaderElement, the JAX-RS implementation (at least in Oracle's JRE) verifies this requirement and throws an exception if you try to add a header block with an empty namepsace.

jarnbjo
  • 33,923
  • 7
  • 70
  • 94
0

This is a disgusting hack that worked for me. First, you need to know the class that the namespaceURI is stored in. You can do this by debugging your application, looking at the SOAPHeaderElement object's fields, and navigating to the source of namespaceURI.

From there, you use reflection to set the field to null after instantiating it. Then remove the attribute. This should result in the attribute not being written out. It depends on the implementation.

SOAPHeaderElement headerElement = header.addHeaderElement(new QName("whatever", "myHeaderName") );
// Disgusting hack to remove the xmlns attribute
Field namespaceURIField = ElementNSImpl.class.getDeclaredField("namespaceURI");
namespaceURIField.setAccessible(true);
namespaceURIField.set(headerElement, null);
namespaceURIField.setAccessible(false);
headerElement.removeAttribute("xmlns");
Jack Cole
  • 1,528
  • 2
  • 19
  • 41