How does the Jakarta RESTful Web Services Specification load an implementation into runtime.

The Jakarta RESTful Web Services Specification actually implements the service loading process, and it allows different implementation frameworks to be loaded in a standard way. Here is the code repository of the spec:

The above repository contains the Java code that defines the interfaces and part of the implementation code that should be shared around all the implementation frameworks.

Note Currently the javadoc inside the code is still using the term JAX-RS, which should be replaced to Jakarta RESTful Web Services or the acronym in the future. There were discussion to the acronym to be used and it is not determined yet: Renamed project to ‘Jakarta RESTful Web Services’ by mkarg · Pull Request #763 · jakartaee/rest · GitHub

In this article I want to analyze the way the spec loads an implementation framework into runtime. The loading process involves several classes, and here is their class diagram:

The above two abstract classes(HeaderDelegate is an inner class of the RuntimeDelegate class) are implemented inside the spec code:

And inside RuntimeDelegate it defines the way to load the implementation into runtime. Here is the javadoc inside the RuntimeDelegate class:

From the javadoc we can see this abstract class should be extended by every implementation framework. Besides, it already defines several methods related with the framework loading process. The entry method is the getInstance() method as shown in above class diagram, and here is the source code of the method:

From the above code we can see it calls the findDelegate() method to do the implementation class loading. Here is the sequence diagram of the findDelegate() method:

From above, we can see it called the find() method from the FactoryFinder class. Here is the source code of the findDelegate() method:

From the above code, we can see it passes the JAXRS_RUNTIME_DELEGATE_PROPERTY and RuntimeDelegate.class into the Factory,find() method. The value of JAXRS_RUNTIME_DELEGATE_PROPERTY is defined in the RuntimeDelegate class itself:

public static final String JAXRS_RUNTIME_DELEGATE_PROPERTY = "jakarta.ws.rs.ext.RuntimeDelegate";

We’ll see how this value and the RuntimeDelegate class is used in the find() method of the FactoryFinder class:

From the above source code of the FactoryFinder class, we can see it passes the parameters into the findFirstService() method:

From the above code we can see the parameters are actually passed into the ServiceLoader.load() method. Until now, we can see the whole process relies on the ServiceLoader, which is a feature provided by Java:

Generally speaking, one can write a pure text file with the interface or the abstract class name, and put the implementation class name inside the file, then ServiceLoader will help to load it into Java runtime.

So the loading process becomes clear: The implementation framework should provide a text file named jakarta.ws.rs.ext.RuntimeDelegate and put the implementation class into the file. Taking RESTEasy as one of the implementation frameworks for example, we can check whether it has this file or not. Doing a file search inside the RESTEasy source code directory will find the result:

➤ find . | grep jakarta.ws.rs.ext.RuntimeDelegate
./resteasy-core/src/main/resources/META-INF/services/jakarta.ws.rs.ext.RuntimeDelegate

As the result shown above, we can see it does have this file, and let’s see the content of the file:

cat ./resteasy-core/src/main/resources/META-INF/services/jakarta.ws.rs.ext.RuntimeDelegate                                                                                                                                                                                                       
org.jboss.resteasy.core.providerfactory.ResteasyProviderFactoryImpl

From the above result, we can see RESTEasy provides an implementation class to the jakarta.ws.rs.ext.RuntimeDelegate, which is ResteasyProviderFactoryImpl. Here is the class diagram of the RESTEasy classes:

As the class diagram shown above, we can see ResteasyProviderFactoryImpl extends the ResteasyProviderFactory class, and the ResteasyProviderFactory class extends the RuntimeDelegate class.

We can see this is the way defined by the spec how an implementation is loaded into runtime.

My Github Page: https://github.com/liweinan

Powered by Jekyll and Theme by solid

If you have any question want to ask or find bugs regarding with my blog posts, please report it here:
https://github.com/liweinan/liweinan.github.io/issues