Spring to use fully qualified names for constructor dependency injection - java

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

Related

Generic way to handle DuplicateBeanException

Team, I am working on an Spring boot application which uses lot of other third party libraries.
All those libraries are built on top of spring core.
The common issue that usually comes is DuplicateBeanException.
Let's say if the bean-name is same from different libraries, spring throws error while trying to start the server. As I do not have control over third party jars. I have to rename the beans in my application: below is the code snippet I wrote to handle this scenario. But this is not an efficient solution as in future there can be again some duplicate beans. How can I solve it in a generic way so that when ever any duplicate beans come, my application can handle and initialize those beans.
My code to handle duplicate bean :
#Configuration
public class ExternalBeanConfiguration {
#Bean(employeeLib1)
public Employee getEmployee() {
return new Employee();
}
#Bean(employeeLib2)
public com.another.library.Employee getEmployee() {
return new com.another.library.Employee();
}
}
When you configure where to scan the beans from the external libraries by #ComponentScan , you can specify a BeanNameGenerator for how the name of the detected beans are defined.
#Configuration
#ComponentScan(basePackages = { "com.foo.lib1" , "com.foo.lib2"}, nameGenerator = FullyQualifiedAnnotationBeanNameGenerator.class)
public class ExternalBeanConfiguration {
}
The FullyQualifiedAnnotationBeanNameGenerator is exactly for solving your problem which is mentioned in the javadoc as :
Favor this bean naming strategy over {#code
AnnotationBeanNameGenerator} if you run into naming conflicts due to
multiple autodetected components having the same non-qualified class
name (i.e., classes with identical names but residing in different
packages)
It will name the bean as the fully qualified class name as the default bean name such that even if different packages has a same class name , it will still have different bean name.

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)?

Get class from any Dependency injection container

I have 2 projects. The first uses Spring 4 and the second uses jBoss 7.
I'm creating a dependency that given a Class name (like "com.foo.Bar") will get the instance from the injection context.
The classes will implement an interface (TransitionRule), so my method would be like:
public TransitionRule getRule(String className) {
//... Magic goes here!
//get the instance of "className" from any container that the imported project is using.
}
Can i do that with only one implementation or i will to create a different implementation to get from Spring and from Jboss context?
You can do a bean lookup by name or type in Spring if you have access to the relevant Spring Context.
You can perform a JNDI lookup in a running JBoss container if the object has been registered in JNDI, for example, an EJB is generally registered in JNDI for you.
Both of these methods follow the Lookup or Service-Locator pattern. These are NOT injections.

Websphere - bean produced by producer from other maven module stopped to be seen

I'm developing under IBM RAD 9 the application for WebSphere 8.5, using EJB 3 :(
I've split the project to following maven modules:
dto (only 'stupid' transfer objects)
ejb (the business logic)
web (the REST channels, build type is WAR)
ear (well, build type is EAR)
EJB module has empty beans.xml file in META-INF. There's a producer class there, that produces some my.ejb.HelperClass
#ApplicationScoped
public class MyHelperProducer {
#Produces
#ApplicationScoped
public HelperClass produceGenWsClient() {
....
}
}
The usage is quite trivial:
#Inject
private HelperClass helper;
It was already functioning! After some changes in the code (involving refactoring of many fields in many classes, but not those involved!) Everything stopped to function. Now I get error messages like that:
[8/27/14 16:33:38:960 CEST] 00000063 BeansDeployer E BeansDeployer
deploy
javax.enterprise.inject.UnsatisfiedResolutionException: Api type
[my.ejb.HelperClass] is not found with the qualifiers Qualifiers:
[#javax.enterprise.inject.Default()] for injection into Field
Injection Point, field : private my.ejb.HelperClass
my.web.MyChannel.helper, Bean Owner : [WSEjbBean
[businessLocals=[my.web.MyChannel],
ejbName=MyChannel1710565165,Name:null,WebBeans Type:ENTERPRISE,API
Types:[java.lang.Object,my.web.MyChannel],Qualifiers:[javax.enterprise.inject.Any,javax.enterprise.inject.Default]]
InjectionType : [class my.ejb.HelperClass] Annotated :
[Annotated Field,Base Type : class my.ejb.HelperClass,Type Closures :
[class my.ejb.HelperClass, class java.lang.Object],Annotations :
[#javax.inject.Inject()],Java Member Name : helper] Qualifiers :
[[#javax.enterprise.inject.Default()]] at
org.apache.webbeans.util.InjectionExceptionUtils.throwUnsatisfiedResolutionException(InjectionExceptionUtils.java:92)
at
org.apache.webbeans.container.ResolutionUtil.checkResolvedBeans(ResolutionUtil.java:96)
at
org.apache.webbeans.container.InjectionResolver.checkInjectionPoints(InjectionResolver.java:189)
at
org.apache.webbeans.container.BeanManagerImpl.validate(BeanManagerImpl.java:1092)
at
org.apache.webbeans.config.BeansDeployer.validate(BeansDeployer.java:394)
at
org.apache.webbeans.config.BeansDeployer.validateInjectionPoints(BeansDeployer.java:332)
at
org.apache.webbeans.config.BeansDeployer.deploy(BeansDeployer.java:183)
at
org.apache.webbeans.lifecycle.AbstractLifeCycle.startApplication(AbstractLifeCycle.java:124)
at
org.apache.webbeans.web.lifecycle.WebContainerLifecycle.startApplication(WebContainerLifecycle.java:78)
at
com.ibm.ws.webbeans.common.CommonLifeCycle.startApplication(CommonLifeCycle.java:106)
The 'funny' thing there is, I've already got such errors in other application, but then I've solved them by starting server clean and deleting and reimporting the project to the workspace. Now, however, even that didn't work.
What is actually a problem here? Is there a big bug in the RAD? Or I'm doing something wrong, that was only incidentally working before? How can I diagnose such errors?
Check this link Troubleshooting contexts and dependency injection. Maybe it will help you. Quoting:
Resolve an unsatisfiable dependency.
An unsatisfiable dependency, or
javax.enterprise.inject.UnsatisfiedResolutionException, occurs when
there is no corresponding source for objects matching an injection
point in the application. The API type of the field, along with the
optional set of qualifier annotations, dictates the set of beans that
are valid to satisfy the dependency. Causes of unsatisfiable
dependency are as follows:
There is no managed bean that is assignable to the type on the
injection point.
There is no producer method of any managed bean whose return type is assignable to the injection point.
There is no producer field in any managed bean whose type is assignable to the injection point.
One of the previously mentioned scenarios are valid, but the Qualifier annotations on the injection point are not present on the
bean or producer.
Resolve the error by making a dependency with the API type and
qualifiers available by introducing a new bean, removing qualifiers,
or adding producers fields or methods
Maybe you are missing some classpath dependencies, if bean is created in one module and used in other?

How can I mix Guice and Jersey injection?

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.

Categories