How to insert property in Autodetected Component in Spring? - java

I am using #Service annotation of spring, so that my class should be autodetected by spring and made available for autowiring.But in my class, I need a property 'sqlmap'.If I had been using way of creating beans instead of auto-detection, I would have supplied that property using property tag in that bean..
So, is there any way I can inject my property in my class?Because unless that property is made available, spring will not be able to create bean of that class.

Your #Service class can "pull" a bean into a property using #Resource, e.g.
#Service
public class MyService {
#Resource (name="sqlMapClient")
private SqlMapClient sqlMapClient;
}
An alternative to #Resource is #Autowired, which will automatically select the target by type:
#Service
public class MyService {
#Autowired
private SqlMapClient sqlMapClient;
}
Try both, see which works best for you.

Related

Spring: Using #Qualifier & #Profile

I have a component class (let's class in MyService) which is marked by #Qualifier(US).
As this component needed some values present in an application.yml file, I also marked the class with #Profile({"default", "qual"}) to get the correct values for some inner properties of the class.
Problem, when I execute cucumber tests for this specific qualifier (US), the program throws the following error An unexpected internal server error occurred: No bean named 'US' available: No matching MyService bean found for qualifier 'US' - neither qualifier match nor bean name match!
So, what I understand with this, it's the annotations #Qualifier & #Profile don't work together. Is that right? Or do I miss something to use both of them in the same class?
#Qualifer
This annotation may be used on a field or parameter as a qualifier for
candidate beans when autowiring.
#Profile
Indicates that a component is eligible for registration when one or
more specified profiles are active.
The class with following set of annotations
#Service
#Qualifier("US")
#Profile({"default", "qual"})
public class MyService {
...}
will only register the MyService bean when "default" or "qual" profiles are active and then on the bean can be autowired with the qualifier "US"
#Autowired
#Qualifer("US")
private MyService myService;
#Value can be used to inject the properties
#Value(${some.name})
private String name;

Alias definition in Spring Java configuration

My project depends on a dependency.jar artifact. The dependency contains a Spring service:
#Service
public class Service { }
In my project I inherit from the service and override some functionality:
#Service
public class MyService extends Service {
// overriding
}
In Spring XML configuration I define alias to use MyService over Service everywhere:
<alias name="myService" alias="service" />
How to do alias definition in Spring Java configuration? Currently I do it this way, but it is not very elegant:
#Bean(name = "service")
public Service service(#Qualifier("myService") Service projectImplementation) {
return projectImplementation;
}
Is there a better way how to do it in Spring Java configuration? Thank you!
You can provide several aliases while declaring a bean:
#Bean({"myService", "service"})
According to the name attribute documentation:
The name of this bean, or if several names, a primary bean name plus aliases.
If left unspecified, the name of the bean is the name of the annotated method. If specified, the method name is ignored.
The bean name and aliases may also be configured via the value attribute if no other attributes are declared.
You can use value attribute of #Service annotation & give your alias name there like -
#Service ("service")
public class MyService extends Service {
// overriding
}
And while autowiring or injecting use the alias given in value attribute like -
#Controller ("controller")
public class MyController
{
#Autowired
#Qualifier("service")
private MyService service;
}
This way you don't have to give alias name separately.

The bean could not be injected as a 'Type' because it is a JDK dynamic proxy that implements: reactor.fn.Consumer

My Spring 4 application, which uses Reactor 2, fails to start with:
***************************
APPLICATION FAILED TO START
***************************
Description:
The bean 'orderHandlerConsumer' could not be injected as a 'fm.data.repository.OrderHandlerConsumer' because it is a JDK dynamic proxy that implements:
reactor.fn.Consumer
Action:
Consider injecting the bean as one of its interfaces or forcing the use of CGLib-based proxies by setting proxyTargetClass=true on #EnableAsync and/or #EnableCaching.
The OrderHandlerConsumer is really simple:
#Service
#Order(Ordered.HIGHEST_PRECEDENCE)
public class OrderHandlerConsumer implements Consumer<Event<OrderEnvelope>> {
#Override
public void accept(Event<OrderEnvelope> event) {
event.getData().getLatch().countDown();
}
}
Any ideas what might be going awry?
In your application class file where you define it as Spring application, add underneath it.
#SpringBootApplication
#EnableCaching(proxyTargetClass = true)
While the accepted answer will solve this issue, I think it will be more appropriate for me to explain why appling proxyTargetClass = true will fix this.
First of all, Spring, as a framework, utilizes proxing in order to supply the bean with some extended functionality, such as declaritive transactions via #Transactional, or caching by the means of #Cacheable and e.t.c. There are, in general, 2 ways(*) Spring can create proxy on top of your bean:
Jdk dynamic proxing
CGLib proxing
Offical documentation on this, in case you are interested.
Spring can create jdk dynamic proxy of the bean (in case proxing is required for this bean of course) if original class of the bean implements at least one interface. So spring basically create another implementation of this interface at runtime with some additional logic on top of original class.
What is the problem: if the bean is proxied by the means of jdk dynamic proxing , then you cannot inject this bean via its original class. So something like this:
#SpringBootApplication
#EnableTransactionManagement(proxyTargetClass = false)
public class StackoverflowApplication {
#Autowired private SomeService service;
public static void main(String[] args) {
SpringApplication.run(StackoverflowApplication.class, args);
}
}
#Service
class SomeService implements SomeInterface {
#Override
#Transactional
public void handle() { }
}
interface SomeInterface {
void handle();
}
wont work. Why? Well, becuase #Transactional tells Spring that it needs to create proxy of SomeService at runtime, and within #EnableTransactionManagement I specifically asked Spring to make it by the means of jdk dynamic proxy - spring will succeed, since jdk dynamic proxy can be created, but the problem is at runtime there is not bean of type SomeService, there is only a bean of type SomeInterface (by the way, if you inject service here not by the class, but by the interface - it will work, I assume you understand the reason by reading explaination above).
Solution: by applying #EnableTransactionManagement(proxyTargetClass = true) (notice true value here) you force spring to create CGlib proxy (this rule is applicable only for beans that utilize declarative transaction management, i.e. via annotations). In case of CgLib proxing, Spring will try to extend the original class, and add additional functionality at runtime in the generated child class. And in this case injection by class will work - because the bean extends class SomeService, so
#Autowired
private SomeService someService;
will work perfectly fine. But, in general, if possible, inject bean by interface, not by class. In this case both Cglib and jdk dynamic proxy will work. So, be aware of proxing mechanisms spring can use. Hope it helped, have a nice day.
You can assign a bean name to your OrderHandlerConsumer class so that Autowire resolution will be easier, Moreover, Instead of Autowiring with the concrete class, try to auto-wire with the interface. So that you can change #Service annotation to,
#Service(value="orderHandlerConsumer")
and try to Autowire with the interface type,
#Autowire
reactor.fn.Consumer orderHandlerConsumer;
Please try autowiring as below
class Test{
#Autowired
private Consumer orderHandlerConsumer;
}
If the target object to be proxied implements at least one interface
then a JDK dynamic proxy will be used. All of the interfaces
implemented by the target type will be proxied. If the target object
does not implement any interfaces then a CGLIB proxy will be created.
https://docs.spring.io/spring-framework/docs/3.0.0.M3/reference/html/ch08s06.html
You can call it two ways.
1st way is without mentioning the proxy [with default proxy], you can Autowire it by the interface like below.
#Autowired
private Consumer orderHandlerConsumer;
Spring AOP will create an instance for OrderHandlerConsumer.
2nd way is, mention the proxy in the bean as ScopedProxyMode.TARGET_CLASS.
then you can Autowire an instance without the interface [based on the class].
#Service
#Order(Ordered.HIGHEST_PRECEDENCE)
#Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class OrderHandlerConsumer implements Consumer<Event<OrderEnvelope>> {
#Override
public void accept(Event<OrderEnvelope> event) {
event.getData().getLatch().countDown();
}
}
and Autowire by the class like below.
#Autowired
private OrderHandlerConsumer orderHandlerConsumer;

