properties at application level - java

I am currently having a properties file and I am loading this file in each class where there is a need to get the properties
static PropertiesConfiguration config = null;
config = new PropertiesConfiguration("Interface.properties");
This is working fine. But I know this is not the efficient way to load properties file multiple times.
Can anyone help me how to create the properties file at application level and create a java file (say config.java) + calling the method which returns the property.

One way to solve this is to utilize the dependency injection. You can have a singleton bean that holds the property instance and then you inject this bean as a dependency to each of your class that needs to access those properties.
One way to implement dependency injection to use the Spring framework. For instance, you can achieve loading the property file using Spring's PropertyPlaceHolderConfigurer. Then this bean becomes your reference bean for rest of the application. A tutorial on this can be found here.
Another choice for you is to load the property file in the constructor of the main entry class or the main method of your application and then pass the object to the classes that needs it. However, this will make your application more tightly coupled and maintenance would be harder in the future.
Another option is to create a singleton class that loads the properties and have a method that returns the values as needed.

I used this approach to set the properties at application level.
Define a properties file (say configure.properties).
Create a java class Config:
public class Config {
private static Config instance;
private PropertiesConfiguration configure;
private Config() throws ConfigurationException {
configure = new PropertiesConfiguration("configure.properties");
}
public static Config getInstance() {
if (null == instance) {
try {
instance = new Config();
} catch (ConfigurationException ex) {
throw new RuntimeException(ex);
}
}
return instance;
}
public PropertiesConfiguration getConfigure() {
return configure;
}
public void setConfig(PropertiesConfiguration configure) {
this.configure = configure;
}
}
This java class load the properties file at the startup and calls the getInstance method to get the value of the property. To get the value of the property anywhere else in the application import Config and
Config.getInstance().getConfig().getString("property.given.in.properties");
Sorry if variable names doesn't make much sense.
Thanks all for your input.

I just load my properties file in the System Properties:
public void loadStreamToSysProperties(InputStream in) throws IOException
{
Properties p = System.getProperties();
p.load(in);
}
Then I can get them out of System.getProperty where ever I am in the code.
In this example the InputStream is a Stream I created from the file name/path.

Related

Read Data from File in a Java Class Library Without Main Method

I have a set of Java console applications which act as my system's backend Services and which I package each into their own Jars. I also have written a class library (e.g. CoreLibrary) which consists of a set of classes and no main() execution method of it's own. This CoreLibrary is a dependency for each of these Services so I bundle The same CoreLibrary Jar into each of these Services Jars.
A number of classes in my CoreLibrary use some constant value(s) (configurations) for which I had defined a class like:
public class Config {
public static final String serverIP = "localhost:9092";
}
Now I want to shift this configuration into a config.json File like:
{
"serverIP" : "localhost:9092"
}
and access it through something like:
public class Config {
public static final String serverIP = getConfigValue();
private String getConfigValue()
{
try {
Reader reader = Files.newBufferedReader(pathToConfig);
CoreConfig item = gson.fromJson(reader, CoreConfig.class);
reader.close();
return item.getServerIP();
} catch (IOException e) {
e.printStackTrace();
return "localhost:9091";
}
}
}
Assuming that having a config file outside my application's Jar would allow me to change the file contents (values) each time before I run my Services Jars instead of going through the process of generating a Jar for each service every time I change this value. I also wouldn't want to load the value from the file from each Service but instead have the value loaded upon startup.
Is there a proper way to achieved this in Java (loading a value from a file from a class library on its own) ? and would it even be considered a valid code practice since item.getServerIP() may possibly produce NullPointerException if the file or json object couldn't be read ?
Note: I'm not using Spring or any such framework. It's plain Java 11 code and uses gson library.

Getting a SpringBoot property in a non-Spring class

