#Value not resolved when using #PropertySource annotation. How to configure PropertySourcesPlaceholderConfigurer? - spring

I have following configuration class:
#Configuration
#PropertySource(name = "props", value = "classpath:/app-config.properties")
#ComponentScan("service")
public class AppConfig {
and I have service with property:
#Component
public class SomeService {
#Value("#{props['some.property']}") private String someProperty;
I receive error when I want to test the AppConfig configuration class with
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'someService': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private java.lang.String service.SomeService.someProperty; nested exception is org.springframework.beans.factory.BeanExpressionException: Expression parsing failed; nested exception is org.springframework.expression.spel.SpelEvaluationException: EL1008E:(pos 0): Field or property 'props' cannot be found on object of type 'org.springframework.beans.factory.config.BeanExpressionContext'
The issue is documented in SPR-8539
but anyway I cannot figure out how to configure PropertySourcesPlaceholderConfigurer to get it work.
Edit 1
This approach works well with xml configuration
<util:properties id="props" location="classpath:/app-config.properties" />
but I want to use java for configuration.

as #cwash said;
#Configuration
#PropertySource("classpath:/test-config.properties")
public class TestConfig {
#Value("${name}")
public String name;
//You need this
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}

If you use #PropertySource, properties have to be retrieved with:
#Autowired
Environment env;
// ...
String subject = env.getProperty("mail.subject");
If you want to retrieve with #Value("${mail.subject}"), you have to register the prop placeholder by xml.
Reason:
https://jira.springsource.org/browse/SPR-8539

I found the reason #value was not working for me is, #value requires PropertySourcesPlaceholderConfigurer instead of a PropertyPlaceholderConfigurer. I did the same changes and it worked for me, I am using spring 4.0.3 release. I configured this using below code in my configuration file.
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}

Don't you need a method on your #Configuration class that returns PropertySourcesPlaceholderConfigurer, annotated #Bean and is static, to register any #PropertySource with Spring?
http://www.baeldung.com/2012/02/06/properties-with-spring/#java
https://jira.springsource.org/browse/SPR-8539

I had the very same problem. #PropertySource is not playing well with #Value. A quick workaround is to have an XML configuration which you'll refer to it from your Spring Java Configuration using #ImportResource as usual and that XML configuration file will include a single entry: <context:property-placeholder /> (of course with the needed namespace ceremony). Without any other change #Value will inject properties in your #Configuration pojo.

This can also be configured in java this way
#Bean
public static PropertySourcesPlaceholderConfigurer properties() {
PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
configurer.setIgnoreUnresolvablePlaceholders(true);
configurer.setIgnoreResourceNotFound(true);
return configurer;
}

That looks mighty complicated, can't you just do
<context:property-placeholder location="classpath:some.properties" ignore-unresolvable="true"/>
then in code reference:
#Value("${myProperty}")
private String myString;
#Value("${myProperty.two}")
private String myStringTwo;
where some.properties looks something like this
myProperty = whatever
myProperty.two = something else\
that consists of multiline string
For java based config you can do this
#Configuration
#PropertySource(value="classpath:some.properties")
public class SomeService {
And then just inject using #value as before

Since Spring 4.3 RC2 using PropertySourcesPlaceholderConfigurer or <context:property-placeholder> is not needed anymore. We can use directly #PropertySource with #Value. See this Spring framework ticket
I have created a test application with Spring 5.1.3.RELEASE.
The application.properties contains two pairs:
app.name=My application
app.version=1.1
The AppConfig loads the properties via #PropertySource.
package com.zetcode.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
#Configuration
#PropertySource(value = "application.properties", ignoreResourceNotFound = true)
public class AppConfig {
}
The Application injects the properties via #Value and uses them.
package com.zetcode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
#ComponentScan(basePackages = "com.zetcode")
public class Application {
private static final Logger logger = LoggerFactory.getLogger(Application.class);
#Value("${app.name}")
private String appName;
#Value("${app.version}")
private String appVersion;
public static void main(String[] args) {
var ctx = new AnnotationConfigApplicationContext(Application.class);
var app = ctx.getBean(Application.class);
app.run();
ctx.close();
}
public void run() {
logger.info("Application name: {}", appName);
logger.info("Application version: {}", appVersion);
}
}
The output is:
$ mvn -q exec:java
22:20:10.894 [com.zetcode.Application.main()] INFO com.zetcode.Application - Application name: My application
22:20:10.894 [com.zetcode.Application.main()] INFO com.zetcode.Application - Application version: 1.1

The thing is: as far as I get it, <util:propertes id="id" location="loc"/>, is just a shorthand for
<bean id="id" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="location" value="loc"/>
</bean>
(see documentation of util:properties). Thus, when you use util:properties, a standalone bean is created.
#PropertySource, on the other hand, as documentation says is an
annotation providing a convenient and declarative mechanism for
adding a PropertySource to Spring's Environment'.
(see #PropertySource doc). So it doesn't create any bean.
Then "#{a['something']}" is a SpEL expression (see SpEL), that means "get something from bean 'a'". When util:properties is used, the bean exists and the expression is meaningful, but when #PropertySource is used, there is no actual bean and the expression is meaningless.
You can workaround this either by using XML (which is the best way, I think) or by issuing a PropertiesFactoryBean by yourself, declaring it as a normal #Bean.

Another thing that may be happening: ensure your #Value annotated values are not static.

In my case, depends-on="bean1" was within property-placeholder was causing the issue. I removed that dependency and used #PostConstruct to achieve the same original functionality and was able to read the new values too.

If you are configuring with xml, after adding
<context:property-placeholder location="..."/>
Make sure your annotations are activated. In my case properties were not fetched for this reason:
<context:annotation-config/>

for me it worked
spring.cloud.config.server.git.default-label=main
spring.cloud.config.server.native.searchLocations=file:///Users/${your username}/Projects/git-local-repositories/
spring.profiles.active=native

Related

#ConfigurationProperites not binding to property source after upgrading to Spring Cloud Hoxton.SR7

I have a #ConfigurationProperties class that is no longer binding to a YML property source that gets resolved via Spring Cloud Config after upgrading to Hoxton.SR7. This code works fine using Hoxton.SR4 with the latest Spring Boot 2.2.9.RELEASE. Now, my properties are not bound and I'm receiving NPEs when I try to reference them. Following is a snapshot of my code:
#Configuration
public class MyConfiguration {
#Bean
public MyPropertiesBean myPropertiesBean() {
return new MyPropertiesBean();
}
}
#ConfigurationProperties(prefix = "com.acme.properties")
#Validated
public class MyPropertiesBean {
...
}
In src/main/resources/META-INF/spring.factories:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.acme.MyConfiguration
Any ideas why my #ConfigurationProperties class doesn't bind after upgrading Spring Cloud to Hoxton.SR7?
You're mixing two ways of binding properties: class and method.
Using a method and #Bean annotation:
#Configuration
public class MyConfiguration {
#Bean
#ConfigurationProperties(prefix = "com.acme.properties")
#Validated
public MyPropertiesBean myPropertiesBean() {
return new MyPropertiesBean();
}
}
This will create MyPropertiesBean and store it inside the application context for you to inject.
Class level bean declaration also creates a bean for you:
#Configuration
#ConfigurationProperties(prefix = "com.acme.properties")
#Validated
public class MyPropertiesBean {
...
}
This will also store a bean.
Although, you should be getting a runtime error when you try to inject MyPropertiesBean as now in your case there's two beans of the same type and Spring cannot resolve with only the type.

Spring Java Config: configure already existing bean

I want to configure in my #Configuration class bean which is already created by other library's autoconfiguration. I just need to change some fields in that class after it's being initialized.
But I can't find a proper way how to provide code block in #Configuration class and not using #Bean annotation. Is there an ideomatic way to do so in spring?
One way to do this:
#Configuration
class TestConfig {
#Autowired
private SomeBean someBean;
#PostConstruct
private void initSomeBean() {
// someBean.setProperty("qwe");
}
}
#PostConstruct annotation defines init-method, which is getting called after SomeBean is autowired. In this method you can adjust your bean
Do you want to import one Config in AnotherConfig on? It can be done via annotation placed on AnotherConfig:
import org.springframework.context.annotation.Import;
...
#Import(value = {Config.class})
public class AnotherConfig ... {}

#EnableAutoConfiguration annotation with class prameter is not initializing properties object

i have following #CongfigurationProperties class
//#Component
#ConfigurationProperties
#PropertySource("classpath:typesofcharge.properties")
public class ChargeProperties {
private HashMap<String,String> charge=new HashMap<>();
public HashMap<String,String> getCharge()
{
return this.charge;
}
}
And this is my Configuration file
#SpringBootApplication
#ComponentScan({"com.vehiclemanagement.config,com.vehiclemanagement.client,"
+ "com.vehiclemanagement.controller,"
+ "com.vehiclemanagement.exception,"
+ "com.vehiclemanagement.model,"
+ "com.vehiclemanagement.service"})
#EnableConfigurationProperties(ChargeProperties.class)
public class VehicleManagementConfig {
public static void main(String[] args) {
SpringApplication.run(VehicleManagementConfig.class, args);
}
}
If i use #Component annotation in ChargeProperties and remove ChargeProperties.class annotation in Configuration class the charge HashMap is initialized properly
If i remove #Component and pass ChargeProperties.class as argument like this
#EnableConfigurationProperties(ChargeProperties.class) like how document says the charge HashMap is empty when i run
I am using spring boot 2.0.2 release .But i am following latest docs. Can anyone explain why this are not working as document suggest
content of property file is as follows
UPDATE the content of property files are as shown
#DO NOT MODIFY THIS FILE
charge.peak=Double_rate;
charge.lateNight=duration_based_charge;
charge.earlyMorning=special_offers;
When specifying ChargeProperies.class on the #EnableConfigurationProperties annotation it will be registered as a bean through the EnableConfigurationPropertiesImportSelector class inside #EnableConfigurationProperties.
So in the example, if you have only annotated the ChargeProperties class with #ConfigurationProperties it will create a chargeProperties bean with an empty charge HashMap because it defaulted back to application.properties as the source.
A custom source can be specified by using #PropertySource.
#PropertySource annotation providing a convenient and declarative mechanism for adding
a PropertySource to Spring's Environment. To be used in conjunction
with #Configuration classes.
As per documentation above, to use #PropertySource to load the custom source, one has to use the #Configuration annotation.
#Configuration
#PropertySource("classpath:typesofcharge.properties")
Under the hood a #Configuration class is a #Component.
#Target(value=TYPE)
#Retention(value=RUNTIME)
#Documented
#Component
public #interface Configuration
So to your question. By specifying a custom #PropertySource without #Configuration, spring did not load the properties in the #PropertySource annotation and defaulted back to the application.properties.
If we use #PropertySource we have to use component otherwise the properties will not be read
since we added the #ComponentScan We don't have to mention #EnableConfiguationProperties annotation at all The propety class object can be autowired as Bean

#Autowired dependencies are null in compile time weaving of #Aspect class [duplicate]

I have the following spring configuration:
<context:component-scan base-package="uk.co.mysite.googlecontactsync.aop"/>
<bean name="simpleEmailSender" class="uk.co.mysite.util.email.simple.SimpleEmailSenderImplementation"/>
<aop:aspectj-autoproxy/>
Then I have an aspect:
#Aspect
public class SyncLoggingAspect {
#Autowired
private SimpleEmailSender simpleEmailSender
#AfterReturning(value="execution(* uk.co.mysite.datasync.polling.Poller+.doPoll())", returning="pusher")
public void afterPoll(Pusher pusher) {
simpleEmailSender.send(new PusherEmail(pusher));
}
}
This aspect works (I can hit a breakpoint on afterPoll) but simpleEmailSender is null. Unfortunately I cannot find clear documentation on why this is. (For the record, my simpleEmailSender bean exists and is correctly wired into other classes) The following things confuse me:
Is context:component-scan supposed to be picking up #Aspect? If it is then surely it would be a spring managed bean, thus autowired should work?
If context:component-scan isn't for creating aspects, how is my aspect being created? I thought aop:aspectj-autoproxy just creates a beanPostProcessor to proxy my #Aspect class? How would it do this if it isn't a spring managed bean?
Obviously you can tell I don't have an understanding of how things should be working from the ground up.
The aspect is a singleton object and is created outside the Spring container. A solution with XML configuration is to use Spring's factory method to retrieve the aspect.
<bean id="syncLoggingAspect" class="uk.co.demo.SyncLoggingAspect"
factory-method="aspectOf" />
With this configuration the aspect will be treated as any other Spring bean and the autowiring will work as normal.
You have to use the factory-method also on Enum objects and other objects without a constructor or objects that are created outside the Spring container.
For Spring Boot to use #Autowired with AspectJ I have found the following method.
In configuration class add your aspect:
#Configuration
#ComponentScan("com.kirillch.eqrul")
public class AspectConfig {
#Bean
public EmailAspect theAspect() {
EmailAspect aspect = Aspects.aspectOf(EmailAspect.class);
return aspect;
}
}
Then you can successfully autowire your services in your aspect class:
#Aspect
public class EmailAspect {
#Autowired
EmailService emailService;
Another option is to add #Configurable to your aspect class instead of messing around with XML.
Configuring #Autowired with java config only (so no XML based configuration) requires a bit of extra work than just adding #Configuration to the class, as it also needs the aspectOf method.
What worked for me was creating a new class:
#Component
public class SpringApplicationContextHolder implements ApplicationContextAware {
private static ApplicationContext applicationContext = null;
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
And then use that in you aspect in conjunction with using #DependsOn #Configured and #Autowired:
#DependsOn("springApplicationContextHolder")
#Configuration
#Aspect
public class SomeAspect {
#Autowired
private SomeBean someBean;
public static SomeAspect aspectOf() {
return SpringApplicationContextHolder.getApplicationContext().getBean(SomeAspect.class);
}
The #DependsOn is needed because spring can't determine the dependency because the bean is used staticly.
I dont have 50 rep to comment on a question so here is another answer relating to #
Jitendra Vispute answer.
The official Spring doc mentions:
You may register aspect classes as regular beans in your Spring XML configuration, or autodetect them through classpath scanning - just like any other Spring-managed bean. However, note that the #Aspect annotation is not sufficient for autodetection in the classpath: For that purpose, you need to add a separate #Component annotation (or alternatively a custom stereotype annotation that qualifies, as per the rules of Spring’s component scanner).Source: Spring '4.1.7.Release' documentation.
This would mean that adding a #Component annotation and adding the #ComponentScan on your Configuration would make #Jitendra Vispute's example work. For the spring boot aop sample it worked, though I did not mess around with context refreshing.Spring boot aop sample:
Application:
package sample.aop;
#SpringBootApplication
public class SampleAopApplication implements CommandLineRunner {
// Simple example shows how an application can spy on itself with AOP
#Autowired
private HelloWorldService helloWorldService;
#Override
public void run(String... args) {
System.out.println(this.helloWorldService.getHelloMessage());
}
public static void main(String[] args) throws Exception {
SpringApplication.run(SampleAopApplication.class, args);
}
}
The application should also run as plain Spring Framework application with the following annotations instead of #SpringBootApplication:
#Configuration
#EnableAspectJAutoProxy
#ComponentScan
and an AnnotationConfigApplicationContext instead of SpringApplication.
Service:
package sample.aop.service;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
#Component
public class HelloWorldService {
#Value("${name:World}")
private String name;
public String getHelloMessage() {
return "Hello " + this.name;
}
}
Monitor Aspect:
package sample.aop.monitor;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
#Aspect
#Component
public class ServiceMonitor {
#AfterReturning("execution(* sample..*Service.*(..))")
public void logServiceAccess(JoinPoint joinPoint) {
System.out.println("Completed: " + joinPoint);
}
}
This blog post explains it really well. Due to the fact that aspect singleton is created outside spring container you'd need to use factory-method=”aspectOf” that is only available after it is woven in by AspectJ ( not Spring AOP ) :
Notice factory-method=”aspectOf” that tells Spring to use a real
AspectJ ( not Spring AOP ) aspect to create this bean. So that after
the aspect is woven in it has an
“aspectOf” method.
So that :
No matching factory method found: factory method 'aspectOf()' - That
would mean that the aspect was not woven by AspectJ weaver.
From my experience with spring 3.1, if I don't use #Autowired but traditional setter for dependency injection, it gets injected and works as expected without aspectJ weaver. Although I'm encountering problems with the aspect being singleton... It results in 'perthis' instantiation model.
.
Add #Component to aspect class and your dependencies should get injected automatically.
and add context:component-scan for package where your aspect is in spring context file.
#Component
#Aspect
public class SomeAspect {
/* following dependency should get injected */
#Autowired
SomeTask someTask;
/* rest of code */
}
Use compile time weaving, see for plugin example at: https://github.com/avner-levy/minimal_spring_hibernate_maven_setup/blob/master/pom.xml
The following combination of annotation and Spring config works for me thanks to notes above by Tobias/Willie/Eric:
Class:
package com.abc
#Configurable
#Aspect
public class MyAspect {
#Autowired
protected SomeType someAutoWiredField;
}
XML:
<context:spring-configured />
<context:component-scan base-package="com.abc" />
#Configurable(autowire = Autowire.BY_TYPE)
Add this annotation to your Aspectj class. Then it will be handled by Spring IOC.
For Spring Boot using #Autowired in #Aspect,
my way is using spring.factories configuration file
create a file named spring.factories in src/main/resources
the file content is as following
org.springframework.boot.autoconfigure.EnableAutoConfiguration=pack.age.to.YourAspect,pack.age.to.YourDAO

#Value is not injected

I'm trying to inject value from properties file into a spring configuration class as follows:
#Configuration
#EnableWebMvc
public class ImagesContext {
#Autowired
#Value("${some.property.com}")
private String property;
#Bean
public MyClass getMyClass() {
return new MyClass(property);
}
}
But the property is not injected correctly. Instead, when I debug, I see that the property string contains ${some.property.com} and not the string value itself.
The #Value annotation is processed by AutowiredAnnotationBeanPostProcessor which is typically registered if you have a <component-scan> or <annotation-config> configuration in XML (or directly with a bean definition). You need to add either of those, probably <annotation-config>
Add the following bean declaration in your Config class if not done already
#Bean
public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
In order for #Value annotations to work PropertySourcesPlaceholderConfigurer should be registered. It is done automatically when using <context:property-placeholder> in XML, but should be registered as a static #Bean when using #Configuration.

Resources