spring-projects / spring-projects/spring-ws

Improve the experience to enable MTOM with JAXB [SWS-905]

Open
#982 6 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

type: enhancement
Dominant language
Java
Stars
346
Forks
323
Avg merge
3d 2h
Merged PRs (30d)
7

Description

Mauro Molinari opened SWS-905 and commented

I had a very poor experience trying to enable MTOM attachment handling on a receiving endpoint expecting JAXB input parameters. Please let me write the whole story.

I have to receive web service requests as defined by the following contract: http://www.fatturapa.gov.it/export/fatturazione/sdi/ws/trasmissione/v1.0/TrasmissioneFatture_v1.1.wsdl
and the imported schema: http://www.fatturapa.gov.it/export/fatturazione/sdi/ws/trasmissione/v1.0/TrasmissioneTypes_v1.1.xsd

With the following configuration I could make it almost work:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:web-services="http://www.springframework.org/schema/web-services"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/web-services http://www.springframework.org/schema/web-services/web-services-2.0.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"
	default-lazy-init="true">

	<context:component-scan base-package="mypackage" />

	<web-services:annotation-driven />

	<web-services:static-wsdl id="TrasmissioneFatture"
		location="classpath:/wsdl/TrasmissioneFatture_v1.1.wsdl" />

	<bean id="TrasmissioneTypes_v1.1" class="org.springframework.xml.xsd.SimpleXsdSchema">
		<property name="xsd" value="classpath:/wsdl/TrasmissioneTypes_v1.1.xsd" />
	</bean>
</beans>
@Endpoint
public class TrasmissioneFattureEndpoint {

  @SoapAction("http://www.fatturapa.it/TrasmissioneFatture/RicevutaConsegna")
  public void ricevutaConsegna(@RequestPayload FileSdIType input) {
    // processing
  }

where FileSdiType is a Java class generated by running the JAXB compiler XJC against the above XSD file. Please note that FileSdiType is annotated with @XmlType and not with @XmlRootElement (actually, no generated class has the @XmlRootElement annotation...).
Contrary to what the reference documentation says, unmarshalling for FileSdType works even if it is not annotated with @XmlRootElement, but that's fine for me: the code and configuration are very brief and neat!

This almost worked perfectly. I say "almost" because one of the elements of FileSdType schema type is a binary attachment. By trying to retrieve its content in the endpoing implementation using the InputStream on the DataHandler exposed by the corresponding Java type, all works fine as long as the client sends the attachment as an inline base64 binary string.
But if the client uses MTOM, the input stream reads nothing.

The first reaction was: well, I would have expected it to work out of the box, since MTOM is said to be the de-facto standard for attachments.
The second thought was: let's look at the reference documentation better... but nothing relevant is said for this use case.
The third was: let's search with Google.

The actual solution was given by this StackOverflow answer: http://stackoverflow.com/questions/11316023/spring-ws-webservice-with-mtom-attachement-hello-world-test/11576245#11576245
That is: define a Jaxb2Marshaller with enabled MTOM, define a MarshallingPayloadMethodProcessor that uses it, define a DefaultMethodEndpointAdapter that uses that processor, define a message receiver of type SoapMessageDispatcher that uses that method endpoint adapter and make the MessageDispatcherServlet use that message receiver.

With all of this lengthy configuration, I could make it work, but:

  • there's a lot of (manual) configuration to set up and there's no indication in the reference guide on how to do this
  • after founding the StackOverflow question, I discovered there's a MTOM example project in the spring-ws-samples GitHub project, but:
    • I couldn't find any link to this project in the Spring Web Services website on spring.io (I found it by chance using Google...)
    • I couldn't find any mention to that samples project in the reference guide
    • the sample uses Java configuration (not XML), so a bit of translation is required in my case; nevertheless, I couldn't find where the message receiver is configured, which is an essential part of the configuration (I debugged my configuration and, without it, the default method endpoint adapter created by the Spring WS namespace tags is still preferred and used, so MTOM attachment handling doesn't work)
  • while org.springframework.ws.server.endpoint.adapter.method.jaxb.XmlRootElementPayloadMethodProcessor.supportsRequestPayloadParameter(MethodParameter) checks for both the presence of @XmlRootElement and @XmlType, org.springframework.oxm.jaxb.Jaxb2Marshaller.supportsInternal(Class<?>, boolean) only checks for the former annotation and not for the latter, so I had to change my endpoint method signature to use JaxbElement<FileSdIType> (which IMHO introduces useless noise in the endpoint implementation)
  • another (smaller) annoyance is that if I define my Jaxb2Marshaller I have to explicitly set its context path (or packages/classes to scan/support), while with the default non-MTOM enabled configuration this is not required, because the appropriate Jaxb2 marshaller is found automatically (I think it's thanks to org.springframework.ws.server.endpoint.adapter.method.jaxb.AbstractJaxb2PayloadMethodProcessor.createUnmarshaller(Class<?>) and org.springframework.ws.server.endpoint.adapter.method.jaxb.AbstractJaxb2PayloadMethodProcessor.getJaxbContext(Class<?>))

I think all of this should be improved, or at least documented. Also, if the requirement to explicitely enable MTOM on the marshaller is desirable, why this shouldn't just work?

<web-services:annotation-driven marshaller="marshaller" unmarshaller="marshaller" />

where marshaller is my MTOM-enabled Jaxb2Marshaller? In my tests, this does not work (i.e.: specifying the marshaller in the <web-services:annotation-driven> tag is unexpectedly totally useless for this use case).

Probably this is related to #793, which was closed as deferred probably because of a lack of resources, However, in the short-mid term, if this could not be improved, at least please document it in the reference guide: I don't think the need for a MTOM+JAXB working solution is so uncommon.


Affects: 2.2.1

Issue Links:

  • #981 Improve the experience to enable MTOM with JAXB
    ("supersedes")

Referenced from: commits https://github.com/spring-projects/spring-ws/commit/15207405442ec225507a43228b4c260d943f7847

1 votes, 3 watchers

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reviewing issue #981, which supersedes this report, then inspect the mentioned XmlRootElementPayloadMethodProcessor, Jaxb2Marshaller, AbstractJaxb2PayloadMethodProcessor, and annotation-driven configuration. Determine whether the MTOM-plus-JAXB setup should be simplified, supported, or documented, and consider the reference guide and MTOM sample as the completion criteria.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, spring
Domain
backend-api-design, documentation
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
20/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.