Hierarchical Bean Dependency in Spring Boot - java

I have a hierarchy of beans dependency of same parent class S as:
A -> B -> C
where Bean A contains bean B, bean B contains C with code structure something like this:
public class A extends S {
private S successor;
}
public class B extends S {
private S successor;
}
public class C extends S {
private S successor;
}
And when implementing I have
A a = new A();
B b = new B();
C c = new C();
a.successor = b;
b.successor = c;
What I really want to do here to set all the immediate above bean creation and dependency relationships in the Configuration instead of hardcoding in the code; something like:
#Configuration
public class MyConfig {
#Bean
public A a {
return new A();
}
#Bean
public B b {
B b = new B();
A a; // somehow get the bean A here
a.successor = b;
}
#Bean
public C c {
C c = new C();
B b; // somehow get the bean b here
b.successor = c;
}
}
Any inputs on how to go about this using Spring boot Dependency injection?

You can pass required beans as arguments to your provider methods.
#Bean
public A a() {
return new A();
}
#Bean
public B b(A a) {
B b = new B();
a.successor = b;
return b;
}
#Bean
public C c(B b) {
C c = new C();
b.successor = c;
return c;
}
However, this sets the a.successor only when B is injected somewhere. I believe this is not what you expect, and inverting the construction chain is desired:
#Bean
public A a(B b) {
A a = new A();
a.successor = b;
return a;
}
#Bean
public B b(C c) {
B b = new B();
b.successor = c;
return b;
}
#Bean
public C c() {
return new C();
}

Related

Easymock call autowired object method

