IllegalArgumentException: Invalid boolean value when injecting property to boolean in Spring - java

In Spring Boot I attempt to inject a boolean value to an instance variable from an enviroment property which is set (enabled=true).
#Value("${enabled}")
private boolean enabled;
However Spring cannot resolve this for some reason and reports:
Caused by: java.lang.IllegalArgumentException: Invalid boolean value [${enabled}]
It seems like it does not replace expression ${enabled} with the property value.
What needs to be set ? Why doesn't work this by default ?

For Spring-Boot you can find good reference here:
http://www.baeldung.com/properties-with-spring
For given someprops.properites file:
somevalue:true
Here is FAILING version:
#ContextConfiguration
#RunWith(SpringJUnit4ClassRunner.class)
#TestPropertySource( "/someprops.properties" )
public class FailingNg {
#Configuration
public static class Config {
}
#Value("${somevalue}")
private Boolean somevalue;
// Fails with context initializatoin java.lang.IllegalArgumentException: Invalid boolean value [${somevalue}]
#Test
public void test1() {
System.out.println("somevalue: " + somevalue);
}
}
Here is WORKING version:
#ContextConfiguration
#RunWith(SpringJUnit4ClassRunner.class)
public class WorkingOk {
#Configuration
public static class Config {
#Bean
public static PropertyPlaceholderConfigurer properties() {
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
Resource[] resources = new ClassPathResource[] {
new ClassPathResource( "someprops.properties" )
};
ppc.setLocations( resources );
ppc.setIgnoreUnresolvablePlaceholders( true );
return ppc;
}
}
#Value("${somevalue}")
private Boolean somevalue;
#Test
public void test1() {
System.out.println("somevalue: " + somevalue);
}
}

As mentioned in the comments, you are likely missing a PropertySourcesPlaceholderConfigurer bean definition. Here's an example of how to configure that within Java:
#Configuration
public class PropertyConfig {
private static final String PROPERTY_FILENAME = "app.properties"; // Change as needed.
/**
* This instance is necessary for Spring to load up the property file and allow access to
* it through the #Value(${propertyName}) annotation. Also note that this bean must be static
* in order to work properly with current Spring behavior.
*/
#Bean
public static PropertySourcesPlaceholderConfigurer properties() {
PropertySourcesPlaceholderConfigurer pspc = new PropertySourcesPlaceholderConfigurer();
Resource[] resources = new ClassPathResource[] { new ClassPathResource(PROPERTY_FILENAME) };
pspc.setLocations(resources);
pspc.setIgnoreUnresolvablePlaceholders(true);
return pspc;
}
}

Related

Failed to set value with application.properties

I'm trying a very simple code to inject a value from application.properties.
The value which is setted is the property name.
What's wrong with the code?
application.properties
set.browser = ie
public class A {
#Value("${set.browser}")
private String browser;
public A(){}
public void print(){
System.out.println(browser);
}
}
#Configuration
public class ABean {
#Bean
public A getA(){
return new A();
}
}
public class AMain {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(A.class);
A a = context.getBean(A.class);
a.print();
}
}
First of all your application is not spring boot application - you've just instanted spring context even without component scan. Secondly beacause of lack of component scan, your ABean is never created - your context has only A bean. To fix this you can create context from ABean:
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ABean.class);
Thirdly you didn't configured PropertySource (if your application was spring boot application, application.properties would be default property source and it wouldn't be needed):
#PropertySource("classpath:/application.properties")
#Configuration
class ABean {
#Bean
public A getA() {
return new A();
}
}

Spring read property file outside the class path

