Reading config resource from relative path for a Java app - java

--myjar.jar
--config
----appconfig.xml
I'm trying create maven based java application which can read configuration file from a relative path config\appconfig.xml
The idea here is that, the configuration can be modified without recompiling the application.
My implementation is something like this:
#Service
public class JooxXmlConfigurationServiceImpl implements XmlConfigurationService {
#Value("${configuration.xml}")
private String path;
}
Where the value is fetched from a properties file that is uder src/main/java/app-defaults.properties
It works when the String path is defined as the complete address like: C:/myprojects/myapp/config/appconfig.xml
but I need to set the path to be something like config/appconfig.xml

Related

spring boot property with profile from dependency

Problem:
I have 3 parts in the software:
Client A service
Client B service
Target C service
I want to connect to C from A and B
I wrote a library with following setup:
/src/main/java/pkg.../TargetConnector.java
/src/main/java/pkg.../TargetConfig.java
/src/main/resources/application-dev.properties
/src/main/resources/application-tst.properties
/src/main/resources/application-prd.properties
My clients A and B both have there own sources and properties:
/src/main/java/pkg.../Client{A/B}Service.java
/src/main/java/pkg.../Client{A/B}Config.java
/src/main/resources/application-dev.properties
/src/main/resources/application-tst.properties
/src/main/resources/application-prd.properties
The properties of the Connector contains some login info for the service e.g.
target.url=https://....
target.usr=blablabla
target.key=mySHAkey
which is used in the TargetConfig to preconfigure the Connector e.g.
#Value("target.url")
String url;
#Value("target.usr")
String usr;
#Value("target.key")
String key;
#Bean
public TargetConnector connector() {
return new TargetConnector(url, usr, key);
}
Now when I use the connector jar in the client I can find the configuration via packagescan. The connector class is loaded but the problem is that it does not load the properties files.
Research
I found that multiple property files cannot have the same name (e.g. clients application-{profile}.properties clashes with the one from the connector), so I tried to rename application-{profile}.properties of the targetConnector to application-connector-{profile}.properties.
The properties whoever still do not get loaded, (which makes sense since I do not have a e.g connector-dev profile but my profile is simply named dev).
Furthermore, even if I try to explicitly load one of the property files from the connector with:
#PropertySource({"classpath*:application-connector-dev.properties"})
it cannot be found
Question
My question is actually 3 tiered:
How can I load a property file in a dependency jar at all?
How can I load the profiled version of the property file if the the properties file has a different name than application.properties? e.g. application-connector.properties
How can i combine the answers from question 1 and 2 to load the profiled version of the property in the jar?
If further explanation is needed, please ask.
Answer
I went for an approach as given in the accepted answer.
I Just created 3 configs for the dev, tst, prd profiles containing the values needed and annotated the config files with the correct profiles.
You are using #Configuration annotated class. Maybe you can have one per profile. Here you are an example:
#Configuration
#Profile("profileA")
#PropertySource({"classpath:application-profileA.properties"})
public class ConfigurationProfileA{
#Value("${target.url}")
String url;
#Value("${target.usr}")
String usr;
#Value("${target.key}")
String key;
#Bean
public TargetConnector connector() {
return new TargetConnector(url, usr, key);
}
}
Do the same for profile B (maybe you can structure this better but the key points here are the annotation #Profile("") and #PropertySource(""))
Once you have your config class, Spring will use the Configuration class you want by just filling -spring.profiles.active=profileA (or the name of the profile you have written in the #Profile("") annotation)
I think there is a typo in this line #PropertySource({"classpath*:application-connector-dev.properties"})
Please check by removing the asterik.
In order to run with a specific profile, you can run with option -spring.profiles.active=dev for example
If you don’t run with a profile, it will load the default profile in application.properties that you don’t seem to have.
Furthermore, an advice would be to always have an application.properties and put in it the common properties and the default values that you would override in other properties files.
Other mistake is how you assign properties with #Value annotation, you need to use #Value("${PROPERTY_FROM_PROPERTIES_FILE}")

load properties in mule munit

I have some placeholders in my flow. Values for these placeholders are specified in a properties file (in classpath). I am doing munit using java. Currently, these placeholders are not getting replaced by values in property file. Any idea how do I load this file while running munit?
My munit is like this:
Class MyClass extends FunctionalMunitSuite{
#Override
protected String getConfigResources() {
//try 1[gave give value pairs directly]: didnt worked
System.getProperties().put("prop.key", "value");
//try2[load prop files]:didn't worked
prop.load(this.getClass().getResourceAsStream("mypropertyfile.properties"));
System.setProperties(prop);
}
}
In Overriding getConfigResources() specify a test-config.xml which has your mock connector and context property placeholder of properties file. Store that test properties file in src/test/resources
#Override
protected String getConfigResources() {
return "mule-config-test.xml" + ",actual-flow-to-test.xml";
}
Inside mule-config-test.xml, define test property file like this:
<context:property-placeholder ignore-resource-not-found="true" location="wmo-mule-app.properties,wmo-mule-app-unit-test.properties" />
In this case, wmo-mule-app.properties is my actual app property file while wmo-mule-app-unit-test.properties is the over-riding unit-test property file. This unit-test property file will take precedence over wmo-mule-app.properties
Currently you might be having your files in /src/main/resources
try to put it in /src/test/resources

How to keep a jar file external but still use its classes in my Android project?

I need to have a jar file located in a main/assets directory within an Android project. It is important the jar file is located there.
With my main Android project is there a way to reference this jar file in my code and to use its classes?
To be clear I don't want to add the jar to the main project once compiled.
EDIT: I have tried the link below and it seems to load the Class file I've stated. But I'm strugging how to define constructor arguments for the dynamically loaded Class.
android-custom-class-loading-sample
EDIT2
Nearly there. I've confirmed the class is loaded from my classes.jar. I'm stuck instantiating it though.
On the licenseValidatorClazz.getConstructor line I get the error below. I'm guessing I'm missing something from my Interface file?
java.lang.NoSuchMethodException: [interface com.google.android.vending.licensing.Policy, interface com.google.android.vending.licensing.DeviceLimiter, interface com.google.android.vending.licensing.LicenseCheckerCallback, int, class java.lang.String, class java.lang.String]
public Class licenseValidatorClazz = null;
public LicenseValidator validator;
...
// Initialize the class loader with the secondary dex file.
DexClassLoader cl = new DexClassLoader(dexInternalStoragePath.getAbsolutePath(),
optimizedDexOutputPath.getAbsolutePath(),
null,
mContext.getClassLoader());
try {
// Load the library class from the class loader.
licenseValidatorClazz = cl.loadClass("com.google.android.vending.licensing.LicenseValidator");
validator = (LicenseValidator) licenseValidatorClazz.getConstructor(Policy.class,DeviceLimiter.class,LicenseCheckerCallback.class,int.class,String.class,String.class).newInstance(ddd, new NullDeviceLimiter(),
callback, generateNonce(), mPackageName, mVersionCode);
} catch (Exception exception) {
// Handle exception gracefully here.
exception.printStackTrace();
}
I have an Interface which contains the functions to pass to the loaded class.
public interface LicenseValidator
{
public LicenseCheckerCallback getCallback();
public int getNonce();
public String getPackageName();
public void verify(PublicKey publicKey, int responseCode, String signedData, String signature);
public void handleResponse(int response, ResponseData rawData);
public void handleApplicationError(int code);
public void handleInvalidResponse();
}
TO use an external jar to be associated with your application and use it during runtime, it needs to be in dalvik format since normal jars cannot work under dalvikVM.
Convert your files using the dx tool
using aapt cmd , add those classes.dex to your jar file.
Now this jar which contains files in dalvik format can be loaded into our project.
Here is a post which explains the procedure to accomplish it.
There are steps to accomplish this.
You have to make a copy of your JAR file into the private internal storage of your aplication.
Using the dx tool inside the android folder, you have to generate a classes.dex file associated with the JAR file. The dx tool will be at the location /android-sdks/build-tools/19.0.1 (this file is needed by the Dalvik VM, simply jar can not be read by the dalvik VM))
Using the aapt tool command which is also inside the same location, you have to add the classes.dex to the JAR file.
This JAR file could be loaded dynamically using DexClassLoader.
If you are making a JAR from any one your own library, you have to do this steps (1-4) every time when there is a change in your library source code. So you can automate this steps by creating a shell script(in Mac/Linux/Ubuntu) or batch scripts(in Windows). You can refere this link to understand how to write shell scripts.
Note : One situation for implementing this method is, when it is impossible to add the JAR files directly to the build path of core project and need to be loaded dynamically at run time. In normal cases the JAR files could be added to the build path.
please check this link for the detailed code and implementation.
How to load a jar file at runtime
Android: How to dynamically load classes from a JAR file?
Hope this helps!!
You should try out the Services API - java.util.ServiceLoader
You define a service interface and its implementations in your jar.
package com.my.project;
public interface MyService { ... }
public class MyServiceBarImpl implements MyService { ... }
public class MyServiceFooImpl implements MyService { ... }
Then you define the services contained within the jar file in the META-INF/services/ directory. For instance, in the file 'META-INF/services/com.my.project.MyService', you list the provider classes.
# Known MyService providers.
com.my.project.MyServiceBarImpl # The original implementation for handling "bar"s.
com.my.project.MyServiceFooImpl # A later implementation for "foo"s.
Then, in your main codebase, you can instantiate a MyService instance with the ServiceLoader:
for (MyService service : ServiceLoader.load(MyService.class)) {
//Perform some test to determine which is the right MyServiceImpl
//and then do something with the MyService instance
}
These examples are taken more-or-less straight from the API, although I've changed the package names to make them slightly less annoying to read.

How Or where Do I access my properties file

I have a properties file myprops.properties as follows:
Wsdl=someurl
UserName=user
UserPassword=pasword
Application=appName
And inside my controller I'm trying to access to set values in my service as follows
Properties prop = new Properties();
prop.load(new FileInputStream("resources/myprops.properties"));
myService.setWsdl(prop.getProperty("Wsdl"));
myService.setUserName(prop.getProperty("UserName"));
myService.setUserPassword(prop.getProperty("UserPassword"));
myService.setApplication(prop.getProperty("Application"));
my Issue is I just do not know what path to use. Its a Spring project if that makes any difference. and Idealy I would like to have the properties file in my "src/main/resources" folder
I realise this may be very simple to some but I have tried searching for the solution both here and on Google and I cannot seem to find a solution that has helped. I've tried moving the file around the project but cannot seem to figure it out
The Error I get is
java.io.FileNotFoundException: resources\drm.properties (The system cannot find the path specified)
any advice/explanation or even a link that clearly explains it would be great
well, src/main/resources are on the classpath, you just need to do.
Properties properties = PropertiesLoaderUtils.loadAllProperties("your properties file name");
If you are using spring, you could set your property placeholder.
<context:property-placeholder location="classpath:resources/myprops.properties" />
and in your beans you can inject the values from the properteis using the #Value annotation
#Autowired
public Foo(#Value("${Wsdl}") String wsdl) {
...
}
in the case above I used in the constructor, but its possible to use by Autowired field/setter.
So in your service you could have something like:
#Service
public class MyService {
private final String wsdl;
private final String username;
private final String password;
private final String application;
#Autowired
public MyService(
#Value("${Wsdl}") String wsdl,
#Value("${UserName}") String username,
#Value("${UserPassword}") String password,
#Value("${Application}") String application
) {
// set it to each field.
}
}
Given that src/main/resources is on the classpath, you could do:
Resource resource = new ClassPathResource("/myprops.properties");
Properties props = PropertiesLoaderUtils.loadProperties(resource);
Don't use a FileInputStream; use getResourceAsStream() to read it from the servlet context.
You can always count on mkyong. This is an example/tutorial on how to load and read property files.
http://www.mkyong.com/java/java-properties-file-examples/
This question should be marked as a duplicate:
Loading a properties file from Java package
How to use Java property files?
Load a property file in Java
Java Properties File not loading
Java NullPointerException on loading properties file
Not able to load properties file in Java

How do I read a .properties file without calling its absolute path

I have my .properties file in
com.someOtherpage
-somefolder
--theProperties.java `<--- This guy needs it`
com.somepackage
WEB-INF
-config
--project.properties `<--- Here is where he sits`
when deployed how can I call the properties file with out calling its absolute path like below
public class theProperties
{
private static Properties properties = new Properties();
public theProperties()
{
}
public String get(String attribute) throws Exception
{
//what do I need to set up to be able to call this file this way
//notice there is no '../../project.properties'
// -----
InputStream is = theProperties.class.getResourceAsStream("project.properties");
properties.load(is);
is.close();
return properties.getProperty(attribute);
}
}
The above isn't working, why?
If you put the properties file in the same package as the Class that reads it you specify its path relative to that class, that is if the properties file is in the exact same package as the class loading it you specify the path as project.properties.
If you put the properties file in the default package and the loading class isn't in the default package, you have to specify an absolute path like, /project.properties. Just a reminder no classes should be in the default class path as a general rule.
Either way, your properties file has to be on the classpath which yours isn't. In other words it has to be somewhere in WEB-INF/classes/.
A better solution, but more complex is to use Guice to inject properties and not write your own reader.
here is a nice explanation of how...
http://jaitechwriteups.blogspot.com/2007/01/how-to-read-properties-file-in-web.html
Assuming you want to avoid the absolute filepath, not the absolute path within the classpath, you need to do:
theProperties.class.getResourceAsStream("/WEB-INF/config/project.properties")
The forward slash at the front is important. Without it the path is relative to the loading class's package location.

Categories

Resources