How can I mix Guice and Jersey injection? - java

I've already seen the following question on how to inject #Context dependencies into Jersey resource constructors. But my question is slightly different -- I'd like to inject a #PathParam String. I have a class resembling the following:
#Path("foo/{fooId}/bar")
public class BarResource {
#Inject
public BarResource(#PathParam("fooId") String foo, Service service) {
...
}
...
}
The Service is injected fine by Guice, but the path segment is always null. This actually surprises me; if anything I assumed Guice would loudly explode complaining about an unresolvable dependency.
How can I inject a path parameter in this manner? I would prefer to avoid field injection for the purposes of keeping these resource classes unit-testable.

It appears that #PathParam is not acceptable by default as a Constructor argument. This new feature document states
The arguments allowed in a resource class constructor depends on the resource provider used to create an instance of the resource class [...]. For default per-request resource classes you can use any combination of parameters annotated with UriParam, UriParam, QueryParam, MatrixParam, HeaderParam or HttpContext.
You could provide your own resource provider that processes the #PathParam annotation.

Related

Spring to use fully qualified names for constructor dependency injection

I have multiple modules (application + library) in a project and they contain service classes of same names (but different packages) that are to be injected thru Lombok generated constructors within their respective modules.
When I start the app module, the Spring's ClassPathBeanDefinitionScanner however picks both and raises BeanDefinitionStoreException because it detects both as a candidates, due to the same bean name and doesn't care about the fully qualified type name.
Is there an option to enable more precise resolution of the beans that also requires a type match?
Isn't this a design flaw? What am I missing?
Edit: Names, I believe, are taken from constructors generated by Lombok's #RequiredArgsConstructor, and service classes are also generated code (MapStruct mappers).
You can use #Component("beanName"), #Bean("beanName"), #Named("beanName") to assign a custom name to a bean. By default, spring uses the class name as the bean name. For Example, you can define bean name of your CustomAccountsApiController class as below:
#RestController("customAccountsApiControllerPrimary")
public class CustomAccountsApiController {
}
You can read more on bean name from here

Constructor bean injection with custom annotation

