How to use constructors to the #repository in Spring? - java

I want to construct the #repository with some parameters:
#Repository
public class BasicRepository<T> {
#Autowired
MongoTemplate mongoTemplate;
private final Class typeParameterClass;
public BasicRepository(Class typeParameterClass){
this.typeParameterClass = typeParameterClass;
}
public void createCollection(T t) {
if (!mongoTemplate.collectionExists(typeParameterClass)) {
mongoTemplate.createCollection(typeParameterClass);
}
}
}
In java configuration:
#Configuration
public class SpringConfiguration {
#Bean
public BasicRepository<Topic> topicDao(){
return new BasicRepository<Topic>(Topic.class);
}
}
When I run the code ,it throws the exception about “Error creating bean with name 'basicRepository'” ,I think the annotation of "#Repository" doesnt have the constructors,I want to initialize the "typeParameterClass",Someone can explain how?

So what appears to be happening is that the component-scan is finding your #Repository class and is trying to create a bean out of it, which it can't as it will not know how to instantiate your class with the typeParameterClass parameter.
The fix could be a few of them:
Probably not a good approach may be to go ahead and remove the
#Repository annotation as you are anyway generating the bean
through #Bean annotation. The reason this is not a good option is
because #Repository annotated beans behavior is modified at runtime
. For eg, persistence exception translation to spring runtime types.
One more option could be to retain #Repository annotation but
prevent component scanning for this specific class or specific
package.

Related

Nested auto wiring with generics in Spring

My understanding is that from spring 4 and onward, a generic type can serve as a valid qualifier. This works just fine in the following (basic) example:
public interface TypeResolver<T>{
Class<T> type();
}
#Configuration
public TypeResolversConfig{
#Bean
public TypeResolver<Integer> integerTypeResolver(){
return () -> Integer.class
}
#Bean
public TypeResolver<String> stringTypeResolver(){
return () -> String.class
}
}
#Service
public class SomeService{
#Autowired
private TypeResolver<Integer> integerTypeResolver;
}
However if I add another bean as such:
#Service
public class SomeOtherService<T>{
#Autowired
private TypeResolver<T> tTypeResolver;
}
And then proceed to edit SomeService as follows:
#Service
public class SomeService{
#Autowired
private SomeOtherService<Integer> someOtherService;
}
I get a
Field tTypeResolver in com.example.demo.SomeOtherService required a single bean, but 2 were found
exception. Is there any way around this, or is this just an inherent limitation whereby spring can only get around type erasure to a limited extent? I am using spring boot 2.1.8.RELEASE.
Generics are not present during compile time,so Autowiring generic type is meaning less.
So you can achieve this one by like this
#Service
public class SomeService{
#Autowired
private TypeResolver<Integer> integerTypeResolver;
#Autowired
private TypeResolver<String> stringTypeResolver;
...
}
NO need of SomeOtherService.

How to use spring #autowired annotation in the class having void methods?

I have an interface and service implements it. It has some void methods.
I am using spring java bean configuration. But unable to create bean object because of void methods.How to handle this problem.
I tried to use #PostConstruct instead of #Bean after reading some blogs, but it didn't work out.
public interface MyInterface {
void someData(List<MyClass> list, String somedata);
}
#Service("myInterface")
public DummyClass implements MyInterface {
public void someData(List<MyClass> list, String somedata){
// my business logic
}
}
public AppConfig {
#Bean
public MyInterface myInterface {
return new DummyClass(); // but gives error void cannot return value
}
}
My Junit looks like this
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(
classes = {AppConfig.class},
loader = AnnotationConfigContextLoader.class
)
public class MyTest {
#Autowired
DummyClass dummyClass;
// If I don't use AppConfig and simply autowire then I get
"Error creating bean name, unsatisfied dependency
}
How do I achieve dependency injection here?
Use #Configuration annotation on AppConfig class, with this all the beans defined on this class will be loaded on spring context.
If you use #Service annotation on DummyClass, you do not need to declare #Bean annotation because you are already saying to spring to detect this class for dependency injection. On the other hand use #Bean annotation to specify the instantiation of the class. Normally I let the #Bean to complex classes for dependency injection or to override configurations.

BeanNotOfRequiredTypeException: Bean named X is expected to be of type X but was actually of type 'com.sun.proxy.$Proxy

I have such classes and Spring context.
How to fix this wrong Java configuration, not xml?
I'd tried some solutions from other posts, but without success.
#Service
#Transactional
public class XCalculationService implements VoidService<X> {
}
public interface VoidService<Input> {
}
#AllArgsConstructor
public class XService {
private XCalculationService calculationService;
}
#Configuration
public class ServiceConfiguration {
#Bean
public OrderService orderService(XCalculationService calculationService) {
return new XService(calculationService);
}
#Bean
public XCalculationService calculationService() {
return new XCalculationService ();
}
}
Error
BeanNotOfRequiredTypeException: Bean named 'calculationService' is expected to be of type 'com.x.XCalculationService' but was actually of type 'com.sun.proxy.$Proxy
Here is 100% fix:
#EnableTransactionManagement(proxyTargetClass = true)
Java proxies are working on interfaces, not concrete classes.
Reasoning with spring documentation: https://docs.spring.io/spring-framework/docs/3.0.0.M3/reference/html/ch08s06.html
If the target object to be proxied implements at least one interface then a JDK dynamic proxy will be used.
Therefore, when using aspect/proxy based annotations as #Transactional, Spring will attempt to proxify the concrete class and resulting object will be instance of VoidService interface not XCalculationService.
Therefore you can solve it two ways:
use #Arthur solution and turn off Java's interface proxy in favor of CGLib for transaction support
#EnableTransactionManagement(proxyTargetClass = true)
Instead of using XCalculationService type in injectable fields, use only its proxied interface aka VoidService.
I suppose you have got #ComponentScan somewhere activated and it scans your #Service annotated XCalculationService class.
So you should either remove #Service from XCalculationService
or remove
#Bean
public XCalculationService calculationService() {
return new XCalculationService ();
}
from ServiceConfiguration

