How to get control over JAXBContext in JAX-WS?
Solution 1
First option is @UsesJAXBContext
annotation. More info here: Specify JAXB Packages in SLSB and JAX-WS
I haven't tested it cause when I found this annotation I've been already halfway towards other solution which might be helpful for others.
The key is using @WebServiceProvider
instead of @WebService
, a bit low-level but simple:
@WebServiceProvider(
wsdlLocation = "WEB-INF/wsdl/injector.wsdl"
)
@ServiceMode(value = Service.Mode.PAYLOAD)
public class InjectorService implements Provider<Source> {
private Unmarshaller unmarshaller;
@Override
public Source invoke(Source request) {
try {
DOMResult requestDom = new DOMResult();
Transformer trans = TransformerFactory.newInstance().newTransformer();
trans.transform(request, requestDom);
Node requestNode = requestDom.getNode();
// Get the operation name node.
Node operationNode = requestNode.getFirstChild();
// Get the parameter node.
Node parameterNode = operationNode.getFirstChild();
// Unmarshal
JAXBElement<Object> element = unmarshaller.unmarshal(parameterNode, Object.class);
Object unmarshalled = element.getValue();
// Handling customer object and response ......
} catch (Exception e) {
throw new RuntimeException("Endpoint error", e);
}
}
protected Class[] getCustomerClasses() {
// return customer classes somehow
}
@PostConstruct
public void init() throws Exception {
JAXBContext jbc = JAXBContext.newInstance(getCustomerClasses());
unmarshaller = jbc.createUnmarshaller();
}
}
That's it. Customer classes can be obtained from classpath, bundle context or whatever.
Solution 2
From what I know, there is no "declarative" way of hinting an alternative way to unmarshall, on top of the one you already have in place as per JAX-WS, or JAXB - what you're looking for. By the way, the "strange" Xerces node is actually expected, since xsd:any/anyType and Object go hand in hand in your scenario.
My suggestion is to use a relatively simple and portable solution: build your own thin "binding" layer inside your generic web method. All it does for the inbound, is to do the unmarshalling of the XML node to the Java class as per your other JAXB bindings. It must then lookup a Java package name (for your JAXBContext) from the QName of the DOM Element unmarshalled by your WS stack. The lookup can use properties file, reflection or any other mechanism specific to your deployment. For the outbound (return) you then apply a reverse logic to marshall the response. This approach is actually quite common, particularly when other type of unsupported-XML bindings technologies are "tunnelled" through a standard WS stack.
Related videos on Youtube
andbi
Updated on June 05, 2022Comments
-
andbi almost 2 years
I need to deploy the same web service for each customer. This
@javax.jws.WebService
usesObject
as method arguments and return types (resulting in<xs:anyType/>
in wsdl). Each instance of web service is deployed along with customer's jar on the classpath. This jar has known structure and contains JAXB-annotated classes which client wants to handle via my service.The problem is that when customer passes an instance of his class as method agrument, server-side JAXB context unmarshals it into some strange xerces dom node because (as I understand it) during the deployment time only
@WebMethod
and@WebService
annotations were scanned which, as was already said, are all dealing withObject
only.Simply speaking, I need to hint JAXB at
WEB-INF/lib/customer_classes_14586.jar
which means taking some control overJAXBContext
creation during JAX-WS deployment.Is it possible at all?
Server-specific solutions are fine (glassfish 3.1 with metro ws stack)
UPDATE
I've missed one thing that might be important: I deploy these web services as OSGI bundles at runtime via web admin console. When I press deploy button new jar is programmatically built up from customer library, webservice class, wsdl and manifests. So I could interfere in build process and provide hinting information at this point of time if this helps.
-
andbi over 12 yearsThanks for reply, it looks interesting. You said it's a quite common approach, could you please elaborate more on that - any links, resources or code samples?
-
Petru Gardea over 12 yearsPlease take a look at this article: ibm.com/developerworks/websphere/library/techarticles/…; I've used it as a reference back in the days where JAXB was emerging and a number of service stacks were based exclusively on JAX-RPC. You'll notice a similitude with your approach (SOAPElement being your Object in the signature). I believe these articles, quite common then, are still relevant in your case.
-
Petru Gardea over 12 yearsI noticed your update; you could rewrite generated Java code or config files as part of the automatic build process. I would look at what is created vs. what is needed and come up with a transform (text replace, XSLT, whatever works with you). Many people may sneeze at this; things such as the experience one gets while developing under a specific IDE may suffer since artifacts are somewhat "dynamic" or require additional steps. It really depends a lot more on the details of your solution.