annotation in spring boot #autowired - spring-boot

I have been coding basic java for a while and now experiencing to spring boot.
It is very often to see annotation in spring boot.
To me, annotation is to save time for developer to implement less code, by definition online. But this doesn't satisfy my question below
So far, I am experiencing #autowired. What confused me is that #autowired enable dependency injection and tell bean to configure xml (which i dont understand how useful it is yet)
For example,
class A {
private int id;
// With setter and getter method
}
class B {
private String name;
#Autowired
A a;
B(A a){this.a = a} ;
}
}
However, isnt it that, in basic java, it has been allowing to pass instance as argument without #autowired? Why does this suddenly become a benefit? or what am I missing?
class A {
private int id;
// With setter and getter method
}
class B {
private String name;
A a;
B(A a){this.a = a} ;
}
}

You get a benefit when you do this (although it is not recommended)
#Component
class A {
private int id;
// With setter and getter method
}
#Component
class B {
private String name;
#Autowired
A a;
B() {
}
}
now, assuming these classes live in the same or a sub-package of the #SpringBootApplication annotated class, will be auto-configured for you, and A will be injected into B using reflection by the Spring framework.
However, as I mentioned this is not recommended and you probably want to inject it through the constructor, since that makes your component easier to test (you can easily inject a mock in stead). Note that when you have a component/bean with a constructor that takes arguments #Autowired is inferred and spring will try to find the beans to inject into it for you.
#Component
class A {
private int id;
// With setter and getter method
}
#Component
class B {
private String name;
final A a;
B(A a) {
this.a = a;
}
}

Related

Spring Newbie : How can I inject a a Bean instance with various members initializations?

I am Spring newbie.
I am trying to understand the dependency injection process using Autowired annotation.
For example when using Field autowiring.
#Autowired
private SomeInterface obj;
So, Spring scans now all the components to find a class which implements this interface, creates an instance of it and injects it into the my class.
I guess it uses the implementation class constructor to create the instance by default.
What I still cannot figure out is, can I inject instances with different members values.
And if I can - how can I do that?
For example (quick and dirty code):
interface SomeInterface(){
int getValue();
}
#Component
class SomeInterfaceImpl implements SomeInterface(){
int n;
#Override
int getValue(){
return 0;
}
}
class MyClass(){
#Autowired
private SomeInterface obj;
....
}
So Spring will use SomeInterfaceImpl default constructor to create obj,
and n memebr value will be 0.
But the idea is to inject many variations of the class, isn't it? For example for testing other values.
So, if I want to inject a SomeInterfaceImpl instance but with n = 1, can I do that?
Or am I missing the Dependency injection point, and the injection are varied only by the implementing classed of SomeInterface?
I'll be happy for explanation.
Thanks!
Indeed, Spring's dependency injection seems to have been primarily designed with the idea that when you are using member injection, you will have only one implementation.
This can be solved with Spring's #Qualifier annotation, which you can use to specify which implementation you want injected, when there is more than one.
So, for instance, you might do this:
interface SomeInterface(){
int getValue();
}
#Component("A")
class SomeInterfaceImplA implements SomeInterface(){
int n = 0;
#Override
int getValue(){
return n;
}
}
#Component("B")
class SomeInterfaceImplB implements SomeInterface(){
int n = 42;
#Override
int getValue(){
return n;
}
}
class FooClass(){
#Autowired
#Qualifier("A")
private SomeInterface obj;
int getX() {
return obj.getValue(); // returns 0
}
}
class BarClass(){
#Autowired
#Qualifier("B")
private SomeInterface obj;
int getX() {
return obj.getValue(); // returns 42
}
}

Spring #Required properties when creating #Bean annotated beans

