I have an issue where Spring #Value annotation not working in the constructor.
I have this Email class that is reading some email related configuration.
In the constructor, if I put a break-point the values are empty
But if I call the sendEmail method, there are values.
The other class:
#Autowired
Email sender;
Email class:
#Component
public class Email{
#Value("${TO_EMAIL}")
private String toEmail;
public Email() {
// Here toEmail is null
}
public void sendEmail(String subject, String body) {
// Here toEmail has value
}
}
As far I remember, the value injection occurs after the constructor call.
Try to change your constructor to this:
public Email(#Value("${TO_EMAIL}") String toEmail) {
this.toEmail = toEmail;
}
The value injection occures after the constructor call, to solve this in your case, you can leave the constructor empty. And add a method annotated with "#PostConstructor".
This way, the empty constructor will be called, then the values will be injected, then the #PostConstructor method will be called.
I encountered similar problems when I work with ApplicationRunner
public class AppStartupRunner implements ApplicationRunner {
#Autowired
private Environment myEnv; //not work
#value(${xxx.xxx})
private String myValue //not work
#Autowired
public AppStartupRunner(Environment env) {
System.out.println(myEnv); //null
System.out.println(myValue); //null
}
}
After I changed to the below codes, it works perfectly
#Autowired
public AppStartupRunner(Environment env) {
env.getProperty("key") //works!
}
Related
I use spring boot 2.
I need to validate many condition, instead of creating many if, I create a class for every condition who implements isValid method.
public interface Rulecondition<T>{
boolean isValid(){
}
public class ClientGroup implements Rulecondition<Billing>{
private Billing billing;
public ClientGroup(Billing billing){
this.billing=billing;
}
#Override
public boolean isValid(){
return true; //only for example...
}
}
I create a class who use a stream of all condition and verify if everything is valid
#Component
public class ConditionRuleEngine{
private List<Rulecondition> rules = new ArrayList<>();
public ConditionRuleEngine(){
}
public void addRule(Rulecondition rule){
rules.add(rule);
}
public boolean conditionApply(){
retunr rules.stream().allMatch(r->.isValid()));
}
}
In a service class, I autowired ConditionRuleEngine
#Service
public class OperationService(){
private final ConditionRuleEngine conditionRuleEngine;
#Autowired
public OperationService OperationService(final ConditionRuleEngine conditionRuleEngine){
this.conditionRuleEngine=conditionRuleEngine;
}
public void execute(Billing billing){
//need to add condition
conditionRuleEngine.run();
}
}
Is there any better way to add condition then creating a new?
ClientGroup cg = new ClientGroup(billing);
conditionRuleEngine.add(cg);
Yes, but there is one change that would help your situation: Removing the generic type argument, T, from the Rulecondition interface. Since Rulecondition only contains a isValid method that does not depend on the generic parameter, T, that parameter can be safely removed:
public interface RuleCondition {
boolean isValid();
}
The reason for this removal is that it simplifies the Spring-based solution to your problem. Without that generic parameter, you can now mark each of your RuleCondition implementations with #Component (making them eligible for dependency injection) and autowire a List<RuleCondition> into your ConditionRuleEngine class:
#Component
public class ConditionRuleEngine {
#Autowired
private List<RuleCondition> rules;
// ...other implementation details...
}
Spring will inject all of the components that implement RuleCondition into the rules field.
While removing the generic parameter, T, simplifies the solution, it is not required.
If you do need to maintain the generic parameter, T, then you can autowire the RuleCondition for each generic parameter by specifying the parameter in the List type:
public interface RuleCondition<T> {
boolean isValid(T value);
}
#Component
public class ClientGroup implements RuleCondition<Billing> {
#Override
public boolean isValid(Billing value) {
// ...
}
}
#Component
public class ConditionRuleEngine {
#Autowired
private List<RuleCondition<Billing>> billingRules;
#Autowired
private List<RulecCndition<Other>> otherRules;
// ...other implementation details...
}
Spring will inject all RuleCondition objects that match the generic parameter. For example, billingRules will contain a List of all RuleCondition<Billing> (and will not include any RulecCndition<Other> objects.
I am trying to use dependency injection in my Spring MVC web application. I have a function like this in my controller
#RequestMapping(value = "/stockgoogle/", method = RequestMethod.GET)
public #ResponseBody Stock stockGoogle(Locale locale, Model model) {
StockDaoImpl si = new StockDaoImpl();
//al=s.listCurrent(id);
Stock s=si.listGoogle();
System.out.println("reached here");
model.addAttribute("s", s );
return s;
}
I want to dependency inject StockDaoImpl. Can you please tell me how I can do this. I have been trying to read but most of the explainations are very complex. Should I use #Autowired ? Where should I put it? Can you please help.
You can inject it through the Controller's constructor
class YourController{
private final StockDao dao;
#Autowired
public YourController(StockDao dao){
this.dao = dao;
}
}
And now StockDaoImpl has to be defined as a Bean of course,
#Bean
public StockDao stockDao(){
return new StockDaoImpl();
}
Another way for doing it would be defining StockDaoImpl as a Component
Add below config in Spring config file(for example root-context.xml)
then in your controller, you like below code
class TestController{
#Autowired
private StockDao stockDao;
}
With spring-4 you can directly inject in given way :
#Autowired
private StockDao stockDao;
public #ResponseBody Stock stockGoogle(Locale locale, Model model) {
//al=s.listCurrent(id);
Stock s = stockDao.listGoogle();
System.out.println("reached here");
model.addAttribute("s", s );
return s;
}
Here
StockDao will contain method signature
StockDaoImpl implements StockDao and definition of methods
Autowired will inject that Dao and you can use its method.
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());
}
}
A question on how Spring injection works? If I inject same service in a class and all its sub-classes is it going to to inefficient? How does Spring's container going to store/control this?
public class baseClass {
#Autowired
private iService serviceName
}
public class extendedClassA extends baseClass {
#Autowired
private iService serviceName
}
public class extendedClassB extends extendedClassA {
#Autowired
private iService serviceName
}
Thanks..
I haven't tried but I believe it is going to cause problem.
The main problem is not due to Spring, but variable shadowing in your example. BaseClass' serviceName is shadowed by child class, that means, if you haven't done special handling, BaseClass' serviceName is going to be null.
You may want to consider doing this:
// !!!! Mind your naming convention!!!!!!
public class BaseClass {
#Autowired
private FooService fooService;
protected FooService getFooService() {
return this.fooService;
}
public setFooService(FooService fooService) { ... }
}
public class ExtendedClassA extends BaseClass {
// no need to inject fooService again, whenever it need to use that,
// simply do getFooService() and use it
}
Adrian Shum response seems fine but you need to declare too your BaseClass bean in your applicationContext file with the property "abstract=true"
<bean id="baseClass" class="BaseClass" abstract="true"/>
I'm having an issue when trying to mock a property of a service from within a Junit test:
#ContextConfiguration("classpath:application-config.xml")
#RunWith(SpringJUnit4ClassRunner.class)
public class FooServiceTests {
#Autowired
private FooServiceImpl fooService;
#Test
public void testFoo() {
String str = fooService.foo();
assertEquals("Var", str);
}
#Before
public void mockFooDao() throws Exception {
FooDao mockFooDao = Mockito.mock(FooDao.class);
Mockito.when(mockFooDao.foo()).thenReturn("Var");
ReflectionTestUtils.setField(fooService, "fooDao", mockFooDao);
}
}
Mocking fooDao has no effect since the the result is not the expected. Here is the code of both the service and the dao:
#Service("fooService")
public class FooServiceImpl implements FooService {
#Autowired
protected FooDao fooDao;
#Override
public String foo() {
return fooDao.foo();
}
}
#Repository
public class FooDaoImpl implements FooDao {
#Override
public String foo() {
return "foo";
}
}
As we can see the actual service is meant to return "foo", but the test mocks the dao so the service returns "var". I know it's a CGLIB proxy related thing but I can't figure out how to make it work without using a setter for the fooDao property. Any help would be appreciated.
Regards and thanks in advance.
Short answer
You have to unwrap the proxy and set the field on the target object:
ReflectionTestUtils.setField(unwrapFooService(), "fooDao", mockFooDao);
The unwrapFooService() can be defined as follows:
private FooServiceImpl unwrapFooService() {
if(AopUtils.isAopProxy(fooService) && fooService instanceof Advised) {
Object target = ((Advised) fooService).getTargetSource().getTarget();
return (FooServiceImpl)target;
}
return null;
}
...long one
The problem is quite complex, but solvable. As you have guessed this is a side-effect of CGLIB proxies being used. In principle, Spring creates a subclass of your FooServiceImpl named similar to FooServiceImpl$EnhancerByCGLIB. This subclass contains a reference to the original FooServiceImpl as well as... all the fields FooServiceImpl has (which is understandable - this is a subclass).
So there are actually two variables: FooServiceImpl$EnhancerByCGLIB.fooDao and FooServiceImpl.fooDao. You are assigning a mock to the former but your service uses the latter... I wrote about this pitfalls some time ago.