HK2 annotations not being handled - java

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.

Related

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?

Registering DirectChannelMetrics as a JMX Bean programmatically

I have a Spring integration application with several FileTailingMessageProducers and DirectMessageChannels created programmatically -- i.e. not through XML configuration, but within a ApplicationListener<ContextRefreshedEvent>. Now I would like to monitor the message channels using JMX. I guess I will have to add them using my integrationMBeanExporter.
This is what I tried:
DirectChannelMetrics directChannelMetrics = new DirectChannelMetrics(tailedLines, "tailedLines");
integrationMBeanExporter.getServer().registerMBean(directChannelMetrics, new ObjectName("d:foo=foo"));
Yet I am getting the following Exception:
javax.management.NotCompliantMBeanException: MBean class org.springframework.integration.monitor.DirectChannelMetrics does not implement DynamicMBean, and neither follows the Standard MBean conventions
It is surprising to me, that the DirectChannelMetrics does not fulfill JMX requirements, since when I look into my application with jvisualvm I can see other beans of this type registered without problems.
Any ideas?
From one side MBeanExporter does this on the matter:
return new StandardMBean(bean, ((Class<Object>) ifc));
Before registering bean as an MBean.
From other side I think your logic smells a bit. It looks abnormal to create MessageChannels at runtime. Especially those which are for the JMX export.
I can agree about dynamic FileTailingMessageProducers, but seems for me we can avoid dynamic channels with refactored logic for the predefined channels.
You could leverage Spring's MBeanExport.registerManagedResource(directChannelMetrics, new ObjectName("d:foo=foo")). Spring will generate a management interface for the instance of DirectChannelMetric class. But DirectChannelMetric class needs either to implement the Mbean/MXBean interface or to match current MBeanInfoAssembler expectations(be marked with the #ManagedResource annotation in the case of MetadataMBeanInfoAssembler or implements one of specified interfaces in the case of InterfaceBasedMBeanInfoAssembler etc).

How do I register beans in camel unit tests that use beans?

I want to unit test single routes configured in java that uses beans. I read in camel in action (chapter 6.1.4) how to do this:
protected RouteBuilder createRouteBuilder() throws Exception {
return new myRoute();
}
But in my case the rout needs some beans to be registered. I know how to register beans in standalone app: see here
But how to register beans within "CamelTestSupport"? Is there a way to use beans without registry? Probably by injecting them (all beans hav no arg constructors)? I am using Guice and in my tests i am using Jukito (Guice+Mockito).
Afer Camel 3.0.0
You can now update the JNDI registry from anywhere you have access to the camel context.
context.getRegistry().bind("myId", myBean);
More info available here https://camel.apache.org/manual/latest/camel-3-migration-guide.html#_camel_test
Before Camel 3.0.0
You need to override the createRegistry() method,
#Override
protected JndiRegistry createRegistry() throws Exception {
JndiRegistry jndi = super.createRegistry();
//use jndi.bind to bind your beans
return jndi;
}
#Test
public void test() {
//perform test
}
No, you cannot use beans without registry.
You need to use the registry to hold the beans instance, otherwise Camel cannot look up the bean for you. You just need to override the createRegistry() method to setup right registry with your beans if your test class extends CamelTestSupport.
The answer provided by #Matthew Wilson is no longer recommended starting with Camel 3.0.0
His solution is still in the ballpark but the implementation details have changed. I have chosen to inject it in setUp (the example is in Kotlin, use your IDE hints to produce the same in Java):
override fun setUp() {
super.setUp()
context.registry.bind("yourBean", YourBean())
}
As you can see, the registry is still involved but now you can only get it from the context. I consider it cleaner to keep these kinds of setup routines in the conveniently named overrideable method setUp. Just don't forget to call the parent version.
If there is a better place to put this kind of routines in, let me know so I can upgrade the answer.
Docs: https://camel.apache.org/manual/latest/camel-3-migration-guide.html

Jersey 2.* & HK2. Inject different object (e.g. DAO) based on a path parameter

I am implementing a multi-tenant application. Many of my resources have paths like "/api/tenant/{tenant_id}/resource/path/". What I would like to do is to inject different DAOs (or possibly other objects) to the resource based on the "{tenant_id}" path parameter.
I have two suboptimal ideas on how to achieve something similar:
Use a wrapper class like this:
class SomeDAOWrapper
{
SomeDAO getSomeDAO()
{
return new SomeDAO(tenantId_m);
// Alternatively we could store the DAOs in some hash-table
// with tenantId_m as the key.
}
#PathParam("tenant_id")
private long tenantId_m;
}
Then in my resource class I would have SomeDAOWrapper as an attribute annotated with #BeanParam.
Use a sub-resource locator on path "/api/tenant/{tenant_id}" that would return the resources with the correct DAOs.
Any other ideas? Ideally what I would like to do is to simply have SomeDAO attribute in my resource class that is annotated with #Inject or something similar (and that would use some factory that takes the tenant_id path parameter into account).
I ran into this same kind of problem and ended up using the guice multibinder solution. You essentially bind your Dao's to a MultiBinder and then Inject a factory into your service. This was the cleanest solution I could come up with for the problem.
Check out this url, it is pretty much what I did to get dependency injection working with a resource that needed a specific dao.
https://groups.google.com/forum/#!topic/google-guice/J6S77sILTAY

Binding generated classes in gin

I am trying to dynamically generate some set of event handlers (using com.google.gwt.core.ext.Generator subclass). The whole generation process works fine, my generated handlers accepts EventBus via setter injection (#Inject annotation) and the whole idea is that these automagically generated handlers register themselves in the (injected) EventBus under the hood. The problem is that all these handlers must be somehow instantiated. GIN does not know anything about them until they will be bound in GIN module; something like below:
bind(MyDynamicallyGeneratedHandler.class).asEagerSingleton();
The problem with this code is that I have to generate gin module also (which will contain all bind(...) instructions). It works well but I cannot install generated module (#Inject it) into another not generated module so that its bind instructions are executed (as a result of install(MyDynamicModule.class)). I tried dirty tricks with static injection and providers - all without success.
Is there any way to configure dynamically generated GIN module? Or maybe is there any way to instantiate dynamically generated handlers so that setter injection (and thus event bus registration) happens?
Here is sample code snippet:
// it is standard interface
public interace DynamicHandler {
#Inject
void setEventBus(EventBus eventBus);
}
// one of dynamically generated handlers
// where (how) to instantiate me?
public class MyHandler implements DynamicHandler {
#Inject
AnotherHandlerSpecificComponent component
void setEventBus(EventBus eventBus) {
eventBus.register(...); // register myself
}
}
Important thing to note is that all these dynamically generated handlers have some other dependencies #Injected (apart from EventBus). And these dependencies (their types) ale handler-specific (AnotherHandlerSpecificComponent in the example above). So what I need to do is to instantiate these handlers in a way that triggers GIN injection (I cannot, for example, inject dependencies manually).
Thanks in advance for any clues. I am totally stucked...
How about a Factory where you inject the dependencies for the handlers and try to instantiate and register the actual handlers (e.g. by reflection or scanning the file system?)

Categories

Resources