How does Java initialize the JAXB/JAX-WS/etc implementation?
Asked Answered
N

4

7

I'm just digging around a bit trying to understand how Java can have standard reference implementations included in the JRE (eg JAXB/JAX-WS in JRE6), while still allowing 3rd-party implementations to override that (eg CXF).

I've gotten to the place that I found the javax.xml.ws.spi.FactoryFinder.find() method which either locates the class specified in META-INF/services/java.xml.ws.spi.Provider or com.sun.xml.internal.ws.spi.ProviderImpl (for the JAX-WS case) and creates an instance of that.

What I can't find is how/where/at which stage the JRE calls that FactoryFinder.find() method.

Can anybody enlighten me?

[edit] I've found the answer but am not allowed to post it myself for another 3 hours...

Newberry answered 1/1, 2012 at 11:25 Comment(0)
N
6

Figured out the complete logic. Actually nothing happens on JVM startup. It's all based on lazy loading, eg the real JAX-WS/whatever provider is only loaded/instantiated the first time it's needed.

In the case of loading the JAX-WS implementation:

Assume we want to call a web service, using code like:

MyService     service = new MyService_Service();
MyServiceSoap port    = service.getMyServiceSoap();

port.mymethod(); 

then the following happens to initialize the JAX-WS implementation:

  • Any JAX-WS webservice extends javax.xml.ws.Service, so MyService_Service extends Service
  • When you create an instance of your web service, its superclass (javax.xml.ws.Service) is also initialized (constructor)
  • The constructor for "Service" calls javax.xml.ws.spi.Provider.provider(), which is a static method that uses javax.xml.ws.spi.FactoryFinder.find() to find and instantiate the implementation as configured.

Assume we want to publish a web service using code like:

@WebService(endpointInterface = "my.package.MyService")
public class MyServiceImp implements MyService {
    ...
}

MyServiceImp      service  = new MyServiceImp();
InetSocketAddress addr     = new InetSocketAddress(8080);
Executor          executor = Executors.newFixedThreadPool(16);
HttpServer        server   = new HttpServer(addr);
server.setExecutor(executor);

HttpContext       context  = server.createContext("/MyService");
Endpoint          endpoint = Endpoint.create(service);
endpoint.publish(context);
server.start();

then the following happens to initialize the JAX-WS implementation:

  • Endpoint.create() runs Provider.provider().createEndpoint()
  • Provider.provider() is a static method that uses javax.xml.ws.spi.FactoryFinder.find() to find and instantiate the implementation as configured.

The following links helped me understand this:

Newberry answered 1/1, 2012 at 19:27 Comment(0)
F
3

You can change the default behavior using system property javax.xml.bind.context.factory. Its value should be the fully qualified class name of the factory.

The default value of this property is com.sun.xml.internal.bind.v2.ContextFactory. This factory is not required to implement any specific interface by it must implement method createContext(String, ClassLoader, Map)

Ferneferneau answered 1/1, 2012 at 11:34 Comment(2)
But does that mean that the logic behind these Factory methods is basically hardcoded into the specific JRE release? Eg JRE 6 knows specifically about JAX-WS/JSR224(?) and has some "onStartup" hook inside it that explicitly calls FactoryFinder.find() for those standards it knows about?Newberry
As far as I understand it "knows" one default implementation. But one can override it by implementing his own ContextFactory and configuring it using the mentioned system property.Ferneferneau
W
2

There are a few mechanisms which control which implementation you use. each jre/jdk has a built in "default" implementation hardcoded into the init code. There are also some system properties you can use to specify a specific implementation (as @AlexR mentioned). however, that is not the standard mechanism for specifying a different implementation. most alternate implementations include a special file in their META-INF directory (within the jar) which indicate to the jre/jdk that they should be used instead of the default implementation (this works without setting any system properties, you just drop the jars into the classpath). these special files are found by ServiceLoader utility and enable the alternate implementation to be automatically loaded.

Welty answered 1/1, 2012 at 13:18 Comment(0)
W
1

I found that a working JAXB sample fails after putting a weblogicfullclient.jar onto the classpath, because the jar contains a META-INF/services/javax.xml.bind.JAXBContext but not the implementation. Unfortunately, one cannot tell JAXB to "just use PLATFORM_DEFAULT_FACTORY_CLASS", you have to put it on a System property (-Djavax.xml.bind.JAXBContext=com.sun.xml.internal.bind.v2.ContextFactory for 1.6 and -Djavax.xml.bind.context.factory=.. for 1.7), the javax.xml.bind.ContextFinder.find(String, String, ClassLoader, Map) implementations differ for 1.6 and 1.7

Whitlow answered 26/9, 2013 at 12:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.