I would like to inject a bean (lets call it clientStub) into my service bean.
There are two requirements for that:
In order to create the clientStub bean, I need to access the #Client annotation, that carries some important information that are used to lookup the relevant configuration in the properties.
It must support constructor based injection (and #Bean method parameter injection)
Expected usage:
#Autowired
public MyService(
#Client("invoice-manager") InvoiceManagerClientStub clientStub,
SomeOtherBean bean1, ...) {
or
#Bean
MyService myService(
#Client("invoice-manager") InvoiceManagerClientStub clientStub,
SomeOtherBean bean1, ...) {
So I would like to do the same as the #Value annotation e.g. derive the value from the annotation on the parameter (plus some internal lookups).
Unfortunately, the usual BeanFactorys don't seem to be aware of the target's annotations.
Alternatives considered
Using an BeanPostProcessor to inject the values into annotated fields. Well, this is what I'm currently doing, but it doesn't feel right to have an immutable class with a single setter for injection.
Injecting it to a field and then exposing it as a bean or manually invoking the constructor is even worse.
Creating a proxy instance of the injected class. This isn't possible since the injected classes are generated + final and not part of my library.
Derive the configuration from the bean name: Not sure how to implement this and how to explain the user what the configuration parameters should be named in their properties files. I also would like to avoid bean name conflicts.
Non-Goals
Overwriting any core beans. I would like to distribute the extension as a library (spring-boot based), so any excessive replacement of spring internal beans should be avoided.
TLDR
How do I tell spring to resolve the parameter using my annotation's value (resolver)?

How do HttpSession and HttpServletRequest inject into Spring by #Autowired? [duplicate]

As I know per default are controllers in Spring MVC singletons. HttpServletRequest passed offen to the controller handler method. And its ok, while HttpServletRequest is request-scoped, but I see often HttpServletRequest gets #Autowired into the controller field, like this:
#Controller("CMSProductComponentController")
#RequestMapping(CMSProductComponentController.CONTROLLER_PATH)
public class CMSProductComponentController {
#Autowired
private HttpServletRequest request;
}
Could be this a problem? And more general question: What happens if inject a reqeust-scoped component into a singleton?
No, for HttpServletRequest it will not be a problem and it shouldn't for other request scoped beans. Basically, Spring will generate a proxy HttpServletRequest that wraps some kind of ObjectFactory (RequestObjectFactory for HttpServletRequest) (YMMV) that knows how to retrieve the actual instance. When you use any of the methods of this proxy, they will delegate to that instance.
What's more, this is done lazily, so it won't fail at initialization. It will however fail if you try to use the bean when there is no request available (or if you haven't registered the RequestScope).
The following is in response to the comments and to clarify in general.
Regarding the proxy-mode attribute of #Scope or the XML equivalent, the default is ScopedProxyMode.NO. However, as the javadoc states
This proxy-mode is not typically useful when used with a non-singleton
scoped instance, which should favor the use of the INTERFACES or
TARGET_CLASS proxy-modes instead if it is to be used as a dependency.
With request scoped beans, this proxy-mode value will not work. You'll need to use INTERFACES OR TARGET_CLASS depending on the configuration you want.
With scope set to request (use the constant WebApplicationContext.SCOPE_REQUEST), Spring will use RequestScope which
Relies on a thread-bound RequestAttributes instance, which can be
exported through RequestContextListener, RequestContextFilter or
DispatcherServlet.
Let's take this simple example
#Component
#Scope(proxyMode = ScopedProxyMode.INTERFACES, value = WebApplicationContext.SCOPE_REQUEST)
public class RequestScopedBean {
public void method() {}
}
...
#Autowired
private RequestScopedBean bean;
Spring will generate two bean definitions: one for your injected bean, a singleton, and one for the request scoped bean to be generated on each request.
From those bean definitions, Spring will initialize the singleton as a proxy with the types of your target class. In this example, that is RequestScopedBean. The proxy will contain the state it needs to produce or return the actual bean when it is needed, ie. when a method is called on the proxy. For example, when
bean.method();
is called.
This state is basically a reference to the underlying BeanFactory and the name of the request-scoped bean definition. It will use these two to generate a new bean and then call method() on that instance.
The documentation states
The Spring IoC container manages not only the instantiation of your
objects (beans), but also the wiring up of collaborators (or
dependencies). If you want to inject (for example) an HTTP request
scoped bean into another bean, you must inject an AOP proxy in place
of the scoped bean. That is, you need to inject a proxy object that
exposes the same public interface as the scoped object but that can
also retrieve the real, target object from the relevant scope (for
example, an HTTP request) and delegate method calls onto the real
object.
All eagerly loaded request scoped beans, if implemented correctly, will be proxies. Similarly, request scoped beans that aren't eagerly loaded will either be proxies themselves or be loaded through a proxy. This will fail if there is no HttpSerlvetRequest bound to the current thread. Basically, a proxy is necessary somewhere in the bean dependency chain for request scoped beans.
What happens if inject a reqeust-scoped component into a singleton?
Try it and you'll get a BeanCreationException¹ during application context initialization. The error message clearly explains why this doesn't happen with HttpServletRequest:
Scope 'request' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton;
So obviously HttpServletRequest is a scoped proxy. If you want to use beans of smaller scopes in singletons they have to be proxies. The documentation elaborates about smaller scoped dependencies in Scoped beans as dependencies.
[1]: unless you didn't change the default behaviour for proxyMode, which is NO or try to inject it with #Lazy. The latter might result into a valid application context but might lead to request scoped beans acting like singletons (e.g. if a request scoped bean is injected into a singleton).

How to get DI working with Guice and Webapps?

How do you get DI to work in a webapp? So far I've done the following:
1) Annotate setter method with #Inject
2) Extend AbstractModule so that it binds the interface class to the implementation class for the attribute whose setter was annotated in step 1
3) Extend GuiceContextServletListener and overrode getInjector so that it returns Guice.createInjector(new ExtendedAbstractModule())
4) Registered the extended GuiceContextServletListener in web.xml as a listener
I've verified that the extended GuiceContextServletListener.getInjector() method is called when the webapp is started. The attribute whose setter was annotated is not being injected and remains null.
I went ahead and created a ServletModule that serves the servlet that instantiates the object with the #Inject setter. After instantiating the object I get the Injector from the ServletContext and call the injectMembers method passing it the instantiated object.
What annotation are are you using on the setter?
I normally use #Named annotation to get attribute values which can be pointed to a property file or setup individually.
http://code.google.com/p/google-guice/wiki/BindingAnnotations
#Inject
void somethingSetter(#Named('Tag')String s) {
}
There is a tutorial of how to setup a complete Java web service using Guice and Sitebricks here:
http://www.techtraits.ca/five-minute-guide-to-setting-up-a-java-webserver/

is it not allowed to implement a single local interface by two stateless beans?

I am getting following exception when a Local Interface is implemented by two Stateless beans, in which one having normal functionality and other having some enhanced functionality in it.
java.lang.RuntimeException: could not
resolve global JNDI name for #EJB for
container UserBean: reference class:
org.app.SecurityServiceLocal ejbLink:
duplicated in Some.jar
Finally I came to know why I am getting this exception
I have used #EJB annotation to inject a Stateless bean into another Stateless bean Name UserBean with following code
#Stateless(name="UserBean")
#EJB(name="app/SecurityService",
beanInterface=SecurityServiceLocal.class)
public class UserBean implements UserRemote{
}
If you check the injection details I was injecting SecurityServiceLocal, which was implemented by two Stateless bean classes name SercurityServiceBean and SecurityServiceEnhaBean. So, container is in ambiguity state to decide which bean to inject in as both are implementing same interface.
This can be resolved by specifying some more information like beanName property value in #EJB annotation. There you need to provide which stateless bean class needs to be injected by using bean name(declared at that bean level (or) in ejb-jar.xml). check the code to identify the change in the injection mapping
#Stateless(name="UserBean")
#EJB(name="app/SecurityService",
beanInterface=SecurityServiceLocal.class,
beanName="SecurityServiceEnha")
public class UserBean implements UserRemote{
}
It's hard to say for sure without seeing code. A good first step would be to use the optional mappedName="" attribute on your session beans' annotion to give each a unique JNDI name. You'll have to use an equivalent mappedName attribute in your client to make sure you are using the bean that you intent.

Categories