I've got a number of properties defined in my application.properties file. These are loaded into a number of different configuration files across the system via #Configuration, #PropertySource, and #ConfigurationProperties annotations.
In addition, I have a library, separate from this system, that has no dependence on Spring (and ideally will stay that way). At some point in the execution of the system, it initializes an instance of a class from this library via reflection and a no args constructor. However, in that initialization, I want to get a Spring property and assign it to a local field - however, as I mentioned before, this library class is not spring configured, and is in fact in an entirely different project. How can this be done?
My current solution is that when the property is initialized in the config class, the setter for the property also sets a system property (via System.setProperty("someProp", propValue)), and then in the no args constructor of the library class I call System.getProperty("someProp"). However, this feels really hacky, particularly the part where I set the variable. Perhaps there is some way to configure SpringBoot to automatically propagate that particular property up to become a System property as well?
My code atm
ServiceConfig.class
#Configuration
#PropertySource("classpath:application.properties")
#ConfigurationProperties(prefix = "service")
public class ServiceConfig {
private String serviceUrl;
public String getServiceUrl() {
return serviceUrl;
}
public void setServiceUrl(String serviceUrl) {
this.serviceUrl = serviceUrl;
System.setProperty("SERVICE_URL", serviceUrl);
}
}
My application.properties
service.serviceUrl=http://localhost:8000
LibraryClass.class
public class LibraryClass {
private final String serviceUrl;
public LibraryClass() {
this.serviceUrl = getProperty("OAUTH_SERVICE_URL");
}
...
}
if your LibraryClass has a setter method - in the example below named setServiceUrl(...) - to set this configuration property you could add this to your existing ServiceConfig configuration class:
#Bean
public LibraryClass getLibraryClass(#Value(${"OAUTH_SERVICE_URL"}) String serviceUrl) {
LibraryClass libraryClass = new LibraryClass();
libraryClass.setServiceUrl(serviceUrl);
return libraryClass;
}
Other than that - if you cannot modify LibraryClass because it's parts of a 3rd party library or so... you could use Spring's Environment instance, to read all needed properties that - later - will be accessed inside of the constructor of LibraryClass and set them just the way you did as System properties. Also add this to your config class:
#Autowired
public void setSystemPropsNeededForLibraryClassConstruction(Environment environment) {
System.setProperty("serviceUrl", environent.getProperty("serviceUrl"));
}

Portable CDI extension to inject beans at runtime

Referencing this: http://docs.jboss.org/weld/reference/latest-master/en-US/html_single/#_the_literal_injectiontarget_literal_interface
Following the instructions from above, i am able to load SomeFrameworkComponent.class dynamically at runtime via some custom ClassLoader. It looks like this:
public class CustomClassLoader extends ClassLoader {
public CustomClassLoader() {
}
public Class defineClass(String location, byte[] classData, String name) {
java.nio.file.Path p = java.nio.file.Paths.get(location);
try {
return defineClass(name, Files.readAllBytes(p), 0, classData.length);
} catch (ClassFormatError | IOException e) {
e.printStackTrace();
}
return null;
}
}
After that i follow the steps exactly from 16.5. The InjectionTarget interface and it all works. However if i change the .class file and reload it, CDI will return the old one every time. The new class is correctly reloaded, because when i call newInstance() on the class returned from defineClass, it be an instance of the updated class as expected.
If i understand correctly, once a bean is registered, it is put (bound) in a Context, which is a container for beans. Subsequent requests for that bean will retrieve it from that container. And if i want to be able to destroy it at will or for every request get a new one from a new .class file, i will have to create a custom Context that will support this. Right?
If my assumptions are correct, then how do i specify programmatically my custom Context that the .class object is supposed to go?

Spring jUnit Testing properties file

