Dependency Injection to generics spring - spring

Is it possible to Inject generic in spring boot like below?
public interface A <T> extends ElasticsearchRepository<T, Long> {
}
public class B {
#Autowired
private A<Object> a;
}
following code give this error
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'genericElasticRepository': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Unable to obtain mapping metadata for class java.lang.Object!
is there any alternatives to generic? I dont want to write for interfaces for all type of T
thanks in advance
updated
There was not any problem with generics in my code I guess it is rather repositories has something to do with concrete class. JpaRepository or ElasticsearchRepository does not allow to pass generic they need concrete type I dont know why

With Spring 4.0 you can use generics it will automatically consider generics as a form of #Qualifier.
Reference - https://spring.io/blog/2013/12/03/spring-framework-4-0-and-java-generics

Related

MapStruct using interface with Spring Boot causes NoSuchBeanDefinitionException

I have implemnted an interface for using MapStruct:
#Mapper(componentModel = "spring")
public interface MapStructMapper {
MapStructMapper INSTANCE = Mappers.getMapper( MapStructMapper.class );
MyApiModel myInternalClassToMyApiModel(MyDocument.MyInternalClass myInternalClass);
MyDocument.MyInternalClass myApiModelToMyInternalClass(MyApiModel myApiModel);
}
When running the gradle build I get the following exception when tests are executed:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'MapStructMapper' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
In my test class I currently have only:
#Autowired
protected MapStructMapper mapper;
and in my build.gradle
implementation 'org.mapstruct:mapstruct:1.4.2.Final'
annotationProcessor 'org.mapstruct:mapstruct-processor:1.4.2.Final'
How can I solve this problem and how can I invoke the mapping if I use MapStruct using an interface?
Based on the information you provided, it's hard to give a definitive answer.
Please check that you not only included the mapstruct dependencies but also the annotation processor in your build such that the MapStructMapperImpl is actually generated.
If it is indeed generated, you must make sure that it is included in the application context of your test. If you use #SpringBootTest, you need to make sure that the interface is declared in a package that is scanned by the component scan. If you construct a dedicated context with #ContextConfiguration, you need to list MapStructMapperImpl.class in the list that you pass to the parameter classes like you would with other classes annotated with #Component.

Can impl bean in spring have more public methods than Interface?

if there is an interface in spring with 1 abstract public method and an implementation of this interface with 2 public methods (1 is overide and second public method is extra). If we autowire the interface we are not able to use the second public method in impl. Is this a correct behavior? In maven build it does say its using and autowiring IMPL bean but not able to find the second extra public method.
It's more of a Java question rather than a Spring one. There are a few things going on here:
Yes, an implementation can have more methods than the interface it's implementing.
Since you cannot initialize an interface, as in Spring case, it can only autowire an implementation of the interface to your bean.
Let's look at the following example:
You have an interface SomeInterface with methods methodA, and it's implementation SomeInterfaceImpl with methodA and methodB.
If you autowire a bean by its interface:
#Autowired private SomeInterface someInterface;
then you can only access methodA (without explicitly casting it to SomeInterfaceImpl, obviously), although what you have autowired is SomeInterfaceImpl and has methodB implemented.
If you autowire its impltementation:
#Autowired private SomeInterfaceImpl someInterface;
then you'll be able to access both methodA and methodB. HTH.

What are possible causes for Spring #ComponentScan being unable to auto create a class anotated by #Repository

