I have 3 classes say for example: A, B and C. all these three classes are independent to each other. there is no parent child relationship. In class c, if I want to use A and B without using getBean method how to inject and use it in class c?
Is there any other way to do it in spring latest version. Please provide your inputs.
you can use autowiring to inject A and B in C:
#Component
public class A {
...
}
#Component
public class B {
...
}
#Component
public class C {
#Autowired
private A a;
#Autowired
private B b;
... use A and B ..
}
Related
...
#RequiredArgsContructor(onConstructor_ = {#Lazy})
Class A{
private final B b;
#Lazy
private final C c;
}
Class A{
private final B b;
private final C c;
A(B b,#Lazy C c){
this.b = b;
this.c = c;
}
}
Is it Same?
I want to using #Lazy with #RequiredArgsConstructor
I want to using #Lazy with #RequiredArgsConstructor
It's not the same. When you put #Lazy over constructor it leads to the creation of a lazy-resolution proxy for all affected dependencies, i.e. in your first case both b and c injected into constructor are resolved lazily.
In the second case only c is resolved lazily.
See Is using `#Lazy` on a component constructor equal to annotating every argument?
I want to using #Lazy with #RequiredArgsConstructor
Use your first approach.
P.S. Btw, having #Lazy over constructor in the first case makes redundant #Lazy over private final C c;.
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;
}
}
If there are two beans of the same type but with different names. Will spring Autowire the bean based on the name without us adding #Qualifier on the variable? I saw in the documentation, "As a fallback Spring uses the bean name as a default qualifier value".
#Component
class A{
}
#Component
class B extends A{
}
class C{
#AutoWired
A a;
//Will a be of type class A, even without #Qualifier...?
}
If there are two beans of the same type but with different names. Will spring Autowire the bean based on the name without us adding #Qualifier on the variable?
#Autowire in the first place cares about type, later about the name. You will get exception saying that there are multiple candidates for injection while only 1 is expected.
#Resource on the other hand, cares about name first, type later.
In this case, B will get injected because there is an A and a B for Spring to choose from and only one of them matches what the #Autowired field is asking for (Class B, because A is not assignable to B).
However, if you had two B's, you would have to qualify it or mark one of them as the primary.
For example, given this:
#Configuration
public class MyConfig {
#Bean
public B example1() {
return new B();
}
#Bean
public B example2() {
return new B();
}
}
Well, now you have two instances of B, with different names. You can fix this one of two ways:
Qualify your Autowire
Note that I'm using field injection here, you really should use constructor, I'm doing it to save space.
#Component
public class SomeComponent {
#Autowired
#Qualifier("example1")
private B b;
}
Or
Mark A Bean as Primary
Redefine the beans, marking one as #Primary
#Configuration
public class MyConfig {
#Bean
#Primary // <-------- NEW!
public B example1() {
return new B();
}
#Bean
public B example2() {
return new B();
}
}
And then inject without needing to name it:
#Component
public class SomeComponent {
#Autowired // (Will pick Primary)
private B b;
}
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.
I have 2 classes (B,C) extends class A.
#Service
public class A extends AbstratClass<Modele>{
#Autowired
A(MyClass br) {
super(br);
}
#Service
public class B extends A{
#Autowired
B (MyClass br) {
super(br);
}
#Service
public class C extends A{
#Autowired
C (MyClass br) {
super(br);
}
But i have this message:
No unique bean of type [A] ] is defined: expected single matching bean but found 2: [A, B, moveModeleMarshaller]
I really cant get why i have this message & how to resolve even after reading Spring documentation.
Thanks in advance.
You should rewrite your class to something like this with the #Qualifier annotation.
#Service
#Qualifier("a")
public class A extends AbstratClass<Modele>{
#Autowired
A(MyClass br) {
super(br);
}
#Service
#Qualifier("b")
public class B extends A{
#Autowired
B (MyClass br) {
super(br);
}
#Service
#Qualifier("c")
public class C extends A{
#Autowired
C (MyClass br) {
super(br);
}
You must also use the #Qualifier annotation on the instance of type A you're autowiring the Spring bean into.
Something like this:
public class Demo {
#Autowired
#Qualifier("a")
private A a;
#Autowired
#Qualifier("b")
private A a2;
public void demo(..) {..}
}
If you don't like to have this Spring configuration in your production code, you have to write the dependency injection logic with XML or Java configuration instead.
You can also specify a default bean of type A with the #Primary annotation above one of your service classes that extends type A. Then Spring can autowire without specifying the #Qualifier annotation.
Since Spring will never try to guess which bean to inject, you have to specify which one or mark one of them with #Primary as long as its more than one bean of a type.
You are trying (somewhere else) to autowire a bean of type A. Something like:
#Autowired
private A beanA;
But you have 2 beans that conform to this.
You can resolve this by using #Resource and specifying which bean exactly:
#Resource("b")
private A beanA;
(where "b" is the name of the injected bean) or using the #Qualifier annotation.
Generally you will get this error when defined two beans with same class
<bean id="a" class="com.package.MyClass"/>
<bean id="b" class="com.package.MyClass"/>
if you address the above two line we have two beans with same class.
when you trying to autowire this class in any other classed you will get this type of error
You have two solutions
First Method
use qualifier by defining a bean id init
like this
#Autowired
#Qualifier("a")
MyClass a;
#Autowired
#Qualifier("b")
MyClass b;
Second Method
use JSR250 api(its a jar file you can put into your class path
Then do autowriring like below
#Resource("a")
MyClass a
#Resource("b")
MyClass a