I'm developing a Spring Boot application and am trying out using Java annotation-based bean creation (using #Configuration and #Bean) rather than the familiar old XML-based bean creation. I'm puzzled though. If I attempt to create a bean in XML but fail to set an #Required property I get a BeanInitializationException when the application context is created. In my trials so far with annotation-based bean creation though this does not seem to be the case.
For example:
public class MyClass {
...
#Required
public void setSomeProp(String val){
}
}
Then in Spring XML:
<bean class="MyClass"/>
This will blow up during application startup (and IntelliJ flags it) because the required property is not set. But the same does not seem to be true of this:
#Configuration
public class MyConfig {
#Bean
public MyClass myClass() {
return new MyClass();
}
}
This application starts up just fine even though the required property is not ever set. I must be missing something here, because this seems like a pretty key feature in Spring.
UPDATE
I did some digging & debugging and it turns out that the bean definition is somehow being flagged to skip checking that #Required fields are set. In the Spring class 'RequiredAnnotationBeanPostProcessor' the boolean method 'shouldSkip()' is returning true for beans created this way. When I used the debugger to force that method to return false bean creation did indeed blow up with the expected exception.
Seeing as I'm making a pretty basic Spring Boot application I'm inclined (as Zergleb suggests) to submit this as a bug.
UPDATE 2
Some further debugging has revealed that even if the field is getting set forcing the check still throws the same exception, as if it hadn't been set. So perhaps dunni is correct and there is no way for this to work with #Bean notation.
As you said I also could not get #Required to run as expected this may be a bug and needs to be reported. I have a few other suggestions that did work for me.
Class annotated with #Configuration
//With the bean set up as usual These all worked
#Bean
public MyClass myClass() {
return new MyClass();
}
When you annotate the class #Component and load using component scanning works as expected.(The component scanning part is important you either need your #Configuration class to either have #ComponentScan or perhaps remove #Configuration and replace with #SpringBootApplication and this will enable scanning for components without needing to wire them up using #Bean configs)
#Component // Added this
public class MyClass {
...
#Required //Failed as expected
public void setSomeProp(String val){
}
}
Use #Autowired(required=true) //Fails with BeanCreationException //No qualifying bean of type [java.lang.String] found for dependency
//No more #Component
public class MyClass {
...
#Autowired(required=true) //Fails
public void setSomeProp(String val){
}
}
#Autowired required=false //Does not crash
public class MyClass {
...
#Autowired(required=false) //Simply never gets called if missing
public void setSomeProp(String val){
}
}
#Value //Does not work if test.property is missing // Could not resolve placeholder 'test.property' in string value "${test.property}
public class MyClass {
#Value("${test.property}")
String someProp;
//This getter is not neccesary neither is a setter
public String getSomeProp() {
return this.someProp;
}
}
#Value with default value//Does not crash // When getSomeProp is called it returns "My Default Value"(Unless you have test.property=Anything in your application.properties file then it returns "Anything"
public class MyClass {
#Value("${test.property:My Default Value}")
String someProp;
//This getter is not neccesary neither is a setter
public String getSomeProp() {
return this.someProp; //Returns "My Default Value"
}
}
Inside your #Configuration file also fails if it cannot find anything to populate String someProp in the myClass method
#Bean
public MyClass myClass(String someProp) { //Fails being unable to populate this arg
MyClass myObj = new MyClass();
myObj.setSomeProp(someProp);
return ;
}
If course this won't work, since you create the object of MyClass yourself (new MyClass()), thus the annotations are not evaluated. If you create a bean with a #Bean method, the container will only make sure, that all dependencies are there (method parameters) and that the bean scope is adhered to, meaning if it's a singleton bean, only one bean is created per application context. The creation of the bean/object itself is solely the responsibility of the developer.
The equivalent of the xml <bean> tag is annotating the class with #Component, where the bean is created completely by the container, thus the annotations are evaluated.
As it is being said that when you are having your own #Configuration class where you are creating the bean by itself, #Required doesn't apply there.
When you already have a #Component, let Spring Boot do the component scan and at the required setter property you can add #Autowired and it will work fine.
Found this link on web- https://www.boraji.com/spring-required-annotation-example
For example:
I have a Component called Employee having Id and Name.
#Component
public class Employee {
int id;
String name;
public int getId() {
return id;
}
#Autowired
#Required
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
I have a Configuration class called AppConfig.java
#Configuration
public class AppConfig {
#Bean
public int getId() {
return 1;
}
}
So now we see, that component Employee needs an Id property for binding during startup, so I wrote bean method of type Integer, which will get autowired during runtime. If you do not write a bean of type Integer, it will result a BeanCreationException.
And here is my main class file.
#SpringBootApplication
public class SingletonApplication {
public static void main(String[] args) {
ApplicationContext ctx =
SpringApplication.run(SingletonApplication.class, args);
Employee emp = (Employee)ctx.getBean(Employee.class);
System.out.println(emp.getId());
}
}

Implement factory design pattern with spring annotaion

I have a factory class that should return me an instance of classA or classB. These classes implement interface XYZ:
interface xyz;
getInstance()
#service
classA implements xyz{
public void checkStatus(){
}
}
#service classB implements xyz{
public void checkStatus(){
}
}
Factory class:
#component
class ABCFactory{
#Autowire classA A;
public static getInstance(str a){
return classA;
}
}
Client code:
Class A a = ABCFactory.getInstance("A");
a.checkStatus();
I get null pointer exception -- probably a is returned as null?
What is the best approach to implement the factory pattern with spring annotation and autowired bean?
It's difficult to say with any certainty why your auto-wiring isn't taking place without seeing your Spring config. My first guess is that you don't have component scanning switched on:
<context:component-scan base-package="org.example"/>
Adding something like that to your spring config file (with the correct package) will tell Spring to scan the package structure for fields that need to be auto-wired, and services that can be used for auto-wiring.
static is the root of all evil. How did you managed to access classA here?
#Component
class ABCFactory{
#Autowire classA A;
public static getInstance(str a){
return classA;
}
}
A field is not static while getInstance() method is - your code won't compile.
Furthermore, dependency injection works on instances, not on static classes. Thus you should get rid of static:
#Component
class ABCFactory {
#Autowire classA A;
public xyz getInstance(str a){
return A;
}
}
and inject ABCFactory where you need it (e.g. in other services or controllers):
#Autowired
private ABCFactory factory;
BTW your design looks supicious in Spring environment, what do you want to achieve?