I came across a tutorial which seemed to be fitting my usecase and tried implementing it. I failed but wasn't sure why. So I tried to find another example with similar code and looked at the book "Spring in Action, Fourth Edition by Craig Walls"
The books describes at page 300 the same basic approach. Define a JdbcTemplate Bean first.
#Bean
NamedParameterJdbcTemplate jdbcTemplate(DataSource dataSource) {
return new NamedParameterJdbcTemplate(dataSource);
}
Then a Repository implementing an Interface
#Repository
public class CustomRepositoryImpl implements CustomRepository {
private final NamedParameterJdbcOperations jdbcOperations;
private static final String TEST_STRING = "";
#Autowired
public CustomRepositoryImpl(NamedParameterJdbcOperations jdbcOperations) {
this.jdbcOperations = jdbcOperations;
}
So I did like the example in the book suggests, wrote a test but got the error message
Error creating bean with name 'de.myproject.config.SpringJPAPerformanceConfigTest': Unsatisfied dependency expressed through field 'abc'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'de.myproject.CustomRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
To my understanding as book and tutorial describe, the Repository should be recognized as a Bean definition by the component scan.
To test this I created an context and asked for all registered Beans.
AnnotationConfigApplicationContext
context = new AnnotationConfigApplicationContext();
context.getBeanDefinitionNames()
As assumed my Repository wasn't among them. So I increased, for test purposes only, scope of the search in my project, and set it to the base package. Every other Bean was shown, except the Repository.
As an alternative to component scanning and autowiring, the books describes the possibility to simply declare the Repository as a Bean, which I did.
#Bean
public CustomRepository(NamedParameterJdbcOperations jdbcOperations) {
return new CustomRepositoryImpl(jdbcOperations);
}
After that Spring was able to wire the Repository. I looked at the github code of the book in hope for a better understanding, but unfortunately only the Bean solution, which runs, is implemented there.
So here are my questions:
1.) what possible reasons are there for a Bean definition, is a scenario like this one, not to be recognized by the component scan?
2.) this project already uses Spring JPA Data Repositories, are there any reasons not to use both approaches at the same time?
The problem is naming of your classes. There are many things to understand here.
You define a repository Interface #Repository is optional provided it extends CRUDRepository or one of the repositories provided by spring-data. In this class you can declare methods(find By....). And spring-data will formulate the query based on the underlying database. You can also specify your query using #Query.
Suppose you have a method which involves complex query or something which spring-data cannot do out of the box, in such case we can use the underlying template class for example JdbcTemplate or MongoTemplate..
The procedure to do this is to create another interface and a Impl class. The naming of this interface should be exactly like Custom and your Impl class should be named Impl.. And all should be in same package.
For example if your Repository name is AbcRepository then Your custom repository should be named AbcRepositoryCustom and the implementation should be named AbcRepositoryImpl.. AbcRepository extends AbcRepositoryCustom(and also other spring-data Repositories). And AbcRepositoryImpl implements AbcRepositoryCustom
I was able to "solve" the problem myself.
As we also have a front end class annotated with the same basePackage for the #ComponentScan
#EnableWebMvc
#Configuration
#ComponentScan(basePackages = {"de.myproject.*"})
so there were actually two identical #ComponentScans annotations which I wasn't aware off and this did lead to a conflict. It seams the ordering how the whole application had to be loaded had changed, but thats only me guessing.
I simply moved my Repository and its Impl to a subpackage, and changed the
#ComponentScan(basePackages = {"de.myproject.subpackage.*"})
and now everything works fine. Though it escapes me, what the exact reason behind this behavior is.

Spring No unique bean of type

i have a little trouble in Spring with two component of a service.
I have this component:
#Component
public class SmartCardWrapper
and this one:
#Component
public class DummySmartCardWrapper extends SmartCardWrapper
The service autowire both but spring fails due this expection:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [com.cinebot.smartcard.SmartCardWrapper] is defined: expected single matching bean but found 2: [dummySmartCardWrapper, smartCardWrapper]
Why it doesn't use class names?
That's one of the most basic concepts of Spring - Inversion of Control.
You don't need to declare your dependencies using their implementation types (to avoid coupling with implementation). You can declare them using interfaces or superclasses instead, and make Spring find the proper implementation class in the context.
In other words, bean are not distinguished by their implementation classes, because you may want to change implementation class of a bean without changing the beans that depend on it. If you want to distinguish between different beans of the same type, use logical bean names instead:
#Autowired #Qualifier("smartCardWrapper")
private SmartCardWrapper smardCardWrapper;
#Autowired #Qualifier("dummySmartCardWrapper")
private SmartCardWrapper dummySmardCardWrapper;

Spring #Qualifier not working when bean is in another jar file

I have a number of Spring beans, some of which are in a shared library jar. I can't seem to get #Qualifier to work.
I have default-autowire set to "byType", this is using Spring 3.1.0.M2 and running as a standalone executable. If I remove "TestTwoBean" from the shared library the project executes as expected.
myproj-shared-lib.jar:
#Service
public class TestOneBean implements ITestBean {
}
#Service
public class TestTwoBean implements ITestBean {
}
myproj.jar:
#Service
public class TestConsumerBean {
#Autowired #Qualifier("testOneBean")
private ITestBean bean;
}
I get the "no unique bean with name" exception at runtime:
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'testConsumerBean' defined in file [-]:
Unsatisfied dependency expressed through bean property 'bean': : No
unique bean of type [com.myco.ITestBean] is defined: expected single
matching bean but found 2: [testOneBean, testTwoBean]; nested
exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
unique bean of type [com.myco.TestBean] is defined: expected single
matching bean but found 2: [testOneBean, testTwoBean] at
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireByType(AbstractAutowireCapableBeanFactory.java:1167)
...
Does #Qualifier not work in this situation? Is there a known workaround?
Are you sure you want to use autowire by type AND annotation injection? Autowire by type means spring will attempt to inject detected setters and constructor parameters using by type lookup even if they aren't annotated for injection.
At the same time you are trying to inject fields by name. Your #Service annotated classes produce beans with names defaulting to the class name, "testOneBean" and "testTwoBean" respectively. #Qualifier uses bean names as correct matches. The recommended way of doing "by name" injection though is by using #Resource(name="testOneBean"). I can only guess spring tries injection by type due to autowire mode set to by type (which I doubt you really need).
I would recommend reverting to default autowire mode and using #Resource for wiring by name.

Resources