Let's say I have Following classes:
public class A {
#Autowired B b;
public void doSomething(){
b.doSomeThingElse();
}
#Component
#Autowired C c;
public class B {
public void doSomethingElse(){
c.doIt();
}
How can I test A when you know I want to mock c.doIt() but want to call b.doSomethingElse(); with EasyMock?
Thanks in advance
#Autowired is nice but tend to make us forget about how to test. Just add a setter for b and c.
C c = mock(C.class);
c.doIt();
replay(c);
B b = new B();
b.setC(c);
A a = new A();
a.setB(b);
a.doSomething();
verify(c);
Or use constructor injection.
C c = mock(C.class);
c.doIt();
replay(c);
B b = new B(c);
A a = new A(b);
a.doSomething();
verify(c);
In this case, your classes become:
public class A {
private B b;
public A(B b) { // Spring will autowired by magic when calling the constructor
this.b = b;
}
public void doSomething() {
b.doSomeThingElse();
}
}
#Component
public class B {
private C c;
public B(C c) {
this.c = c;
}
public void doSomethingElse(){
c.doIt();
}
}

Constructor based dependency injection inject property based objects

I have two classes
Class B {
#Resource
C c;
}
Class A {
private final B b;
public A(B b) {
this.b = b;
}
}
Then class A is initialized using Spring through #Bean annotation as follows:
#Configuration
public class AppConfigHelper {
#Bean
public C getC() {
return new C();
}
#Bean
public B getB() {
return new B();
}
#Bean
public A getA() {
return new A(getB());
}
}
The problem that I end up with is C getting null in object of type B. Is there a solution to this problem?
I have to get A initialized this way only as the B is the old code which I do not want to touch at this point of time.

Spring. Resolve circular dependency with java config and without #Autowired

I've got circular dependency and java config. While resolving it with xml config is very easy I can't resolve it with java config without #Autowired. Beans:
public class A {
private B b;
public B getB() {
return b;
}
public void setB(B b) {
this.b = b;
}
}
public class B {
private A a;
public A getA() {
return a;
}
public void setA(A a) {
this.a = a;
}
}
I've tried this(I've read that with #Bean annotation Spring won't invoke method every time bean is referenced, but in this case it's actually been invoked all the time):
#Configuration
public class Config {
#Bean
public A a() {
A a = new A();
a.setB(b());
return a;
}
#Bean
public B b() {
B b = new B();
b.setA(a());
return b;
}
}
And this, with #Autowired of Configuration class fields:
#Configuration
public class Config {
#Autowired
A a;
#Autowired
B b;
#Bean
public A a() {
A a = new A();
a.setB(b);
return a;
}
#Bean
public B b() {
B b = new B();
b.setA(a);
return b;
}
}
Also I've tried all above with #Lazy annotation. Doesn't help. But works perfectly if I annotate setters of A and B with #Autowired. But it's not what I want right now. What am I doing wrong and is there any way to resolve Circular dependency in java config without usage of #Autowired?
The behavior you want to get is the following
A a = new A();
B b = new B();
a.setB(b);
b.setA(a);
#Bean methods don't give you that. They run to completion to provide a bean instance.
You basically have to partially create one of the instances, then finish initializing it when you've created the other.
#Configuration
class Config {
#Bean
public A a() {
A a = new A();
return a;
}
#Bean
public B b() {
B b = new B();
A a = a();
b.setA(a);
a.setB(b);
return b;
}
}
or
#Bean
public B b(A a) {
B b = new B();
b.setA(a);
a.setB(b);
return b;
}
Another approach using #Autowired and #Component is to use this pattern:
#Component
class A {
private B b;
public B getB() {
return b;
}
public void setB(final B b) {
this.b = b;
}
}
#Component
class B {
private final A a;
#Autowired
public B(final A a) {
this.a = a;
a.setB(this);
}
public A getA() {
return a;
}
}
This eliminates the need for a separate #Configuration-class. Furthermore, the setB-method can possibly be package-protected if the classes exist in the same package to minimize scoping as much as possible.
I want to add another possible solution for your code. Instead of setting circular dependencies right in the config:
#Configuration
public class Config {
#Bean
public A a() {
A a = new A();
a.setB(b());
return a;
}
#Bean
public B b() {
B b = new B();
b.setA(a());
return b;
}
}
You could also let the spring do the work with the power of #Autowired annotation.
#Configuration
public class Config {
#Bean
public A a() {
A a = new A();
return a;
}
#Bean
public B b() {
B b = new B();
return b;
}
}
public class A {
private B b;
#Autowired
public setB(B b) { this.b = b; }
}
public class B {
private A a;
#Autowired
public setA(A a) { this.a = a; }
}
Of course it is non trivial from the "clean/readable/understandable" point of view because now your configuration is mixed in #Configuration and class itself. But as circular dependencies are quite rare, we could afford the hack.

Spring autowire is giving nullPointerException

This is the controller which calls thread 'TestRunner'.
#Controller
#RequestMapping("/welcome")
public class HomeController {
#RequestMapping(method = RequestMethod.GET)
public ModelAndView addCustomerPage() throws Exception{
ModelAndView modelAndView = new ModelAndView("customer/add-customer-form");
A a = new A();
B b = new B();
C c = new C();
TestRunner runner = new TestRunner(a, b, c);
Thread t = new Thread(runner);
t.start();
return modelAndView;
}
}
This is my thread which calls service HomeService. This service is autowired but still I getting null pointer exception when I call homeService.testMeth(a,b,c);
#Controller
public class TestRunner implements Runnable{
private A a;
private B b;
private C c;
#Autowired
private HomeService homeService;
public TestRunner() {
super();
// TODO Auto-generated constructor stub
}
public TestRunner(A a, B b, C c){
this.a = a;
this.b = b;
this.c = c;
}
public void run() {
// TODO Auto-generated method stub
homeService.testMeth(a,b,c);
}
}
This is service class.
#Service
public class HomeService {
public void testMeth(A a, B b, C c){
System.out.println("inside....");
}
}
Is this because of I am creating 'TestRunner' object with 'new' ?
Is this because of I am creating 'TestRunner' object with 'new' ?
Yes, It is because of this you get NullpointerExceptoin.
To fix the issue change the following:
Mark the following three classes A, B, C as component - if not
already done. Ensure the package is in component scan path:
#Component
public class A {
#Component
public class B {
#Component
public class C {
Then Autowire the A, B, C instances in TestRunner. Also change the annotation of TestRunner to #Component
#Component
public class TestRunner implements Runnable{
#Autowired
private A a;
#Autowired
private B b;
#Autowired
private C c;
In HomeRunner create an instance field for TestRunner and autowire it. Remove the instansiation code with new operator for TestRunner.

How to create two objects that hold a reference to eachother?

class A {
B ob1 = new B();
}
class B {
A ob2 = new A();
}
class C {
A a = new A();
// I am getting a StackOverflowException here
}
I am getting a StackOverflowException on the line I commented on. How can I solve this?
Problem with your approach is that when you create instance of A, this instance have to create instance of B which also have to create instance of A which creates instance of B... and so on until stack will overflow.
Probably most intuitive way would to solve this problem with getters/setters like
class A{
private B b;
public void setB(B b) { this.b = b; }
public B getB() { return b; }
}
class B{
private A a;
public void setA(A a) { this.a = a; }
public A getA() { return a; }
}
class Demo {
public static void main(final String[] args) throws Exception {
A a = new A();
B b = new B();
//let them see each other
a.setB(b);
b.setA(a);
}
}
If you want the B object to hold a reference to the A object that created it, you want something like this:
class A {
B ob1 = new B(this);
}
class B {
A a;
public B(A a) {
this.a = a;
}
}
This will not result in a StackOverflow and B will know about A and A will know about B. What you were doing is creating an instance of A which created an instance of B which created an instance of A which created...

Categories

Resources