I have a jUnit Test that has its own properties file(application-test.properties) and its spring config file(application-core-test.xml).
One of the method uses an object instantiated by spring config and that is a spring component. One of the members in the classes derives its value from application.properties which is our main properties file. While accessing this value through jUnit it is always null. I even tried changing the properties file to point to the actual properties file, but that doesnt seem to work.
Here is how I am accessing the properties file object
#Component
#PropertySource("classpath:application.properties")
public abstract class A {
#Value("${test.value}")
public String value;
public A(){
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
}
public A(String text) {
this();
// do something with text and value.. here is where I run into NPE
}
}
public class B extends A {
//addtnl code
private B() {
}
private B(String text) {
super(text)
}
}
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations={"classpath:META-INF/spring/application-core-test.xml",
"classpath:META-INF/spring/application-schedule-test.xml"})
#PropertySource("classpath:application-test.properties")
public class TestD {
#Value("${value.works}")
public String valueWorks;
#Test
public void testBlah() {
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
B b= new B("blah");
//...addtnl code
}
}
Firstly, application.properties in the #PropertySource should read application-test.properties if that's what the file is named (matching these things up matters):
#PropertySource("classpath:application-test.properties ")
That file should be under your /src/test/resources classpath (at the root).
I don't understand why you'd specify a dependency hard coded to a file called application-test.properties. Is that component only to be used in the test environment?
The normal thing to do is to have property files with the same name on different classpaths. You load one or the other depending on whether you are running your tests or not.
In a typically laid out application, you'd have:
src/test/resources/application.properties
and
src/main/resources/application.properties
And then inject it like this:
#PropertySource("classpath:application.properties")
The even better thing to do would be to expose that property file as a bean in your spring context and then inject that bean into any component that needs it. This way your code is not littered with references to application.properties and you can use anything you want as a source of properties. Here's an example: how to read properties file in spring project?
As for the testing, you should use from Spring 4.1 which will overwrite the properties defined in other places:
#TestPropertySource("classpath:application-test.properties")
Test property sources have higher precedence than those loaded from the operating system's environment or Java system properties as well as property sources added by the application like #PropertySource
I faced the same issue, spent too much calories searching for the right fix until I decided to settle down with file reading:
Properties configProps = new Properties();
InputStream iStream = new ClassPathResource("myapp-test.properties").getInputStream();
InputStream iStream = getConfigFile();
configProps.load(iStream);
If you are using a jar file inside a docker container, and the resource properties file, say application.properties is packaged within the same classes directory that contains the java(this is what IntelliJ IDE does automatically for resources file stored in /src/main/resources), this is what helped me:
public static Properties props = new Properties();
static {
try {
props.load(
Thread
.currentThread()
.getContextClassLoader()
.getResourceAsStream("application.properties")
);
} catch (Exception e) {
e.printStackTrace();
}
}
Most other methods either only worked inside the IDE or inside the Docker. This one works in both.
if you want to load a few properties, I found a good way in the spring
ReflectionTestUtils.
#Before
Public void setup(){
ReflectionTestUtils.setField(youclassobject, "value", "yourValue")
}
>you can follow this link as well for more details https://roytuts.com/mock-an- autowired-value-field-in-spring-with-junit-mockito/

How can I get my config file from class to class?

Just a quick and simple question. I have a program with several classes that read information off of a .properties file. Is it better practice to pass the file from class to class as an argument in the constructor, or open the file directly in each class?
If you're going to do this by hand, I would recommend you create a configuration class, that takes the file via the constructor, and reads the property values into member variables. Then every other class that needs configuration takes a Configuration class via it's constructor. However, almost no one does this, and instead uses a framework like spring, which handles property injection for you.
In spring, it would look something like this:
<!-- application context xml file -->
<context:property-placeholder location="file:///some/path/to/file" />
Then in your java classes:
public class SomeClass {
#Value("${some.property}")
private String someProp;
#Value("${some.other.prop}")
private Integer someOtherProp;
// ...
}
At application startup the properties get injected into your class.
My suggestion is to have a Util class which loads the properties file and get values from that Util to the required classes.
Note: I dont think you have any issues on loading the properties file.
I would suggest that you create an immutable class that takes in the file as a constructor argument and sets all the instance variables. I'd call it PropertyConfiguration. Then since the class is immutable, you won't have to worry about passing it to everyone. You could even have a class that holds it.
For example, the code below would set you up to have a nice set up to have several things available project wide. I would just ensure that anything that's shared be immutable to ensure thread safety.
public class ClientUtils {
private static ClientContext _clientContext = null;
public static void setClientContext(ClientContext cc) {
_clientContext = cc;
}
public static ClientContext getContext() {
return _clientContext;
}
}
public class ClientContext {
private final Configuration _configuration;
public ClientContext(Configuration config){
_configuration = config;
}
public Configuration getClientContext() {
return _configuration;
}
}
If your program contains data which need not be a part of compilation and can vary from deployment to deployment, you must add it to the properties file : ( Things like database connection string, email addresses ).
Just in case you need this, I'm adding the code for accessing the properties files.
Drop the file in build directory.
Properties properties = new Properties();
properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("credentials.properties"));

Categories