Spring read property file outside the class path - java

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;
}

Related

Spring boot #Value NullPointerException

I'm writing a Spring Boot application and am trying to load some values from a properties file using the #Value annotation. However, the variables with this annotation remain null even though I believe they should get a value.
The files are located in src/main/resources/custom.propertes and src/main/java/MyClass.java.
(I have removed parts of the code that I believe are irrelevant from the snippets below)
MyClass.java
#Component
#PropertySource("classpath:custom.properties")
public class MyClass {
#Value("${my.property:default}")
private String myProperty;
public MyClass() {
System.out.println(myProperty); // throws NullPointerException
}
}
custom.properties
my.property=hello, world!
What should I do to ensure I can read the values from my property file?
Thanks!
#value will be invoked after the object is created. Since you are using the property inside the constructor hence it is not available.
You should be using constructor injection anyway. It makes testing your class easier.
public MyClass(#Value("${my.property:default}") String myProperty) {
System.out.println(myProperty); // doesn't throw NullPointerException
}
You are getting this error because you are initializing the class with new keyword. To solve this,
first you need to create the configuration class and under this class you need to create the bean of this class.
When you will call it by using bean then it will work..
My code:
#Component
#PropertySource("db.properties")
public class ConnectionFactory {
#Value("${jdbc.user}")
private String user;
#Value("${jdbc.password}")
private String password;
#Value("${jdbc.url}")
private String url;
Connection connection;
#Bean
public String init(){
return ("the value is: "+user);
}
My Config.class:
#Configuration
#ComponentScan
public class Config {
#Bean
public Testing testing() {
return new Testing();
}
#Bean
public ConnectionFactory connectionFactory() {
return new ConnectionFactory();
}
}
Calling it:
public static void main(String[] args) {
AnnotationConfigApplicationContext context= new AnnotationConfigApplicationContext(Config.class);
ConnectionFactory connectionFactory= context.getBean(ConnectionFactory.class);
System.out.println(connectionFactory.init());
}




How to use dependency-injection with SpringBootTest

I have an application that uses SpringBoot for dependency injection and the app works fine, but testing fails because #Autowired fields aren't being injected during tests.
#SpringBootApplication
public class ProcessorInterface {
protected final static Logger logger = Logger.getLogger( ProcessorInterface.class );
public static void main(String[] args) {
try {
SpringApplication.run(ProcessorInterfaceRunner.class, args);
} catch (Exception ex) {
logger.error("Error running ProcessorInterface", ex);
}
}
}
#Component
#Configuration
#ComponentScan
public class ProcessorInterfaceRunner implements CommandLineRunner {
protected final static Logger logger = Logger.getLogger( ProcessorInterface.class );
#Autowired
private RequestService requestService = null;
#Autowired
private ValidatorService validatorService = null;
#Override
public void run(String... args) throws Exception {
ESPOutTransaction outTransaction = null;
outTransaction = new ESPOutTransaction();
// initialize outTransaction fields
...
// done initializing outTransaction fields
if (validatorService.isValid(outTransaction)) {
System.out.println(requestService.getRequest(outTransaction));
} else {
System.out.println("Bad Data");
}
}
}
#Service
public class ESPRequestService implements RequestService<ESPOutTransaction> {
#Autowired
ValidatorService validatorService = null;
#Override
public String getRequest(ESPOutTransaction outTransaction) throws IllegalArgumentException {
if (!validatorService.isValid(outTransaction)) {
throw new IllegalArgumentException("Invalid parameters in transaction object. " + outTransaction.toString());
}
StringBuffer buff = new StringBuffer("create request XML");
buff.append("more XML");
return buff.toString();
}
}
#Service
public class ESPValidatorService implements ValidatorService {
private static org.apache.log4j.Logger logger = Logger.getLogger(ESPValidatorService.class);
// declare some constants for rules
private static final int MAX_LENGTH_XYZ = 3;
#Override
public boolean isValid(OutTransaction outTransaction) {
ESPOutTransaction espOutTransaction = (ESPOutTransaction)outTransaction;
boolean isValid = true;
if (espOutTransaction == null) {
logger.warn("espOutTransaction is NULL");
isValid = false;
} else {
// XYZ is required
if (espOutTransaction.getXYZ() == null) {
logger.warn("XYZis NULL\r\n" + espOutTransaction.toString());
isValid = false;
}
// XYZ max length = MAX_LENGTH_XYZ
if (espOutTransaction.getXYZ() != null && espOutTransaction.getPubCode().trim().length() > MAX_LENGTH_XYZ) {
logger.warn("XYZis too long (max length " + MAX_LENGTH_XYZ + ")\r\n" + espOutTransaction.toString());
isValid = false;
}
}
return isValid;
}
}
These all work and I get good output when I run the app. When I try to test it though, it fails because it can't find ESPValidatorService to inject into ESPRequestService
#RunWith(Suite.class)
#SuiteClasses({ ESPOutTransactionValidatorTest.class, ESPRequestTest.class })
public class AllTests {}
#RunWith(SpringRunner.class)
#SpringBootTest(classes = {ESPRequestService.class})
public class ESPRequestTest {
#Test
public void testGetRequest() {
ESPRequestService requestService = new ESPRequestService();
String XYZ = "XYZ";
ESPOutTransaction outTransaction = null;
outTransaction = new ESPOutTransaction();
outTransaction.setXYZ(XYZ);
String strRequest = "some expected request XML";
String request = requestService.getRequest(outTransaction);
assertEquals(request, strRequest);
}
}
#RunWith(SpringRunner.class)
#SpringBootTest(classes = ESPValidatorService.class)
public class ESPOutTransactionValidatorTest {
#Test
public void testIsValid() {
ESPValidatorService validatorService = new ESPValidatorService();
ESPOutTransaction outTransaction = null;
// test request = null
assertFalse(validatorService.isValid(outTransaction));
String XYZ = "XYZ";
outTransaction = new ESPOutTransaction();
outTransaction.setXYZ(XYZ);
// test all good
assertTrue(validatorService.isValid(outTransaction));
// test XYZ
outTransaction.setXYZ(null);
assertFalse(validatorService.isValid(outTransaction));
outTransaction.setXYZ("ABCD"); // too long
assertFalse(validatorService.isValid(outTransaction));
outTransaction.setXYZ(XYZ);
}
}
How can I get the unit tests to auto wire?
I see two problems :
1) you don't rely on Spring beans but you create instances with the new operator.
Instead of writing :
ESPRequestService requestService = new ESPRequestService();
you should let Spring inject the instance :
#Bean
ESPRequestService requestService;
2) The #SpringBootTest configuration is not correct.
In each test, you specified a very specific bean class in the classes attribute of #SpringBootTest :
#SpringBootTest(classes = ESPValidatorService.class)
public class ESPOutTransactionValidatorTest {
and
#SpringBootTest(classes = {ESPRequestService.class})
public class ESPRequestTest {
But classes attributes of #SpringBootTest serves to specify the annotated classes to use for loading an ApplicationContext.
The annotated classes to use for loading an ApplicationContext. Can
also be specified using #ContextConfiguration(classes=...). If no
explicit classes are defined the test will look for nested
#Configuration classes, before falling back to a
SpringBootConfiguration search.
So all configuration classes and beans of your application may not be discovered and loaded in the Spring container .
To be able to load all application beans during your tests, the most simple way is not specifying the classes attribute in the #SpringBootTest annotation :
#SpringBootTest
public class ESPRequestTest { ...}
It will look for a Spring bean that holds the #SpringBootConfiguration.
Ideally, it will found the #SpringBootApplication bean of your application.
If the package of the test class is located inside the package (or at a lower level) of the #SpringBootApplication class, it should be automatically discovered.
Otherwise the other way is specifying a configuration that will allow to load all required beans :
#SpringBootTest(classes = MySpringBootApplication.class)
public class ESPRequestTest { ...}

Spring: Use application property inside an autowired constructor that instantiate a final field

I've created the MCVE below. The service should get a message and replace the vowels with a predefined ugly.char coming from application.properties.
application.properties:
ugly.char=x
UglifyService.java:
public interface UglifyService {
String uglifyMessage(String message);
}
UglifyServiceImpl.java:
#Service
public class UglifyServiceImpl implements UglifyService {
#Value("${ugly.char}")
private char uglyCharFromAppProp;
private final char uglyChar;
#Autowired
public UglifyServiceImpl() {
this.uglyChar = uglyCharFromAppProp;
}
#Override
public String uglifyMessage(String message) {
return message.replaceAll("[aeiouAEIOU]", String.valueOf(uglyChar));
}
}
UglyCharController.java:
#Controller
public class UglyCharController {
private final UglifyService uglifyService;
#Autowired
public UglyCharController(UglifyService uglifyService) {
this.uglifyService = uglifyService;
}
#Value("${ugly.char}")
private char uglyChar;
#RequestMapping("/")
#ResponseBody
public String index() {
return "Usage: http://localhost:8080/some-message";
}
#GetMapping("/{message:.+}")
#ResponseBody
public String uglifyMessage(#PathVariable String message) {
String uglyMessage = uglifyService.uglifyMessage(message);
return "The ugly char is: '"+ uglyChar +"'." +
"<br>The uglifyed message is: "+ uglyMessage;
}
}
Application.java:
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
The problem is that, instead of replacing the vowels, the service is just removing them.
When requesting localhost:8080/mymessage the response should be mymxssxgx, but I am getting mymssg.
My questions are:
Why the service is not working as expected?
What would be the right way to make it work, considering that I would like the uglyChar to be final inside the singleton service and to come from application.properties?
Note: The service starts to work if I replace String.valueOf(uglyChar) with String.valueOf(uglyCharFromAppProp), but uglyChar would not be final, as I would like it to be.
When object is instantiated, first the constructor is executed and then the values of the properties are set and #Value is executed. For this reason the value of uglyChar does not have the value of the property.
You can do it with:
private final char uglyChar;
#Autowired
public UglifyServiceImpl(#Value("${ugly.char}") final char uglyCharFromAppProp){
this.uglyChar = uglyCharFromAppProp;
}

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.

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

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;
}
}

Categories

Resources