I have a property file located in tomcat folder.Im trying to read the propert file content as follow.but im getting null value for the property value.
file path has no any issue.
#ComponentScan(basePackages = "org.sakaiproject.log.api")
#Configuration
#PropertySource(name = "props", value = {
"file:/home/tomcat-sakai-7.0.55/sakai/local.properties",
"file:/home/tomcat-sakai-7.0.55/sakai/sakai.properties" })
public class SpringCryptoContext {
#Value("${aes.encryption.cipherString}")
private static String cyperString;
public SpringCryptoContext() {
}
public static void main(String[] args) throws Exception {
ApplicationContext context = new AnnotationConfigApplicationContext(
SpringCryptoContext.class);
System.out.println(cyperString);
}
}
Edit:
I created seperate class and load the properties as follow.
#Service
#PropertySource(name = "locations", value = {
"file:/home/nirmala/projects/iml/tomcat-sakai-7.0.55/sakai/local.properties",
"file:/home/nirmala/projects/iml/tomcat-sakai-7.0.55/sakai/sakai.properties" })
public class CryptoToolImpl implements CryptoTool {
private Cipher cipher = null;
private Key key = null;
#Value("${pii.encryption.cipherString}")
private String cipherString = "";
public static final Logger log = Logger.getLogger(CryptoToolImpl.class);
public IMLCryptoToolImpl() {
try {
fixKeyLength();
cipher = Cipher.getInstance(cipherString);
key = KMSKeyStoreSingleton.getInstance().getPrivateKey();
} catch (Exception e) {
log.error("Error in initializing CryptoToolImpl : "
+ e.getMessage());
}
}
#Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigDev() {
return new PropertySourcesPlaceholderConfigurer();
}
}
but i get the following error
Error in initializing CryptoToolImpl : Invalid transformation format:
Please add the following bean in your configuration class:-
//To resolve values using the #Value
#Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigDev() {
return new PropertySourcesPlaceholderConfigurer();
}
Update
static won't work in this case, you need to do the following:-
Add the following code:-
#Value("${aes.encryption.cipherString}")
private String cyperString;
public String getCypherString(){
return this.cyperString;
}
This is just an example, but static you are using because you are accessing it in the main method which is static and for accessing the variable, you marked it static
The issue is that the static variable is a class variable which is having no property when the code reaches at your line of System.out for the variable, At this time - spring is still doing internal initialization etc..
You are accessing/ using the variable as non spring framework while you are instantiating using spring. It has to be single way only
And I would suggest to have a separate class to load these variables into context, may be some class marked with #Component or more specifically #Service
Something below should help.
#Configuration
#PropertySources(value={
#PropertySource(value="file:${catalina.home}/sakai/local.properties"),
#PropertySource(value="file:${catalina.home}/sakai/sakai.properties")
})
public class SpringCryptoContext {
#Value("${aes.encryption.cipherString}")
private String cyperString;
}

How to read data from java properties file using Spring Boot

I have a spring boot application and I want to read some variable from my application.properties file. In fact below codes do that. But I think there is a good method for this alternative.
Properties prop = new Properties();
InputStream input = null;
try {
input = new FileInputStream("config.properties");
prop.load(input);
gMapReportUrl = prop.getProperty("gMapReportUrl");
} catch (IOException ex) {
ex.printStackTrace();
} finally {
...
}
You can use #PropertySource to externalize your configuration to a properties file. There is number of way to do get properties:
1.
Assign the property values to fields by using #Value with PropertySourcesPlaceholderConfigurer to resolve ${} in #Value:
#Configuration
#PropertySource("file:config.properties")
public class ApplicationConfiguration {
#Value("${gMapReportUrl}")
private String gMapReportUrl;
#Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigInDev() {
return new PropertySourcesPlaceholderConfigurer();
}
}
2.
Get the property values by using Environment:
#Configuration
#PropertySource("file:config.properties")
public class ApplicationConfiguration {
#Autowired
private Environment env;
public void foo() {
env.getProperty("gMapReportUrl");
}
}
Hope this can help
I have created following class
ConfigUtility.java
#Configuration
public class ConfigUtility {
#Autowired
private Environment env;
public String getProperty(String pPropertyKey) {
return env.getProperty(pPropertyKey);
}
}
and called as follow to get application.properties value
myclass.java
#Autowired
private ConfigUtility configUtil;
public AppResponse getDetails() {
AppResponse response = new AppResponse();
String email = configUtil.getProperty("emailid");
return response;
}
application.properties
emailid=sunny#domain.com
unit tested, working as expected...
i would suggest the following way:
#PropertySource(ignoreResourceNotFound = true, value = "classpath:otherprops.properties")
#Controller
public class ClassA {
#Value("${myName}")
private String name;
#RequestMapping(value = "/xyz")
#ResponseBody
public void getName(){
System.out.println(name);
}
}
Here your new properties file name is "otherprops.properties" and the property name is "myName". This is the simplest implementation to access properties file in spring boot version 1.5.8.

Cannot access properties

