Inject constructor parameter by custom annotation in spring? - spring

In spring, injecting custom non-autowirable value to fields/setter can be processed by BeanPostProcessor, like:
class Foo
{
#MyAnnotation
SomeService sth;
}
But, in constructor parameter, seems no any extension for customizing injection, only #Value or #Qualifier accepted, which is implemented by spring framework core.
class Foo
{
Foo(
#Value("sth") String sth, // OK
#Qualifier("foo") Foo foo, // OK
#MyAnnotation SomeService sth // Bad!
) { ... }
}
Is there any way to achieve this goal?

Related

Spring custom annotation for bean injection

I am looking to inject a bean by means of a custom annotation
#Service
class Foo(#MyBean val bar: Bar) { fun someMethod() { bar.invoke() } }
with
#Retention(AnnotationRetention.RUNTIME)
#Target(AnnotationTarget.PROPERTY, AnnotationTarget.VALUE_PARAMETER)
annotation class MyBean
Currently we have a configuration class that defines multiple bean methods
#Configuration
class config {
#Bean
fun bar(): Bar = { getBaz() }
}
I have seen implementations of BeanPostProcessor but that seems to add behaviour to already existing beans. My question is, is there a way to initialise and assign beans to a field by means of a custom annotation.
Since you're injecting the field through a constructor, you don't need to annotate the field itself, but rather the constructor.

Spring Configuration - Inject Mock Beans

I am using Spring, Junit and Mockito. I need to override beans defined in the main spring configuration using another mockito test configuration (injecting mock beans only as needed). Nested beans have been #Autowired in the application.
Update:
Based on alfcope's answer below, it is important to add the name attribute so that spring can allow the primary bean (mock) to override the original one. Otherwise you get this exception:
org.mockito.exceptions.misusing.MissingMethodInvocationException:
when() requires an argument which has to be 'a method call on a mock'.
For example:
when(mock.getArticles()).thenReturn(articles);
The info message in the spring log shows:
Skipping bean definition for [BeanMethod:name=bar,declaringClass=test.package.MockitoTestConfiguration]: a definition for bean 'bar' already exists. This top-level bean definition is considered as an override.
Example:
I have a simplified example below that works. Here, Bar is the nested inside Foo, and I need to mock Bar for testing:
#Component
public class Foo
{
#Autowired
private Bar bar;
public String getResponseFromBar(String request)
{
String response = bar.someMethod(String request);
//do something else with this reponse
return response;
}
}
#Component
public class Bar {
public String someMethod(String request) {
String response = null;
//do something
return response;
}
}
Now for testing, let's say I want to inject a mockbar instead of the real bar. How can I achieve this in my test class below?
#Profile("test")
#Configuration
public class MockitoTestConfiguration {
//adding the name attribute is important.
#Bean(name="mockBar")
#Primary
public Bar bar() {
logger.debug("injecting mock bar");
return Mockito.mock(Bar.class);
}
}
Actual test case:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = "classpath*:test-context.xml")
public class FooTest {
#Autowired
Foo foo;
#Autowired
Bar mockBar; //need this to set up the mock response in the test case.
#Test
public void testAMethodInFoo_WithBarInjectedByMockito() {
//set up the mockBar response
Mockito.when(mockBar.someMethod("1")).thenReturn("1-response");
String response = foo.getResponseFromBar();
assertEquals("1-response", response);
}
}
Based on the ConfigurationClassBeanDefinitionReader code I guess you are using xml configuration to define your main bean. If so, just add a name when creating your mockito bean.
#Bean(name="mockbar")
#Primary
public Bar bar() {
logger.debug("injecting mock bar");
return Mockito.mock(Bar.class);
}
This way Spring will allow you to have both beans, and as you are using #Primary it will be the one used by your tests.
Spring overriding primary bean with non-primary bean
ConfigurationClassBeanDefinitionReader Code
Alternatively, if you use Mockito, you can do this and completely do away with the extra MockitoTestConfiguration class and named primary mock beans in the test profile. Just simply do this:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = "classpath*:test-context.xml")
public class FooTest {
#Autowired
#InjectMocks
Foo foo;
#Mock
Bar mockBar; //need this to set up the mock response in the test case.
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
#Test
public void testAMethodInFoo_WithBarInjectedByMockito() {
//set up the mockBar response
Mockito.when(mockBar.someMethod("1")).thenReturn("1-response");
String response = foo.getResponseFromBar();
assertEquals("1-response", response);
}
}

