2

I am working in Spring Boot, and in MyService class I got a class name as String and i want to initialize that object and get back returned values.

but I have no much more idea about it, I think it achieved by Dependency injection. but, how ?

Suppose I have classes A.java, B.java, C.java and Service class MyService.java

@Component
public class A{
 public String wish(int timeHr){
 //some logic of time based wish
 return "Hello A"+" good morning";
}
}
@Component
public class B{
 public String wish(int timeHr){
 //some logic of time based wish
 return "Hello B"+" good morning";
}
}
@Component
public class C{
 public String wish(int timeHr){
 //some logic of time based wish
 return "Hello C"+" good morning";
}
}
@Service
public class MyService{
 // i get here A class name as String like,
 String classNameString = "A"; // or "B", or "C"
 int timrHr = new Date().getHours();
 //how to here i will initialize above class and get method wist(param) returned wish msg.
 //like, a.wish(timeHr); and it gives "Hello A good morning"
}

I expect the output of returned by wish().

Can any one suggest me how do I achieved it ?

Thanks.

asked Aug 2, 2019 at 10:44
3
  • 1
    Why dont you use @Autowire in your MyService? Like @Autowire A a; Commented Aug 2, 2019 at 10:49
  • @arnonuem but how to we decide to autowired when we have String of class name like,` String classNameString = "A" or "B" or "C"`. thanks to reply. Commented Aug 2, 2019 at 11:05
  • Might be helpful stackoverflow.com/questions/5725222/… Commented Aug 2, 2019 at 11:08

3 Answers 3

4

I can think of two ways here. First way is to name the class (after @Component) and using context, try to get the bean. You can also name the bean using @Qualifier

@Component("A")
public class A{
 public String wish(int timeHr){
 //some logic of time based wish
 return "Hello A"+" good morning";
}
@Component("B")
public class B{
 public String wish(int timeHr){
 //some logic of time based wish
 return "Hello B"+" good morning";
}
}
@Component("C")
public class C{
 public String wish(int timeHr){
 //some logic of time based wish
 return "Hello C"+" good morning";
}
}
@Service
public class MyService{
 @Autowired
 private ApplicationContext context;
 void myMethod() {
 A a = (A) context.getBean("A");
 System.out.println(a.wish(123));
 } 
 }

Second way is to make all your wisher classes implement an interface and iterate through all the implementing beans of this interface and find the correct bean

@Component
public class A implements Wisher{
 public String wish(int timeHr){
 //some logic of time based wish
 return "Hello A"+" good morning";
}
@Component
public class B implements Wisher{
 public String wish(int timeHr){
 //some logic of time based wish
 return "Hello B"+" good morning";
}
}
@Component
public class C implements Wisher{
 public String wish(int timeHr){
 //some logic of time based wish
 return "Hello C"+" good morning";
}
}
public interface Wisher{ public String wish(int time); }
@Service
public class MyService{
 @Autowired
 private List<Wisher> wishers;
void myMethod() {
 String requiredClassName = "A";
 Wisher requiredWisher = null;
 for (int i = 0; i < wishers.length(); i++) {
 Wisher w = wishers.get(i);
 if (w.getClass().getName().equals(requiredClassName)) {
 requiredWisher = w;
 break;
 }
 System.out.println(w.wish(123));
 }
}
 }
answered Aug 2, 2019 at 12:26
2
  • Thanks your 1st way is work for me. But i have a doubt, Is it a good practice to Autowired ApplicationContext in service class and it have any disadvantage of it ? Commented Aug 2, 2019 at 13:04
  • 1
    @programmer420 I don't see any adv/disadv of using it. We are using it in production code itself. You can try using ApplicationContextAware interface as said in stackoverflow.com/questions/4914012/… Commented Aug 2, 2019 at 13:10
1

String is not a manageable bean by Spring IoC framework, but instances of classes A, B and C are your beans.

What you should do is to declare the classes A, B and C as implement of the common interface and inject a corresponding bean by this type:

interface Wisher {
 String wish(int timeHr);
}
@Component
public class A implements Wisher {
 public String wish(int timeHr){
 //some logic of time based wish
 return "Hello A"+" good morning";
 }
}
@Component
public class B implements Wisher {
 public String wish(int timeHr){
 //some logic of time based wish
 return "Hello B"+" good morning";
 }
}
@Component
public class C implements Wisher {
 public String wish(int timeHr){
 //some logic of time based wish
 return "Hello C"+" good morning";
 } 
}
@Service
public class MyService{
 @Autowired
 private Wisher a; // instance of "A" or "B", or "C"
 void myMethod() {
 int timrHr = new Date().getHours();
 wisher.wish(timrHr);
 } 
 }
answered Aug 2, 2019 at 10:55
5
  • Thanks to replying here, But to we instance here A, B, or C . when i have String of Component class like String s ="A" or "B" or "C". Commented Aug 2, 2019 at 11:02
  • you can declare your strings as beans: @Bean String stringA() { return "Hello A"+" good morning";} in a class annotated with @Configuration and inject them, but does it make any sense?))) Commented Aug 2, 2019 at 11:11
  • i get class name as a String from request to Controller and Service, it must initialise this class here and returned the particular wish(). Commented Aug 2, 2019 at 11:21
  • 1
    what about having a Map<String, Wisher> wishers in MyService where names are mapped to A, B and C? when you receive a request with a name you can retrieve a corresponding Wisher from the map and call wisher.wish(). Commented Aug 2, 2019 at 11:24
  • 2
    @star67 , your autowiring of Wisher interface will not work. Spring will not understand which bean among A or B or C to Autowire. In such cases, you have to use Qualifier annotation. Please see my answer below. Commented Aug 2, 2019 at 12:35
1

Considering you are using Spring for implementation all your beans will be Singleton and these will be initialized at the start of App(when ApplicationContext is loaded) and then at that time application has no way to check which implementation to inject.

So there is no way you can conditionally inject bean at runtime with Dependency injection

instead you can use other design like below -

@Service
public class MyService{
 private Wisher wisher;
 public Wisher setupWisher(String class){
 if (class.equals("A")) {
 wisher = new A();
 }else if(class.equals("B")){
 wisher = new B();
 }else if(class.equals("C")){
 wisher = new C();
 }
 }
 void myMethod(String requestString) {
 int timrHr = new Date().getHours();
 setupWisher(requestString).wish(timrHr); 
 }
}
answered Aug 2, 2019 at 12:25
2
  • thanks for replying your answer is a good idea . i have a question , what is disadvantage when we go here with ApplicationContext (above answer by Praveen E) ? Commented Aug 2, 2019 at 13:08
  • 1
    there is no such disadvantage.. nowadays developers use applicationcontext by autowired just as below. it all boils down to design which you think should be selected for implementation. I will prefer the one i suggested as i don't want A,B,C to be spring bean within applicationcontext because it does nothing extra to qualify as spring bean Commented Aug 3, 2019 at 9:45

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.