Replace AbstractContainerRequestValueFactory in Jersey 2.26 - java

Hi all I´m struggling migrating from Jersey 2.25 to 2.26 since, it has a break change in a internal class of the library AbstractContainerRequestValueFactory
They claim in the issue sections that since the package is internal it should not be used. But they dont offer a solution or workaround.
Any idea how can I replace the use of that class for something else to continue using the provide implementation as I´ve been doing so far?
class MyOwnFactory extends AbstractContainerRequestValueFactory[Future[Object]] {
override def provide: Future[Object] = getContainerRequest.getProperty(Constants.individual).asInstanceOf[Future[Object]]
}

The equivalent would be to use a Supplier and inject the ContainerRequest, as the Supplier replaces the HK2 Factory and all AbstractContainerRequestValueFactory is is an HK2 Factory that injects the Provider<ContainerRequest>. Just look at the source
See also:
Jersey 2.26: register #Inject in ResourceConfig bindFactory cannot convert Factory to Supplier
Registering a custom ValueParamProvider in Jersey 2.27

Related

#RolesAllowed interfering with #RequestMapping

In a spring boot app, using annotations only, i want to implement security
I have added an #EnableGlobalMethodSecurity(jsr360Enabled=true) to a configuration class. the class also has an #EnableSecurity anntation
Now, when i add a #RolesAllowed to any #RestController class, be it on method level or level, the startup logs don't list the class at all. instead , there is line:
'Rejected bean name (rest controller class): no URL paths identified'.
Does anyone have an idea what might be causing this?
After #M.Deinum set me on the path, i did some reading and have an explanation. If anyone can elaborate more or correct me on the more technical details, feel very welcome.
Spring proxies classes to wire beans together.
Classes that don't implement an interface are proxied by using CGLib to make a subclass with additional functionality
classes that do implement an interface, spring uses dynamic proxy to access the functionality of the class, but doing so it can only proxy interface methods.
in my case, my controller implements an interface with non-endpoint related methods, so spring ignored all handling methods and the RequestMappingHandlerMapping did not find any methods to bind, because if only 'saw' the interface methods on the class
using #EnableGlobalMethodSecurity(proxyTargetClass=true) forces the use of CGLib, so the full methods are recognised by our mapper.

What is the proper place to register MessageBodyReader and MessageBodyWriter implementations?

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?

CXF SpringComponentScanServer usage

I want to configure CXF to auto-scan for resources, providers, features, and the lot. In my search I came across the SpringComponentScanServer, which sounds like something I need. Unfortunately, documentation about this class is virtually non-existent.
When you have classes annotated with #javax.ws.rs.ext.Provider, they get picked up by CXF as expected. When you have a feature annotated with org.apache.cxf.annotations.Provider, it will also get picked up by CXF.
But what if you have a third-party feature that does not have this annotation?
For example, the CXF LoggingFeature? You cannot, as far as I know, add an annotation to a class if you can't change it's source code.
I came up with the following, hideous, solution, but surely, there must be a better way to do this???
#Configuration
#Import(SpringComponentScanServer.class)
public class CxfConfig {
#Component
#Provider(Provider.Type.Feature)
static class MyLoggingFeature extends LoggingFeature {
}
}
Here, I basically extend the existing LoggingFeature, only to add the #Provider annotation.
I found the following example CXF JAXRS Spring Boot example, which does what I want with the Swagger2Feature. That works, but only starting from CXF 3.1.6, and only for the Swagger2Feature. Not for LoggingFeature.
So my question is: is there a less hideous way to add the LoggingFeature?

How do I get my Jersey 2 Endpoints to eagerly initialize on startup?

I am porting some code from Jersey 1.x and my implementation of various Health Check endpoints relies on all the #Singleton endpoint resources being initialized at start up so as to be able to detect which checks to do.
In Jersey 2.0 - whatever I do I can't seem to get my resource endpoints to initialise at start up and they are only constructed+initialized when each one is accessed for the first time.
I guess I could initialise them myself in the Application class but I'd rather use the package scanning!
Does anyone have any idea if there is some config option that will tell Jersey 2 to eagerly initialise all resource endpoints that it finds during package scanning?
Or some HK2 annotation or trick?
"Or some HK2 annotation or trick?"
You can use HK2's Immediate Scope. Just annotate the resource class with #Immediate (which acts like #Singleton, so you can get rid of that), then enable the immediate scope on the ServiceLocator. An example:
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.hk2.utilities.ServiceLocatorUtilities;
...
#ApplicationPath("/rest")
public class JerseyApplication extends ResourceConfig {
#Inject
public JerseyApplication(ServiceLocator locator) {
ServiceLocatorUtilities.enableImmediateScope(locator);
packages("thepackages.to.scan");
}
}
UPDATE
Based on this related question, if you need to explicitly instantiate the ResourceConfig, as in the case of the linked question, you can create a Feature and register the feature, as seen in this answer
UPDATE 2
Please see related issue
UPDATE 3
Looks like Immediate scope memory leak issue previously linked to has been resolved in version 2.22.1

HK2 annotations not being handled

I'm using HK2 through Jersey, and am looking to get #Immediate services working. In the process, I notice that (as it seems) none of the annotations for my services are getting registered. E.g., after spinning up my ServiceLocator and looking at my descriptor for a service annotated with #Singleton, it is still set as #PerLookup. My code for initiating my application handler is below:
ApplicationHandler handler = new ApplicationHandler(resourceConfig, new AbstractBinder() { ... });
My binder registers a service like so:
bindAsContract(ShouldHaveSingletonScope.class);
Looking at my ServiceLocator immediately after this, I see that the scope is not being pulled from the class (still #PerLookup). Is there something additional I need to specify to tell HK2 to parse class annotations? This seems like a pretty standard use case so I must be missing something.
There is a method on ServiceLocatorUtilities called addClasses
So get access to the ServiceLocator and just do
ServiceLocatorUtilities.addClasses(locator, ShouldHaveSingletonScope.class);
The binders are very literal, and will only do what you tell it as opposed to looking at the classes directly.
This should work:
bindAsContract(ShouldHaveSingletonScope.class).in(Singleton.class);
You can either configure the locator manually using Binder
-or-
use hk2 annotations, run hk2-inhabitants-generator (see hk2 doc) which will generate META-INF/hk2-locator/default file, then you will need to create your own ComponentProvider (see jersey doc) to populate service locator from that.

Categories

Resources