Is every rest service starting with extending that application class and defining applicationpath? What is the lifecyce of that application class itself? Here is an example:
import javax.ws.rs.core.Application;
#javax.ws.rs.ApplicationPath("resources")
public class ApplicationConfig extends Application {}
Is this a servlet? Is it always alive? How shall I understand this class? Is it a cdi bean? Does the server creates this class on every request?
What is Application?
Application is a deployment agnostic abstract class provided by JAX-RS for configuring and registering the components of a JAX-RS application and it's also used to supply additional metadata to the application.
Application is one of the types that can be injected using the #Context annotation. For more details, refer to this answer.
Subclasses of Application
Application subclasses can implement methods such as getClasses(), getSingletons() and getProperties() for configuring and registering components and properties.
Application subclasses can be annotated with #ApplicationPath, defining the base URI for the JAX-RS resource classes (classes annotated with #Path). Application subclasses are instantied once when the web application starts and they are managed by the JAX-RS runtime.
The simplest implementation possible is as following:
#ApplicationPath("api")
public SampleApplication extends Application {
}
In the example above no resources classes or providers are registered, so the JAX-RS runtime will scan the classpath for JAX-RS components and will register them automatically.
However, according to this post from Jakub Podlesak, this approach is discouraged in production environments:
The above example works great. When started, the application just scans the actual class-path, and adds every single JAX-RS component class found there to the actual runtime configuration. Isn't is great? Frankly, this kind of configuration could work just fine. Until someone changes either the system configuration (system class-path) or the way how you application is being packaged (a new 3rd party component could be added/removed from the application class-path then). These changes could be out of your control and if one of them happens, you application configuration could break. For this reason, it is not wise to use this kind of configuration in a production environment.
Jersey, the JAX-RS reference implementation, provides the ResourceConfig class. Compared to Application, ResourceConfig provides advanced capabilities to simplify registration of JAX-RS components, such as scanning for root resource and provider classes in a provided classpath or a in a set of package names, etc. For more details, refer to the Jersey documentation.
Working with multiple Application subclasses
Is also worth mentioning that you are not restricted to a single Application subclass per web application. The same WAR can have multiple Application subclasses. For more details, have a look at this post from Adam Bien:
To deploy multiple JAX-RS applications with different URIs in one WAR you will have to create one javax.ws.rs.core.Application subclass per such an application (or use web.xml for this purpose). Obviously the in Java EE ubiquitous Convention over Configuration (or Configuration by Exception) cannot work any more: you will have to explicitly configure resources in each subclass by overriding the method getClasses or getSingletons:
#Path("first")
public class FirstResource {
#GET
public String first() {
return "first";
}
}
#ApplicationPath("one")
public class JAXRSConfigurationOne extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> resources = new HashSet<>();
resources.add(FirstResource.class);
return resources;
}
}
#Path("second")
public class SecondResource {
#GET
public String first() {
return "second";
}
}
#ApplicationPath("two")
public class JAXRSConfigurationTwo extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> resources = new HashSet<>();
resources.add(SecondResource.class);
return resources;
}
}
Both JAX-RS applications become accessible through distinct URIs: http://localhost:8080/multiple-roots/one/first and http://localhost:8080/multiple-roots/two/second
What if no Application subclass is present?
If no Application subclass is present, the JAX-RS implementations are required to add a servlet and set its name to javax.ws.rs.Application and to automatically discover all resource classes and providers which must be packaged with the application.
For further details, have a look at the chapter 2 of the JAX-RS 2.1 specification.
Related
I am developing an application with Spring boot and deploying multiple WARs to an external tomcat.
I want to register a shareable bean with these WARs when tomcat starts.
I use: Java8, Spring boot(2.5.5) and Tomcat9
Bean I want to be shared by Apps:
public class TestData {
private String username;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
SampleApp(There are multiple apps that Autowire an instance of TestData in the same way):
#SpringBootApplication
#RestController
public class App extends SpringBootServletInitializer {
#Autowired
TestData testData;
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(App.class);
}
#RequestMapping(value = "SampleApp1", method = RequestMethod.GET)
public String getUsername() {
return testData.getUsername();
}
}
I think your question is about sharing the data of one singleton Bean between different application containers deployed in the same webserver.
This is not possible for security reasons. Each deployed application has its own classloader and hence cannot easily access beans residing in the memory of the other containers.
I suggest you add a microservice that is accessed by the different deployed applications and use that instead. It can easily be accessed via e.g OpenFeign as a client and almost looks like a bean with getters and setters if done right.
There are several approaches to your problem, solving it on different levels.
Create a shared library with required stuff and install it to Tomcat server. "Install" normally means to put assemled jars to $CATALINA_HOME/lib directory or similar. Class Loader HOW-TO can give you more details. Not sure how it works with shared instances of classes, but it's definitely possible to share classes (factories, for example) and configurations through shared library. With shared configuration and factories you can at least produce identical beans (not necessary the same, but it seems enough for you case).
Define a JNDI resource shared between all applications. Of course, this requires your class to be accessible by Tomcat, so you first have to go through option 1. This way you can have "published" instance of a class shared between all applications. Details can be found at JNDI Resources HOW-TO. With this approach you can inject published resource with #Resource annotation.
Create a microservice (as one of other answers suggests) that can provide you data and features and access it from your application. This gives you maximum flexibility but also brings complexity requiring actual communication to the microservice.
Obviously, options 1 and 2 require direct access to the server configuration.
I am just new to Spring and facing a design problem. The problem is i have a maven multiple module projects. Project Structures goes as follows.
module-backoffice - Packaging(war)
module-ws - Packaging(war)
module-dao - Packaging(jar)
module-shared - Packaging(jar)
In "module shared "all my service class and in "module-dao" all dao related codes exists.
module-shared and module-dao is in the build path of module-backoffice and module-ws.
Now Problem is when i run module-backoffice war and module-ws war Spring creates two instance of Service class beans and dao class beans.
What should i do so that one instance of service class and dao class will be created and shared among multiple war ? Please help. Thanks you.
Code in Module-Shared: Below is Service factory class
#org.springframework.stereotype.Service
public class Services {
#Autowired
private List<Service> services;
private static final Map<Class<?>, Service> serviceCache = new ConcurrentHashMap<Class<?>, Service>();
#PostConstruct
public void initServiceCache() {
services.forEach(service -> serviceCache.put(service.getClass(), service));
services = null;
}
public static Bootstrap bootstrap() {
return (Bootstrap) serviceCache.get(Bootstrap.class);
}
And the service class is :
#Component
public class Bootstrap implements Service {
public Bootstrap() {
System.out.println("Bootstrap");
}
}
When i run tomcat deploying two wars then in console two times "Bootstrap" printed. How do i restrict that.?
The purpose of web container like tomcat is to able to run applications independently so they can be started and stopped without affecting each other. In case you think there can be multiple future applications will also require the same service, you can make a separate application and expose an API for the operations.
I have implemented Javax WS RS API MessageBodyReader for com.ca.tas.crypto.cmp.client.GeneralPKIMessageJaxRsReader and MessageBodyWriter for org.bouncycastle.asn1.cmp.PKIMessage so that I can easily use the types in CMP over HTTP REST API. Now, to register the types I have created META-INF/services/javax.ws.rs.ext.Providers file and put the class names there. Everything works fine, I can do REST calls using the API, except:
IntelliJ IDEA (or one of the plugins I have installed into it) complains that
Registered extension should implement javax.ws.rs.ext.Providers
on the two lines in the file. Based on the resources I have found somewhere on the Internet I thought adding #Provider and #Produces("application/pkixcmp") annotations should be enough.
I have noticed that FasterXML Jackson has META-INF/services/javax.ws.rs.ext.MessageBodyReader and META-INF/services/javax.ws.rs.ext.MessageBodyWriter files and those seem to register a class that implements the interfaces as well.
So my questions are:
Is the IntelliJ IDEA correct or wrong to complain about me not implementing javax.ws.rs.ext.Providers?
What is the correct file to register the MessageBodyReader and MessageBodyWriter implementations?
What is the authoritative documentation that would enlighten me about this?
Is the IntelliJ IDEA correct or wrong to complain about me not implementing javax.ws.rs.ext.Providers?
The files in the META-INF/services are part of the way we can create extensible applications by making use of the ServiceLoader. How it works is that the filename should be the name of the contract and the contents of the file should be a list of implementations of that contract. The ServiceLoader will then see the file and collect all the implementations. So using the ServiceLoader, we could do
ServiceLoader<MessageBodyReader> readersLoader
= ServiceLoader.load(MessageBodyReader.class);
Based on the class passed to the load method, Java will search for the file
META-INF/services/javax.ws.rs.ext.MessageBodyReader
and look at the contents of that file to find all the implementations that it should load.
So based on that information, you can see that IntelliJ is correct in complaining, as your reader and writer do not correctly implement javax.ws.rs.ext.Providers.
One thing I should point out is that I don't think that the ServiceLoader class is used directly as it requires that the service implementations have no-arg constructors. But this is the exact pattern that is used in regards to the META services.
What is the correct file to register the MessageBodyReader and MessageBodyWriter implementations?
The use of META-INF/services files is not something that is a part of the JAX-RS specification. This is an implementation detail that will be specific to the JAX-RS implementation, though this pattern is used a lot. You will mostly see the files being used in reusable libraries, such as the Jackson library you mentioned1.
If the provider is going to be a part of our application, then there are more common ways in which to register it.
The #Provider annotation as you mentioned is a marker annotation to detect a provider class that should be registered. When scanning is enabled, the runtime scans for classes annotated with #Provider and then it will register them with the application.
When we talk about scanning, there are a couple different ways: classpath scanning and package scanning. Classpath scanning is enabled in a JAX-RS application by having an empty Application class that is annotated with #ApplicationPath.
#ApplicationPath("/api/*")
public class ApplicationConfig extends Application {}
This is enough to get a JAX-RS application configured2. Classpath scanning will be enabled, which will scan the entire classpath for all classes annotated with #Path and #Provider and register those classes.
Package scanning is something that is specific to the Jersey implementation. We could configure our application as such
#ApplicationPath("api")
public class ApplicationConfig extends ResourceConfig {
public ApplicationConfig() {
package("the.package.to.scan");
}
}
Here, we are telling Jersey to scan the the.package.to.scan package for #Path and #Provider classes to register with the application.
Another way to register our providers is to explicitly register them. In Application subclass, you would override getClasses() or getSingletons() to register them as a class or as an object, respectively.
#ApplicationPath("/api/*")
public class ApplicationConfig extends Application {
private final Set<Class<?>> classes = new HashSet<>();
private final Set<Object> singletons = new HashSet<>();
public ApplicationConfig() {
classes.add(MyMessageBodyReader.class);
singletons.add(new MyMessageBodyReader());
}
#Override
public Set<Class<?>> getClasses() {
return this.classes;
}
#Override
public Set<Object> getSingletons() {
return this.singletons;
}
}
Note that once you override either of these methods and return a non-empty set, the classpath scanning is automatically disabled, and you will need to register everything manually.
If you are using the Jersey implementation, there are also Jersey specific ways that we can explicitly register resources and providers. For more discussion on this, see What exactly is the ResourceConfig class in Jersey 2?.
Another way I can think to register providers is through the use of features. We can use the vanilla Feature or we can use a DynamicFeature.
With the Feature, we register the provider with the entire application
// We should register the feature with our application
public class MyFeature implements Feature {
#Override
public boolean configure(FeatureContext context) {
context.register(MyMessageBodyReader.class);
}
}
With a DynamicFeature we can selectively register a provider with specific resource methods or resource classes. See more in the Jersey docs for dynamic binding. It should be noted that dynamic binding is more used with filters and interceptors (which are also in the general sense of the term, providers) and not so much with entity providers (MessageBodyReader/Writers).
There may be other ways to register your providers, but the one mentioned above are the main ways that you will see it being done in an application.
What is the authoritative documentation that would enlighten me about this?
I'm not sure how much information about META-INF/service files in any documentation. But explicit registration and classpath scanning, you will probably find in the JAX-RS specification or Jersey documentation
1 - It should be noted that just because the file is there, it does not mean that it will be used. It is up to the JAX-RS implementation whether or not they care to use it. For Example, Jersey will not use it on MessageBodyReaders and writers.
2 - See How to use Jersey as JAX-RS implementation without web.xml?
I am planning to implement the Rest service with help of RestEasy framework (3.0.11) and servlet version 3.
I have used resteasy-scan context to scan my rest service at time of runtime, but since servlet version 3.0 hence It is not scan and throwing exception (deployed in tomcat7).
Could you please suggest me to resolve the issue, how to scan the rest services?
Any example or configuration of web.xml would be good.
One way, without any web.xml (RESTeasy servlet) configuration is to just have an empty Application subclass, annotated with #ApplicationPath (for the url-mapping).
According to the JAX-RS spec, in a Servlet 3.x environment if you have the following
#ApplicationPath("/api")
public class MyAppliation extends Application {
}
this is enough to cause the application to register resource class and provider through classpath scanning. In contrast, we could explicitly register resources class and providers this way
#ApplicationPath("/api")
public class MyAppliation extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> classes = new HashSet<Class<?>>();
classes.add(MyResource.class);
return classes;
}
#Override
public Set<Object> getSingletons() {
Set<Object> singletons = new HashSet<Object>();
singletons.add(new MyFilter());
return singletons;
}
}
According to the spec, once we return a non-empty set from either one of these overridden methods, it is assumed the application takes care of all the registration, and the classpath registration is disabled.
Now this is not what you want, but it is just a background as to why the empty class works.
I have two application deployed on glassfish - application A and B.
Both are deployed as war package, application B uses some components from application A.
Now in application A I have an interface:
public interface BusinessInterface() extends SomeOtherInterface {
void someAction();
}
I have 3 implementations of this interface - two in application A, one in application B: BusinessInterfaceA1, BusinessInterfaceA2, BusinessInterfaceB
As long as all of them are CDIBeans, everything is fine - I'm using custom #Qualifier annotations (#BusinessInterfaceA1, #BusinessInterfaceA2) and #Default annotation for B's implementation to distinguish them.
But now I need both application's A implementations to be Stateful EJBs and this is where it becomes funny.
When I just add #Statefull annotation on both implementations, a I got something like this:
javax.servlet.ServletException: org.jboss.weld.exceptions.WeldException: WELD-000049
details:
java.lang.IllegalStateException: Unable to convert ejbRef for ejb BusinessInterfaceA1 to a business object of type interface SomeOtherInterface
How can I fix it? I need all implementations to be avaliable in a way I could inject them like
#Inject #SomeAnnotation private BusinessInterface businessInterface;
It is bug in Glassfish 3.1. The workaround is, to mark implementation with all required interfaces, e.g.:
#Statefull/#Stateless
public class BusinessInterfaceImpl implements BusinessInterface, SomeOtherInterface {
// implementation
}
Even BusinessInterface extends SomeOtherInterface, and from Java specs its useless to do that, but as a workaround for that bug it works.
Another solution is to use Glassfish 4.0