3

I´m trying to use MTOM + XOP to return a byte[] in a Spring Web Service but when marshalling result it throws a SAXParseException with message:

cvc-type.3.1.2: Element 'dataHandler' is a simple type, so it must have no element information item [children].

It seems that after writing XOP tag, validator meet with it instead of the byte[] content that it expects and throws a SAXParseException with FATAL level that stops the process.

I´m using:

  • JDK 1.7
  • SAAJ 1.3
  • SOAP 1.1
  • Spring 4.1.4.RELEASE
  • Spring WS 2.2.0.RELEASE

Thanks in advance

leaqui
  • 533
  • 6
  • 22

2 Answers2

3

I´ve found two workarounds for my situation:

  1. Not setting the xmlschema to marshaller.

  2. Setting a ValidationEventHandler to marshaller that skips XOP failures.

This is an example of setting a ValidationEventHandler to marshaller that skips XOP failures:

Abstract superclass:

import javax.xml.bind.ValidationEvent;
import javax.xml.bind.ValidationEventHandler;

abstract class XopAwareValidationEventHandler implements ValidationEventHandler {

  private static final String CVC_TYPE_3_1_2 = "cvc-type.3.1.2";

  private ValidationEventHandler realHandler;

  XopAwareValidationEventHandler(final ValidationEventHandler handler) {
    this.setRealHandler(handler);
  }

  @Override
  public boolean handleEvent(final ValidationEvent event) {
    final boolean result = this.getRealHandler().handleEvent(event);
    if (!result) {
      if (event.getMessage() != null && event.getMessage().startsWith(CVC_TYPE_3_1_2)) {
        return this.isXopEvent(event);
      }
    }
    return result;
  }

  abstract boolean isXopEvent(ValidationEvent validationEvent);

  private ValidationEventHandler getRealHandler() {
    return realHandler;
  }

  private void setRealHandler(final ValidationEventHandler realHandler) {
    this.realHandler = realHandler;
  }
}

Concrete class for unmarshaller:

import javax.xml.bind.ValidationEvent;
import javax.xml.bind.ValidationEventHandler;

class XopAwareUnmarshallingValidationEventHandler extends XopAwareValidationEventHandler {

  private static final String XOP_INCLUDE = "xop:Include";

  XopAwareUnmarshallingValidationEventHandler(final ValidationEventHandler handler) {
    super(handler);
  }

  @Override
  boolean isXopEvent(final ValidationEvent validationEvent) {
    final ValidationEventLocator locator = validationEvent.getLocator();
    return locator != null && locator.getNode() != null &&
        locator.getNode().getFirstChild() != null &&
        XOP_INCLUDE.equals(locator.getNode().getFirstChild().getNodeName());
  }
}

For marshaller I´m searching for the condition that identifies the case, because the ValidationEventLocator only have the Object set and it could be whatever.

import javax.xml.bind.ValidationEvent;
import javax.xml.bind.ValidationEventHandler;
import javax.xml.bind.ValidationEventLocator;

public class XopAwareMarshallingValidationEventHandler extends XopAwareValidationEventHandler {

  public XopAwareMarshallingValidationEventHandler(final ValidationEventHandler handler) {
    super(handler);
  }

  boolean isXopEvent(final ValidationEvent validationEvent) {
    final ValidationEventLocator locator = validationEvent.getLocator();
    return locator != null && locator.getNode() == null;
  }
}

org.springframework.oxm.jaxb.Jaxb2Marshaller subclass that activates MTOM and adds both event handlers:

import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

import org.springframework.oxm.jaxb.Jaxb2Marshaller;

import XopAwareMarshallingValidationEventHandler;
import XopAwareUnmarshallingValidationEventHandler;

public class XopAwareJaxb2Marshaller extends Jaxb2Marshaller {

  public XopAwareJaxb2Marshaller() {
    this.setMtomEnabled(true);
  }

  protected void initJaxbMarshaller(final Marshaller marshaller) throws JAXBException {
    super.initJaxbMarshaller(marshaller);

    marshaller.setEventHandler(new XopAwareMarshallingValidationEventHandler(marshaller.getEventHandler()));
  }

  protected void initJaxbUnmarshaller(final Unmarshaller unmarshaller) throws JAXBException {
    super.initJaxbUnmarshaller(unmarshaller);

    unmarshaller.setEventHandler(new XopAwareUnmarshallingValidationEventHandler(unmarshaller
        .getEventHandler()));
  }
}
leaqui
  • 533
  • 6
  • 22
0

That's not a problem with SAAJ, but with Spring-WS. It's caused by the fact that Spring-WS passes the XOP encoded message to the schema validator, which doesn't understand XOP. Ultimately the problem is that Spring-WS doesn't have a well defined processing model for XOP/MTOM, as I explained in this article.

Andreas Veithen
  • 8,868
  • 3
  • 25
  • 28
  • Thanks Andreas, I´ve read your article. What surprises me is that this is not an open issue in Spring-WS and not commented very much in forums. – leaqui Jul 27 '16 at 15:18
  • this still a issue to this current date? – Tanner Summers Oct 12 '17 at 19:47
  • I think the situation is pretty much unchanged. Several months ago I sent a couple of pull requests to start fixing some of the issues, but I never got a response. I think the problem is that Spring-WS is not really a community driven project: if you have a support contract with Pivotal, then you will be able to get changes into the product, otherwise good luck. – Andreas Veithen Oct 19 '17 at 18:41