Spring beans with runtime initialization parameters

I have a class which needs
Dependency injection for various beans it uses
Runtime parameters for initialization
The class would look something similar to this
public class Validator {
#Autowired
private ServiceA serviceA;
#Autowired
private ServiceB serviceB;
private String s;
private ClassA a;
private ClassB b;
public void initialize(String s, ClassA a, ClassB b) {
this.s = s;
this.a = a;
this.b = b;
}
public void performTaskA() {
//use serviceA, serviceB, s, a and b
}
public void performTaskB() {
//use serviceA, serviceB, s, a and b
}
public void performTaskC() {
//use serviceA, serviceB, s, a and b
}
}
What are various options through which I can define the above class as spring bean (to take the advantage of dependency injection) and also make sure that the caller calls initialize() before calling any performTask*() methods?
Note - I am aware of Object getBean(String name, Object... args) throws BeansException; but it doesn't look good since we would loose type safety. Any other suggestions?
Update -
The solution mentioned here with lookup method injection is a nice option. Until it is implemented in spring, what's your opinion on the below alternative of using inner classes
public class MyService {
private ServiceA serviceA;
private ServiceB serviceB;
public class DataClass {
private Integer counter;
public DataClass(Integer counter) {
this.counter = counter;
}
public Integer performActionAndGetCount() {
serviceB.performAction();
return this.counter++;
}
}
}
//client module
MyService service = beanFactory.getBean("myService");
MyService.DataClass dataClass = service.new DataClass(1);
Any drawbacks of this approach?
Use component,service or repository annotation to annotate your class. This would enable your class to be considered as a spring bean and you can then use dependency injection and runtime initialization.
Make sure in your {dispatcher-servlet}.xml(replace the name in {} to the name you have given your dispatcher servlet in web.xml} file you have written this line
This can be accomplished using a combination of scope="prototype" and a <lookup-method>.
First, define the class you want to parameterize as a bean with scope="prototype". This will cause the context to generate a new instance every time the bean is requested.
<bean class="com.example.Validator" scope="prototype"/>
Then, define a "factory class" that will wrap the generation and initialization of new objects.
<bean class="com.example.ValidatorFactory">
<lookup-method name="newValidator"/>
</bean>
This class would look like this:
public class ValidatorFactory {
public Validator createValidator(String str, Class<?> classA, Class<?> classB) {
Validator v = newValidator();
v.initialize(str, classA, classB);
return v;
}
protected void newValidator() {
// Spring will implement this via AOP
}
}
This forces clients to go through a routine that will call initialize() while still loading beans via the Spring context.
I am not so clear about your requirement. But I think #PostConstruct annotated method can come to your rescue. You can find more details about #PostConstruct annotation here.
Hope this helps you. Cheers.

spring 3 autowiring and junit testing

My code:
#Component
public class A {
#Autowired
private B b;
public void method() {}
}
public interface X {...}
#Component
public class B implements X {
...
}
I want to test in isolation class A. Do I have to mock class B? If yes, how? Because it is autowired and there is no setter where i could send the mocked object.
I want to test in isolation class A.
You should absolutely mock B, rather than instantiate and inject an instance of B. The point is to test A whether or not B works, so you should not allow a potentially broken B interfere with the testing of A.
That said, I highly recommend Mockito. As mocking frameworks go, it is extremely easy to use. You would write something like the following:
#Test
public void testA() {
A a = new A();
B b = Mockito.mock(B.class); // create a mock of B
Mockito.when(b.getMeaningOfLife()).thenReturn(42); // define mocked behavior of b
ReflectionTestUtils.setField(a, "b", b); // inject b into the B attribute of A
a.method();
// call whatever asserts you need here
}
Here's an example of how I got my tests working with Spring 3.1, JUnit 4.7, and Mockito 1.9:
FooService.java
public class FooService {
#Autowired private FooDAO fooDAO;
public Foo find(Long id) {
return fooDAO.findById(id);
}
}
FooDAO.java
public class FooDAO {
public Foo findById(Long id) {
/* implementation */
}
}
FooServiceTest.java
#RunWith(MockitoJUnitRunner.class)
public class FooServiceTest {
#Mock private FooDAO mockFooDAO;
#InjectMocks private FooService fooService = new FooService();
#Test public final void findAll() {
Foo foo = new Foo(1L);
when(mockFooDAO.findById(foo.getId()).thenReturn(foo);
Foo found = fooService.findById(foo.getId());
assertEquals(foo, found);
}
}
You can inject the field via reflection using Spring's ReflectionTestUtils.setField (or the junit extension PrivateAccessor) or you can create a mock application context and load that. Though for a simple unit (non-integration) test, I favor using reflection for simplicity.
This forum discussion makes sense to me. You can declare your private member b as a type of InterfaceB which is implemented by the class B (ie: service-oriented) then declare a MockB class would also implement the same interface. In your test environment application context, you declare MockB class and your production application context you declare the normal B class and in either case, the code for class A does not need to be changed since it will be auto-wired.

Resources