How can I access Spring beans in no-arg constructor?

#Component
public class MyClass {
public MyClass() {
SomeInterface something;
// Spring magic that i don't know
something.toString();
}
}
What Spring magic do I need to use to inject a bean into "something"?
I also wouldn't mind if it was a field. It just has to be usable from within the constructor!
The basic rules also apply to Spring:
to construct an object, Spring needs to invoke the constructor
Spring can't call a method of an object or set one of its fields if it isn't constructed yet
so if you want to access a field set by Spring , you can't do that from the constructor, unless the value is passed as argument to the constructor.
This thus leaves two choices:
constructor injection:
#Autowired
public MyClass(SomeInterface something) {
// use something
}
post-construct method, called after all the injections have been done, whatever the way:
#Autowired
private SomeInterface something;
#PostConstruct
private void initialize() {
// use something
}

When autowiring use would be beneficiary with example

I have recently learned concept of autowiring in spring. When I was trying to understand in which particular scenarios spring autowiring can be useful
I came up with the below two reasons from one of the questions asked in our stakoverflow forum.
1.I wanted to read values from a property file and inject them into a bean. Only way I could figure out how to do this at start up of my app was to
wire the bean in XML (and inject the properties.) I ended up using the "byName" attribute (because the bean was also marked as #Component) and then
used #Autowired #Qualifier("nameIChose") when injecting the bean into another class. It's the only bean I've written that I wire with XML.
2.I've found autowiring useful in cases where I've had a factory bean making another bean (whose implementation class name was described in a system
property,so I couldn't define the all wiring in XML). I usually prefer to make my wiring explicit though;
Can any body please give me some code snippet example of the above situations that would make my understanding of autowiring more clearer?
Here is an example of injecting properties into a bean.
Using field injection:
#Component
public class YourBean {
#Value("${your.property.name}")
private String yourProperty;
}
Using constructor injection:
#Component
public class YourBean2 {
private String yourProperty;
#Autowired
public YourBeans2(#Value("${your.property.name}") String yourProperty) {
this.yourProperty = yourProperty;
}
}
The following is a super simple example of autowiring various beans
#Component
public class Foo {
public void doSomething() {
}
}
#Component
public class Bar {
private Foo foo;
#Autowired
public Bar(Foo foo) {
this.foo = foo;
}
public void doSomethingElse() {
foo.doSomething();
}
}
In the previous example, no XML configuration of Foo and Bar needs to be done, Spring automatically picks up the beans because of their #Component annotation (assuming of course that component scanning has been enabled)

Dependency Injection with Grails Spring DSL

When I use the Spring DSL provided by Grails is it possible to do constructor injection. If so, an example would be much appreciated.
If constructor injection is not possible, is there some other way that I can inject a spring bean without making the dependencies public properties. Using Spring in a Java project I can do this
class Foo {
#Autowired
private Bar bar
}
And it will autowire the Bar dependency either by name or type
it is possible to use constructor injection even using the BeanBuilder DSL
bb.beans {
exampleBean(MyExampleBean, "firstArgument", 2) {
someProperty = [1,2,3]
}
}
whenever you want to reference other beans as constructor arguments, use the ref() method
bb.beans {
exampleBean(MyExampleBean, "firstArgument", ref('anotherBean')) {
someProperty = [1,2,3]
}
}
You should be able to inject a bean into the constructor using the #Autowired annotation like you'd usually do in Spring. Here's an example:
class Foo {
private final Bar bar
#Autowired
public Foo(Bar bar) {
this.bar = bar
}
}

Resources