I got a Spring MVC application. It runs over the Tomcat 7 server.
I want to make a props.properties file, so my app could access properties during Beans initialization process.
So i did the following:
1.Create a context-parameter to my web.xml
<context-param>
<param-name>mainProps</param-name>
<param-value>${catalina.home}/conf/props.properties</param-value>
</context-param>
2. I created a MainCobfig class
#Configuration
#PropertySource("classpath:/racoonsoft/wish/properties/props.properties")
#Import({WebConfig.class })
public class MainConfig {
#Autowired
Environment env;
#Value("${db.host}")
static String dbHost;
#Value("${db.name}")
static String dbName;
#Value("${db.login}")
static String dbLogin;
#Value("${db.password}")
static String dbPassword;
#Value("${ozon.login}")
static String ozonLogin;
#Value("${ozon.password}")
static String ozonPassword;
#Value("${ozon.apiurl}")
static String ozonApiUrl;
#Value("${payture.apihost}")
static String paytureApiHost;
#Value("${payture.merchant}")
static String paytureMerchant;
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
#Bean
public ScheduledAnnotationBeanPostProcessor scheduledAnnotationBeanPostProcessor() {
return new ScheduledAnnotationBeanPostProcessor();
}
#Bean
public OzonProcessor apiProcessor() {
return new OzonProcessor(ozonLogin, ozonPassword, ozonApiUrl);
}
#Bean
public PGSQLDataSource pgsqlDataSource() throws Exception{
PGSQLDataSource result = new PGSQLDataSource(dbHost,dbName,5432,dbLogin,dbPassword,"org.postgresql.Driver","jdbc:postgresql:");
result.loadSettings();
if(FacebookController.dbProc==null)
{
FacebookController.dbProc = result;
}
//FacebookController.dbProc = result;
return result;
}
#Bean
public PaytureProcessor paytureProcessor()
{
PaytureProcessor proc = new PaytureProcessor(paytureApiHost,paytureMerchant);
return proc;
}
}
3 - I created props.properties file and put it into /conf directory
When i start my application it didnt throw the exception (file not found) - so i beleave it sees the properties file. But during bean initialization my fields (dbHost,dbLogin etc.) are still null`s.
How can i put values from properties file to my fields?
Help me please.
The annotated factory method of PropertySourcesPlaceholderConfigurer MUST be a static method:
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
Spring API Reference manual of #Bean remarks this.
A little bit more detailed explanation:
This is because PropertySourcesPlaceholderConfigurer is a BeanFactoryPostProcessor (BFPP).
BFPP does a post-processing on the bean factory just before other (normal) beans are being instantiated and intialized. So, BFPP's are needed to be created in order to work, before the MainConfig bean is instantiated. Marking this factory method as a static method, we can invoke this method without instantiating MainConfig.
# form user login properties
userName.required = User Name is required
In controller side you declare only userName.required. That's how you declare it.

classpath wildcard in #PropertySource

I am using Spring Java config to create my bean.
But this bean is common to 2 applications.
Both have one property file abc.properties but with different classpath locations.
When i put explicit classpath like
#PropertySource("classpath:/app1/abc.properties")
then it works but when i try to use wildcard like
#PropertySource("classpath:/**/abc.properties")
then it doesn't work.
I try many combinations of wildcard but it still not working.
Is wildcard works in #ProeprtySource
Is there any other way to read to property in classed marked with #Configurations.
#PropertySource API: Resource location wildcards (e.g. **/*.properties) are not permitted; each location must evaluate to exactly one .properties resource.
workaround: try
#Configuration
public class Test {
#Bean
public PropertyPlaceholderConfigurer getPropertyPlaceholderConfigurer()
throws IOException {
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
ppc.setLocations(new PathMatchingResourcePatternResolver().getResources("classpath:/**/abc.properties"));
return ppc;
}
Addidtionally to dmay workaround:
Since Spring 3.1 PropertySourcesPlaceholderConfigurer should be used preferentially over PropertyPlaceholderConfigurer and the bean should be static.
#Configuration
public class PropertiesConfig {
#Bean
public static PropertySourcesPlaceholderConfigurer placeHolderConfigurer() {
PropertySourcesPlaceholderConfigurer propertyConfigurer = new PropertySourcesPlaceholderConfigurer();
propertyConfigurer.setLocations(new PathMatchingResourcePatternResolver().getResources("classpath:/**/abc.properties"));
return propertyConfigurer;
}
}
If you're using YAML properties, this can be achieved using a custom PropertySourceFactory:
public class YamlPropertySourceFactory implements PropertySourceFactory {
private static final Logger logger = LoggerFactory.getLogger(YamlPropertySourceFactory.class);
#Override
#NonNull
public PropertySource<?> createPropertySource(
#Nullable String name,
#NonNull EncodedResource encodedResource
) {
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
String path = ((ClassPathResource) encodedResource.getResource()).getPath();
String filename = encodedResource.getResource().getFilename();
Properties properties;
try {
factory.setResources(
new PathMatchingResourcePatternResolver().getResources(path)
);
properties = Optional.ofNullable(factory.getObject()).orElseGet(Properties::new);
return new PropertiesPropertySource(filename, properties);
} catch (Exception e) {
logger.error("Properties not configured correctly for {}", path, e);
return new PropertiesPropertySource(filename, new Properties());
}
}
}
Usage:
#PropertySource(value = "classpath:**/props.yaml", factory = YamlPropertySourceFactory.class)
#SpringBootApplication
public class MyApplication {
// ...
}

Categories

Resources