#Value in SpringBoot in 2.1.1.RELEASE - java

I have this value defined in the application.properties file
tdk.date.format=yyyy-MM-dd'T'HH:mm:ss'.000Z'
that I use in this class:
public class TdkDateUtils {
private static final Logger LOG = LoggerFactory.getLogger(CryptoDateUtils.class);
#Value("${tdk.date.format}")
private static String tdkDateFormat;
public static boolean afterYesterday2(String strDate) throws ParseException {
LOG.debug("tdkDateFormat -> {} ", tdkDateFormat);
SimpleDateFormat format = new SimpleDateFormat(tdkDateFormat);
Date yesterdayDate = Date.from(Instant.now().minus(1, ChronoUnit.DAYS));
return format.parse(strDate).after(yesterdayDate);
}
}
but is null

TdkDateUtils is a utility class and afterYesterday2 is a static method. It exists entirely outside of your application Spring context, annotations like #Value won't be processed here.
For #Value to work you would have to make TdkDateUtils a bean as only Spring beans will be processed by PropertyPlaceholderConfigurer. Alternatively could read and set the property yourself in TdkDateUtils static initialization block but it goes against Spring philosophy of dependency injection.

Spring doesn’t allow to inject value into static variables. Create a non-static setter method to inject the value.
private static String tdkDateFormat;
#Value("${tdk.date.format}")
public void setDateFormat(String s){
tdkDateFormat = s;
}

Related

My annotation #Value return null even it being used and called into component annotated classes

