Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get control over JAXBContext in JAX-WS?

I need to deploy the same web service for each customer. This @javax.jws.WebService uses Object 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 with Object only.

Simply speaking, I need to hint JAXB at WEB-INF/lib/customer_classes_14586.jar which means taking some control over JAXBContext 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.

like image 982
andbi Avatar asked Sep 04 '11 22:09

andbi


People also ask

What is JAXBContext?

The JAXBContext class provides the client's entry point to the JAXB API. It provides an abstraction for managing the XML/Java binding information necessary to implement the JAXB binding framework operations: unmarshal, marshal and validate.

Is JAXBContext thread safe?

JAXBContext is thread safe and should only be created once and reused to avoid the cost of initializing the metadata multiple times.

What is the use of @WebService annotation?

The annotation @WebService tells the server runtime environment to expose all public methods on that bean as a web service. You can control more levels of granularity by adding other annotations on individual methods or parameters. Using annotations makes it much easier to expose Java artifacts as web services.

What does JAX-WS stand for?

JAX-WS stands for Java API for XML Web Services. JAX-WS is a technology for building web services and clients that communicate using XML.


2 Answers

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.

like image 133
andbi Avatar answered Oct 15 '22 08:10

andbi


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.

like image 21
Petru Gardea Avatar answered Oct 15 '22 06:10

Petru Gardea