Spring How to autowire a component without using #Component or other derivatives

I would like to autowire a component (still using the #Autowired annotation), but not require it to have the #Component (or other similar annotations) on it. How would I do this?
public class A {
#Autowired
private class B b;
}
#Component
public class B {
}
This would be convenient in order to allow autowiring of class A without requiring the creation of A, unless we needed it (in otherwise on the fly by reflection using the class name).
Injection and autowiring do not require #Component. They require beans. #Component states that the annotated type should have a bean generated for it. You can define beans in other ways: with a <bean> declaration in an XML context configuration, with a #Bean method in a #Configuration class, etc.
Your last sentence doesn't make much sense. You can't process injection targets in a bean without creating a bean. You also can't inject a bean without creating it. (Applied to scopes, bean may refer to the target source/proxy and not the actual instance.) Perhaps you want #Lazy.
I don't sure, If I correctly understood to your question. But if you want inject bean B without marking bean A via some annotation, or xml definition, you can use SpringBeanAutowiringSupport
public class A {
#Autowired
private class B b;
public A{
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
}
}

Can #Autowire #Service beans but not members of a class instantiated with "new" keyword - even with context scanning configured

I have an app that's been working well with #Autowired #Service beans.
Now I'm adding a Validator class which is instantiated in the Controller:
BlueValidator validator = new BlueValidator(colors);
validator.validate(colorBlend, bindResult);
In the BlueValidator class I'm trying to #Autowire the blendService which is working as an #Autowired field elsewhere in the app:
public class BlueValidator implements Validator {
#Autowired
private BlendService blendService;
private Colors colors;
But for some reason after instantiating the BlueValidator, I keep getting NullPointerExceptions for the blendService.
Of course I've added the necessary context scanning:
<context:component-scan
base-package="com.myapp.controllers, com.myapp.services, com.myapp.validators" />
I also tried adding the#Autowired annotation to the constructor but that didn't help:
#Autowired
public BlueValidator(Colors colors) {
this.colors = colors;
}
Should I just pass the blendService to the BlueValidator and forget about the Autowiring or is there something obvious missing here?
If you just instantiate an object with new, Spring is not involved, so the autowiring won't kick in. Component scanning looks at classes and creates objects from them - it doesn't look at objects you create yourself.
This can be made to work, using Spring's AspectJ support, but it takes some effort.
Otherwise, you need to let Spring instantiate your objects if you wan autowiring to work.
Should I just pass the blendService to the BlueValidator and forget about the Autowiring
In your situation, I'd say yes, this is the least effort solution.
When you instantiate objects spring cannot do anything for them, so it does not get the dependencies injected (article).
In your case, you have a couple of options:
pass dependencies to the validator from the controller (where you can inject them)
make the validator a spring bean and inject it, instead of instantiating it
use #Configurable, which, via AspectJ, enables spring injection even in objects created with new
#Autowired is being used by Spring's ApplicationContext to populate those fields on creation. Since the ApplicationContext is not the one creating these beans (you are because of the keyword 'new'), they are not being autowired. You need to pass it in yourself if you are creating it.
Don't create validator manually -- allow to Spring do this work for you:
#Controller
class Controller {
#Autowired
BlueValidator validator;
void doSomething() {
...
validator.validate(colorBlend, bindResult);
...
}
}
Also pay attention that adding package com.myapp.validators to context:scan-packages not enough, you also should annotate your validator class with #Component annotation:
#Component
public class BlueValidator implements Validator {
#Autowired
private BlendService blendService;
(BTW this solution works in my project.)

Categories