I'm using Spring and need some help:
I want to set one API key using application.properties instead of hardcoding it, but it always returns null. IntelliJ evaluates it correctly to the value I've set in the file.
I've already read other questions here and almost all solutions are saying that Spring can only "inject" those value anotations in managed classes, like Components, Beans, etc. That's what (think) I did and still got null!
Everything else is working as I intended. Any direction is appreciated!
My application.properties
api.someapiservice.key=08e...f
Class that uses the properties value:
#Component
public class ApiClient implements ApiClientInterface {
#Value("${api.someapiservice.key}")
private String API_KEY;
public ApiClient () {
System.out.println(API_KEY); //Returns null after spring log info: Initialized JPA EntityManagerFactory for persistence unit 'default'
...
}
Class that uses ApiClient:
#Component
public class SomeService {
private final SomeRepository someRepository;
private final ApiClient apiClient;
public PlaylistService(SomeRepository someRepository , ApiClient apiClient ) {
this.SomeRepository = SomeRepository;
this.apiClient = ApiClient;
}
Field injection can't possibly happen until after the instance is already constructed, so your #Value (or #Autowired) fields will always be null in the constructor. Move the #Value to a constructor parameter instead.
If you want to know what is the value of your #Value field on start up. You can use #PostConstruct annotation, or you can move #Value annotation on your class constructor.
private String API_KEY;
public ApiClient(#Value("${api.test.value}") String key) {
this.API_KEY= key;
System.out.println(this.API_KEY);
}
or using #PostConstruct Annotation
#Value("${api.someapiservice.key}")
private String API_KEY;
#PostConstruct
public void init() {
System.out.println(this.API_KEY);
}

How can I interpolate a class constant in a Spring `#Value` annotation?

I want to let Spring assign a property value.
public class Foobar {
#Value("${example.property.foo:bar}")
private String foo;
}
Let's say I want to refer to example.property.foo in several different places, so I'd rather assign the flag as a constant on Foobar:
public class Foobar {
public static final String FOO_PROPERTY_FLAG = "example.property.foo";
}
The setting of example.property.foo=whatever happens elsewhere (as a system property, or in a #TestPropertySource).
How can I refer to FOO_PROPERTY_FLAG in the annotation? This works:
#Value("${" + FOO_PROPERTY_FLAG + ":bar}")
But it's kind of ugly. Can I use the "#{}" expression syntax here somehow?
#Value("${#{FOO_PROPERTY_FLAG}:bar}") // doesn't work; value is never injected
You can do something like:
public static final String KEY = "propertyName";
#Value("#{T(a.b.c.package.MyConstants).KEY}")
The important part is to specify package and class. Otherwise spring will try to lookup constant in BeanExpressionContext which is actually executing your SpEL
private #Value("${propertyName}") String propertyField;
No getters or setters!
With the properties being loaded via the config:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
p:location="classpath:propertyFile.properties" name="propertiesBean"/>
There's also the totally non-Xml version:
#PropertySource("classpath:propertyFile.properties")
public class AppConfig {
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
Make sure and add in the namespace URI xmlns:p="springframework.org/schema/p"; to use the p: prefixed attributes

Inject value in a spring bean from constants java file

I have an application in which in a spring bean, value is being injected from a property file.
I want to inject value from a constants.java file.
What changes are do I need to make.
Spring bean
#Value("${resetPassword.email.key}")
private String resetPassword;
Property file
resetPassword.email.key = RESET_PASSWORD
Constants.java
public static final String resetPassword_email_key = "RESET_PASSWORD";
You can't reference java constant in properties file. And you don't need Spring injection for that. You simply do
private String resetPassword = Constants.resetPassword_email_key;
If you need to share Constants class between multiple sub-projects (modules of a project), you may want to extract this class to a library that may be included into other projects.
You cannot inject a value to static properties. But you can assign to non-static setter as below:
#Component
public class GlobalValue {
public static String DATABASE;
#Value("${mongodb.db}")
public void setDatabase(String db) {
DATABASE = db;
}
}
From https://www.mkyong.com/spring/spring-inject-a-value-into-static-variables/
You can inject value with #Value from properties file or from spring bean.
To use properties file declare it with util:properties tag:
<util:properties id="jdbcProperties" location="classpath:org/example/config/jdbc.properties"/>
And in spring bean do :
private #Value("#{jdbcProperties.url}") String jdbcUrl;
private #Value("#{jdbcProperties.username}") String username;
private #Value("#{jdbcProperties.password}") String password;
Or you can inject value of another spring bean like:
#Value("#{strategyBean.databaseKeyGenerator}")
public void setKeyGenerator(KeyGenerator kg) { … }
More info at http://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/html/new-in-3.html

Mocking a Properties file with Mockito in Spring

I am trying to write a unit test for the following method in my controller.
#Autowired
private ApplicationContext context;
private String getProperty() {
try {
Properties props = context.getBean("myProperties", Properties.class);
String val = props.getProperty("myProperty");
......
The Bean is declared like this in my applicationContext:
<util:properties id="myProperties" scope="prototype" location="file:${catalina.base}/webapps/myProperties.properties"/>
How can I mock this so that I can test different values of the val variable?
I thought about creating a test properties file and mocking it like this:
context = Mockito.mock(ApplicationContext.class);
Mocikto.when(context.getBean("myProperties", Properties.class)).thenReturn(some test file)
but then I would have to declare the test file as a bean somewhere.
I was wondering if there was an easier way to do this?
Thanks
If you're using spring-3, you can do:
<context:property-placeholder location="myprops.properties" />
And in your code:
#Value("${myProperty}")
private String myProp;
public String getMyProp() {
return myProp;
}
This causes myprops.properties to be made available for variable substitutions via ${...} expressions, and the #Value annotation allows value injection of properties. Then in your unit test you can simply set different values of myProp.
The easier way is to use a org.springframework.beans.factory.config.PropertyPlaceholderConfigurer instead of pulling the properties explicitly from the spring application context. The PropertyPlaceholderConfigurer injects your bean with the properties you specify. Then you don't need Mockito at all, in the test you set the property value in the Controller to whatever you want it to be.
So you'd set up the configurer in the application context xml:
<context:property-placeholder
location="file:${catalina.base}/webapps/myProperties.properties"/>
and add some configuration for your controller (I expect there's a way to do this with annotations but don't know it):
<bean id="whateverMyControllerIdIs" class="com.initech.foobar.MyControllerImpl">
<property name="quux"><value>${myProperty}</value></property>
</bean>
where the controller has an instance variable that you want to populate with the property, with a setter, like this:
String quux;
public void setQuux(String quux) {this.quux = quux;}
Just saw a blog post on Spring 3.1 enhancements, here's the new xml-free way to do this:
#Configuration
#PropertySource("classpath:/com/myco/app.properties")
public class AppConfig {
#Autowired
Environment env;
#Bean
public TestBean testBean() {
TestBean testBean = new TestBean();
testBean.setName(env.getProperty("testbean.name"));
return testBean;
}
}
So I can test without having to load the Spring Context I use a Config class for accessing all of the properties file(s) values from within code. The benefits are:
1) Spring doesn't load in your unit tests
2) You can force an Exception if the property is missing and it is required
3) You can return strongly type property values from the getter() methods (i.e. convert to a Date)
4) The "key" values expected from your properties files are documented in a single Java class (i.e. public static final PROP_XXX)
#Component
public class Config {
public static final String PROP_USER_NAME = "user.name";
private Properties applicationProperties;
/*** Functional methods ***/
/**
* Helper method to ensure consistent Exception handling where requested property values are missing
* from the properties files and they are "required" for the application to function correctly.
*
* #param key
* #return The String value of the property requested
*/
private String readPropertyRequired(String key) {
String value = readProperty(key);
if(StringUtils.isBlank(value)) {
throw new PropertyNotFoundException(key);
}
return value;
}
/**
* Helper method to return String values from the properties files that have been loaded
*
* #param key
* #return The String value of the property requested or NULL if empty
*/
private String readProperty(String key) {
return applicationProperties.getProperty(key);
}
/*** Getters & Setters ***/
#Autowired
public void setApplicationProperties(Properties applicationProperties) {
this.applicationProperties = applicationProperties;
}
public String getUserName() {
return readPropertyRequired(PROP_USER_NAME);
}
}
You can then unit test this class by simply injecting a standard java.util.Properties

Injecting values for static constants in Spring

In one of my classes there is a public static String member and I need set this value in the applicationContext.xml! That is, is it possible for us to inject a value for this static property?
yes there is an example on this link http://planproof-fool.blogspot.com/2010/03/spring-setting-static-fields.html
No, it's not possible to inject a value to a static field from your XML context.
If you can modify the class, you have the following simple choices:
remove the static modifier and add #Inject/#Autowire above the field
add a constructor/setter/init method.
Else, you can do it with Spring's Java configuration support.
An example:
The Demo class with the static field and a JUnit method that asserts that the Spring container injects the wanted value into the static field:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("test-context.xml")
public class Demo {
public static String fieldOne;
#Test
public void testStaticField() {
assertEquals("test", fieldOne);
}
}
Add the context namespace to your applicationContext and component-scan element:
<context:component-scan base-package="com.example" />
Add your bean with the static field like the this:
#Configuration
public class JavaConfig {
#Bean
public Demo demo() {
Demo.fieldOne = "test";
return new Demo();
}
}
In this case, the JavaConfig class must be in the com.example package as declared in the component-scan element.

Categories

Resources