0

I'm having trouble injecting the Bean type to a constructor parameter from a property file. I am able to inject it by directly passing the value to @Qualifier("beanName") as follows.

@Component("circle")
public class Circle implements Shape {

}

@RestController  
class MyController {    
    private final Shape shape;

    @Autowired
    public MyClass(@Qualifier("circle")
            Shape shape) {
    this.shape = shape;     
    }
}

However, the below code samples do not work.

This returns Null.

@RestController
class MyController {    
    private final Shape shape;

    @Autowired
    public MyClass(@Qualifier("${shape}")
            Shape shape) {
    this.shape = shape;     
    }
}

Tried using @Resource(name="${shape}") in place of @Qualifier as mentioned here ( Spring: Using @Qualifier with Property Placeholder ) but get the compiler error " '@Resource' not applicable to parameter "

@Resource("${shape}") gives the error " Cannot find method 'value' "

This does not work too:

@RestController
class MyController {    
    @Value("${shape}")
    private final String shapeBean; //Compiler error : "Variable 'shapeBean' might not have been initialised"
    //Not declaring shapeBean as final will give a compiler error at @Qualifier: "Attribute value must be constant"
    private final Shape shape;

    @Autowired
    public MyClass(@Qualifier(shapeBean)
            Shape shape) {
    this.shape = shape;     
    }
}

The code below does not work too. Gives a compiler error at @Qualifier : "Attribute value must be constant".

@RestController
class MyController {    
    @Value("${shape}")
    private final String shapeBean;
    private final Shape shape;

    @Autowired
    public MyClass(@Qualifier(shapeBean)
            Shape shape) {
    this.shape = shape;     
    }
}

Also tried the following. Both throw a NullPointerException on attempting to access shape.

@Resource(name="${shape}")
private Shape shape; // In addition, throws a warning saying, "Private field 'shape' is never assigned"

@Autowired  
@Resource(name="${shape}")
private Shape shape;

If the constructor parameter was a primitive or a String, I could just use the @Value("${shape}") and inject the value to the variable. But since it's a Class I am not sure how to get it done.
Could someone please tell me if I have configured incorrectly or what I'm supposed to do?

Community
  • 1
  • 1
Arthas
  • 421
  • 1
  • 6
  • 23
  • So you're wanting to select different shapes at runtime? Generally speaking, you'd use something like profiles like that. Can you be more specific about your actual application? – chrylis -cautiouslyoptimistic- May 23 '16 at 19:30
  • Assuming from the above example, I have a Shape interface and concrete classes implementing shape. But for now in my controller, I want only the circle shape to be injected into the Shape object. I was earlier using @Qualifier("circle") which worked perfectly. But since I don't want to keep it hard-coded I would like to get it from a property file. Is there any way I can get the value from a property file and then inject that value into the Shape object? – Arthas May 23 '16 at 19:35

1 Answers1

0

Wouldn't Circle have all methods implemented that's defined in Shape ? - as long as the contract of shape is met, you should be fine. Now in the case that you have multiple shapes present say Triangle, Rectangle and Circle and for some reason you want to dynamically load the exact subclass, you may want to get the particular bean using the ApplicationContext.getBean("").

You can maintain a reference to the various possible shapes by overriding afterPropertiesSet() - look at InitialingBean and at runtime use the right bean.

JVXR
  • 1,294
  • 1
  • 11
  • 20
  • For now I am using services provided by Circle. At some point I might discontinue with the services provided by _Circle_ and subscribe to services provided by _Triangle_. Hence as a fix I want to declare the service provider in my property file rather than declare it in my Controller. Is there a way to assign a property value using annotations? – Arthas May 23 '16 at 21:32
  • Yes, easiest way would be to use spring profiles to activate a set of bean(s) based on the spring.profile.active env variable, Simple tutorials are given below https://spring.io/blog/2011/02/14/spring-3-1-m1-introducing-profile/ http://www.mkyong.com/spring/spring-profiles-example/ – JVXR May 23 '16 at 21:52