Spring annotations confusion

i am really confused with spring annotations.
where to use # Autowired, where class is # Bean or # Component,
i understand we cannot use
Example example=new Example("String");
in Spring
but how alone
#Autowired
Example example;
will solve the purpose?
what about Example Constructor ,how spring will provide String value to Example Constructor?
i went through one of the article but it does not make much sense to me.
it would be great if some one can give me just brief and simple explanation.
Spring doesn't say you can't do Example example = new Example("String"); That is still perfectly legal if Example does not need to be a singleton bean. Where #Autowired and #Bean come into play is when you want to instantiate a class as a singleton. In Spring, any bean you annotate with #Service, #Component or #Repository would get automatically registered as a singleton bean as long as your component scanning is setup correctly. The option of using #Bean allows you to define these singletons without annotating the classes explicitly. Instead you would create a class, annotate it with #Configuration and within that class, define one or more #Bean definitions.
So instead of
#Component
public class MyService {
public MyService() {}
}
You could have
public class MyService {
public MyService() {}
}
#Configuration
public class Application {
#Bean
public MyService myService() {
return new MyService();
}
#Autowired
#Bean
public MyOtherService myOtherService(MyService myService) {
return new MyOtherService();
}
}
The trade-off is having your beans defined in one place vs annotating individual classes. I typically use both depending on what I need.
You will first define a bean of type example:
<beans>
<bean name="example" class="Example">
<constructor-arg value="String">
</bean>
</beans>
or in Java code as:
#Bean
public Example example() {
return new Example("String");
}
Now when you use #Autowired the spring container will inject the bean created above into the parent bean.
Default constructor + #Component - Annotation is enough to get #Autowired work:
#Component
public class Example {
public Example(){
this.str = "string";
}
}
You should never instantiate a concrete implementation via #Bean declaration. Always do something like this:
public interface MyApiInterface{
void doSomeOperation();
}
#Component
public class MyApiV1 implements MyApiInterface {
public void doSomeOperation() {...}
}
And now you can use it in your code:
#Autowired
private MyApiInterface _api; // spring will AUTOmaticaly find the implementation

How do I express a dependency on a bean defined in an imported configuration in Spring?

I recently started working at a place that uses Java configuration for Spring as opposed to XML and so far I'm loving it.
My question is the following:
If we have a #Configuration annotated class A that imports another #Configuration annotated class B, what is the proper, type-safe way for a bean defined in A to depend on a bean defined in B.
Here's an example I saw in a blog (https://blog.codecentric.de/en/2012/07/spring-dependency-injection-styles-why-i-love-java-based-configuration/):
#Configuration
public class PartnerConfig {
#Bean
public PartnerService partnerService() {
return new PartnerServiceImpl();
}
}
#Configuration
#Import(PartnerConfig.class)
public class CashingConfig {
#Autowired
private PartnerConfig partnerConfig;
#Bean
public CashingService cashingService() {
return new CashingServiceImpl(partnerConfig.partnerService());
}
}
As a second part to my question, if I was to do the above, would Spring interpret as a bean dependency? That is, when I do
partnerConfig.partnerService()
in the example above, am I getting Spring to fetch me the partnerService bean, or am I just calling a regular java method and creating a new instance of the PartherService (which is NOT what I want, since the bean should be a singleton) ?
EDIT:
It has been suggested to use a #Qualifier. Would this work?
#Configuration
public class PartnerConfig {
#Bean
#MyCustomQualifier
public PartnerService partnerService() {
return new PartnerServiceImpl();
}
}
#Configuration
#Import(PartnerConfig.class)
public class CashingConfig {
#Bean
public CashingService cashingService(#MyCustomQualifier PartnerService partnerService) {
return new CashingServiceImpl(partnerService);
}
}
I recommend giving the docs a read: http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/annotation/Bean.html
Refer to the section:
#Bean Methods in #Configuration Classes
This sums it up very well.
Typically, #Bean methods are declared within #Configuration classes. In this case, bean methods may reference other #Bean methods in the same class by calling them directly. This ensures that references between beans are strongly typed and navigable.
Also take a look at: http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Configuration.html
Section:
Composing #Configuration classes
Just add the dependency as an argument to the #Bean annotated method and remove the autowiring of the configuration.
#Configuration
#Import(PartnerConfig.class)
public class CashingConfig {
#Bean
public CashingService cashingService(PartnerService partnerService) {
return new CashingServiceImpl(partnerService);
}
}
or simply autowire the PartnerService instead of the configuration.
#Configuration
#Import(PartnerConfig.class)
public class CashingConfig {
#Autowire
private PartnerService partnerService;
#Bean
public CashingService cashingService() {
return new CashingServiceImpl(partnerService);
}
}

Categories