I need to expand environment variables in a string. For example, when parsing a config file, I want to be able to read this...
statsFile=${APP_LOG_DIR}/app.stats
And get a value of "/logs/myapp/app.stats", where the environment variable APP_LOG_DIR = "/logs/myapp".
This seems like a very common need, and things like the Logback framework do this for their own config files, but I have not found a canonical way of doing this for my own config files.
Notes:
This is not a duplicate of the many "variable interpolation in java strings" questions. I need to interpolate environment variables in the specific format ${ENV_VAR}.
The same question was asked here, Expand env variables in String, but the answer requires the Spring framework, and I don't want to pull in this huge dependency just to do this one simple task.
Other languages, like go, have a simple built-in function for this: Interpolate a string with bash-like environment variables references. I am looking for something similar in java.
Answering my own question. Thanks to clues from #radulfr's link in the comments above to Expand environment variables in text, I found a pretty clean solution, using StrSubstitutor, here: https://dkbalachandar.wordpress.com/2017/10/13/how-to-use-strsubstitutor/
To summarize:
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.text.StrLookup;
import org.apache.commons.lang3.text.StrSubstitutor;
public class StrSubstitutorMain {
private static final StrSubstitutor envPropertyResolver = new StrSubstitutor(new EnvLookUp());
public static void main(String[] args) {
String sample = "LANG: ${LANG}";
//LANG: en_US.UTF-8
System.out.println(envPropertyResolver.replace(sample));
}
private static class EnvLookUp extends StrLookup {
#Override
public String lookup(String key) {
String value = System.getenv(key);
if (StringUtils.isBlank(value)) {
throw new IllegalArgumentException("key" + key + "is not found in the env variables");
}
return value;
}
}
}
as of 2022, both StrLookup and StrSubstitutor are deprecated
so I update #sagebrush’s answer:
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lookup.StringLookup;
import org.apache.commons.text.StringSubstitutor;
public class StrSubstitutorMain {
private static final StringSubstitutor envPropertyResolver = new StringSubstitutor(new EnvLookUp());
public static void main(String[] args) {
String sample = "LANG: ${LANG}";
//LANG: en_US.UTF-8
System.out.println(envPropertyResolver.replace(sample));
}
private static class EnvLookUp implements StringLookup {
#Override
public String lookup(String key) {
String value = System.getenv(key);
if (StringUtils.isBlank(value)) {
throw new IllegalArgumentException("key" + key + "is not found in the env variables");
}
return value;
}
}
}
Related
I got a class Config wich looks like that:
public Class Config {
public static int someIntValue = 0;
public static String someText = "some text";
}
What i want to do now is saving and loading that config and there is also that inital config if there is no need to load another. So the config can change at any point in the programm.
What i came up with was a Singelton like pattern
public Class Config {
public static Config instance;
private int someIntValue = 0;
private int String someText = "some text";
public static Config getInstance(){
if(instance == null)
instance = new Config();
return instance;
}
public void setInstance(Config config){
this.instance = config;
}
//getter/setter
...
}
But in the end it doesnt look like the best approach and im not quite happy with it :/
Maybe you guys can help me out with a usual / "best practice" way to do that.
Best Regards
Made
I would just use java.util.Properties, or some wrapper around it. Another good approach is java bean and something like xstream to save/load stuff.
Usually in Java for configuration use properties files. And then use ResuorseBundle for reading properties.
Your "singleton" is not a Singleton in the conventional sense.
1) Field instance must be private
2) Remove SetInstance method
3) And you should make your singleton thread safe.
If you'd consider avoiding writing the boilerplate code around java.util.Properties, you can have a look at something that does it for you: OWNER API.
It's configurable to tailor your needs and it offers some additional neat features if compared to java.util.Properties (read the docs).
Example. You define an interface with your configuration parameters:
public interface ServerConfig extends Config {
int port();
String hostname();
#DefaultValue("42")
int maxThreads();
#DefaultValue("1.0")
String version();
}
Then you use it like this:
public class MyApp {
private static ServerConfig cfg = ConfigFactory.create(ServerConfig.class);
private MainWindow window;
public MyApp() {
// you can pass the cfg object as dependency, example:
window = new MainWindow(cfg);
}
public void start() {
window.show();
}
public static void main(String[] args) {
// you can use it directly, example:
System.out.println("MyApp version " + cfg.version() + " copyright (c) ACME corp.");
MyApp app = new MyApp();
app.start();
}
}
You can define the cfg object as member instance on the classes where you need, or you can pass the instance to constructors and methods where you need it.
Version 1.0.4 will be released soon and it will include also "hot reload" and many improvements.
I am new to accessing DLLs from Java using JNA. I need to access methods from a class within a DLL(written in .net). Form this sample DLL below, I am trying to get AuditID and Server ID. I am ending with the following error while I am running my code. Any guidance really appreciated.
/// Error ///
Exception in thread "main" java.lang.UnsatisfiedLinkError: Error looking up function 'GetEnrollcontext': The specified procedure could not be found.
//DLL File Code//
SampleDLL.ProfileEnroll enrollcontext = new SampleDLL.ProfileEnroll();
enrollcontext.Url =” url”;
enrollcontext.AuditIdType = SampleDLL.ProfileId;
enrollcontext.AuditId = “22222222 “;
enrollcontext.ServerId = “server1”;
/// Java Code ///
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Structure;
import dllExtract.DLLExtractTest.SampleDLL.Enrollcontext;
public class SampleDLLExtract {
public interface SampleDLL extends Library {
SampleDLL INSTANCE = (SampleDLL) Native.loadLibrary("SampleDLL",
SampleDLL.class);
public static class Enrollcontext extends Structure {
public String auditId;
public String serverId;
}
void GetEnrollcontext(Enrollcontext ec); // void ();
}
public static void main(String[] args) {
SampleDLL sdll = SampleDLL.INSTANCE;
SampleDLL.Enrollcontext enrollContext = new SampleDLL.Enrollcontext();
sdll.GetEnrollcontext(enrollContext);
System.out.println(sdll.toString(sdll.GetEnrollcontext(enrollContext)));
}
}
in fact there is a solution for you to use C#, VB.NET or F# code via JNA in Java (and nothing else)! and it is also very easy to use:
https://www.nuget.org/packages/UnmanagedExports
with this package all you need to do is, add [RGiesecke.DllExport.DllExport] to your methods like that:
C# .dll Project:
[RGiesecke.DllExport.DllExport]
public static String yourFunction(String yourParameter)
{
return "CSharp String";
}
Java Project:
public interface jna extends Library {
jna INSTANCE = (jna) Native.loadLibrary("yourCSharpProject.dll", jna.class);
public String yourFunction(String yourParameter);
}
use it in the code:
System.out.println(jna.INSTANCE.yourFunction("nothingImportant"));
Viola!
As already mentioned it works very easy, but this solution has some limitations:
only available for simple datatypes as parameter & return values
no MethodOverloading available. yourFunction(String yourParameter) and yourFunction(String yourParameter, String yourSecondParameter) does not work! you have to name them differently
Use arrays as parameter or return values. (JNA offers StringArray, but I am not able to use them in C#) (maybe there is a solution, but I couldn't come up with one so far!)
if you export a method you can't call it internally in your C# code (simple to bypass that by the following:
.
[RGiesecke.DllExport.DllExport]
public static Boolean externalAvailable(String yourParameter)
{
return yourInternalFunction(yourParameter);
}
With C# it works great, with VB.NET and F# I have no experience.
hope this helps!
I'm building a Swing application in Java and I want the colours to be consistent. So I could do something like:
public class Colours {
public static final String BACKGROUND = "#D9DADE";
}
But then I thought maybe an enum would be better, so I did this:
public enum ColourStyles {
BACKGROUND("#D9DADE");
private String colourValue;
private ColourStyles(String value) {
colourValue = value;
}
public String getColourValue() {
return colourValue;
}
};
But then that made the String now a ColourStyle type and I can't decode it using Color.decode(BACKGROUND).
Is there any better way of doing this completely, like a properties file? I've done Wicket but never come across the same sort of structure for labels/colours in Swing.
Thanks!
The 2 options are good, but i'd prefer a 3rd way and it's using a property file. So you don't have to recompile your application if you want to change.
1st)
public final class Colours {
private Colours(){}
public static final BACKGROUND = "#D9DADE";
}
.
2nd) It's ok, but you can add a method to the enum to return the color.
public enum ColourStyles {
BACKGROUND("#D9DADE");
private String colourValue;
private ColourStyles(String value) {
colourValue = value;
}
public String getColourValue() {
return colourValue;
}
public Color getColour(){
return Color.decode(colourValue);
}
}
And 3rd) create a file for example lookAndFeel.properties
colour.background=#D9DADE
Make a class that could be a singleton to load the properties file and you can add a util method to return the colour like in the enum, the good thing of this is that you can change the values wihout compiling again your application.
4th) If you are using a customizable look&feel you can set that properties using UIManager.put(); to set properties for all components. Here is an example of properties for Nimbus L&F Nimbus defaults
I was wondering if there is a better way to have a point to PATH in a properties file. Consider the following code:
public class Properties
{
//MIKE
public final static String PATH_TO_FILE_A = "C:\\programmer_MIKE\fileA.txt";
public final static String PATH_TO_FILE_B = "C:\\programmer_MIKE\fileB.txt";
//BILL
//public final static String PATH_TO_FILE_A = "/Users/BILL/Desktop/fileA.txt";
//public final static String PATH_TO_FILE_B = "/Users/BILL/Desktop/fileB.txt";
}
when any developer need to invoke FILE_A he simply does:
File file = new File(Properties.PATH_TO_FILE_A);
this works ok for BILL if he commented out MIKE's PATH_TO_FILE_A.
Q: is there a better design? If BILL committed his work including the Properties file - he will cause a problem to MIKE (no worries, he'll get a Coffee Latte later on).
the FILES are big (2-4Gb) and we don't want to put them in our repository (svn) and sometimes there are simply temporary folder to create a PDF so we don't want to put them in a "./docs" path.
Thanks for any pointer!
If for whatever reason you really must have hardcoded paths, then you could store them in some kind of map indexed by username. Something like:
public class Properties {
private static Map<String, DeveloperPaths> properties = create();
private static Map<String, DeveloperPaths> create() {
Map<String, DeveloperPaths> properties = new HashMap<String, DeveloperPaths>();
properties.put("mike", new DeveloperPaths(
"C:\\programmer_MIKE\fileA.txt",
"C:\\programmer_MIKE\fileB.txt")
);
properties.put("bill", new DeveloperPaths(
"/Users/BILL/Desktop/fileA.txt",
"/Users/BILL/Desktop/fileB.txt")
);
return properties;
}
public static File FileA()
{
String user = System.getProperty("user.name");
return properties.get(user).fileA;
}
public static File FileB()
{
String user = System.getProperty("user.name");
return properties.get(user).fileB;
}
}
class DeveloperPaths {
public File fileA;
public File fileB;
public DeveloperPaths(String pathA, String pathB) {
fileA = new File(pathA);
fileB = new File(pathB);
}
}
Then, the code to access each path would be identical regardless of developer, for example:
File myFile = Properties.fileA();
Normally paths are configurable entites and should be stored in property file.
Property files has a build in support in java and it uses Properties object for storing that information.
You can read the property file at startup or init (or similar) method of your application and read the proeprties from property file. This will make your configuration dynamic and anyone would be able to change it.
You can create a static method and call it on startup like:
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class GetProperties {
public static Properties prop = new Properties();
public static void init() {
InputStream inputStream = GetProperties.class.getClassLoader().getResourceAsStream("application.properties");
try {
prop.load(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
}
Things like this should be configured externally and/or passed in via parameter, system parameter, or environment variable. Alternatively you could use DI/IoC, but when there's no attached behavior, IMO a config value is plenty.
It's fine to have a hard-coded default, but otherwise stuff like this doesn't belong in code.
I have set of classes and (struts)jsp files which uses Message bundle. I want to find properties which are not used in project.One simple way would to search for each property (in given project) and if 0 result, delete it.
In eclipse there is a function like
Source > Find Broken Externalized Strings
I don't think it works. Not sure what its for. I get message
"no nls property files with corresponding accessor of class found in selection"
It seems like Eclipse expects to find the class that it generates in the "Externalize Strings..." command:
package com.foo.bar;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
public class Messages {
private static final String BUNDLE_NAME = "com.foo.bar.messages"; //$NON-NLS-1$
private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle.getBundle(BUNDLE_NAME);
private Messages() {
}
public static String getString(String key) {
try {
return RESOURCE_BUNDLE.getString(key);
} catch (MissingResourceException e) {
return '!' + key + '!';
}
}
}
Actually, after digging a little deeper, I found that Eclipse really wants the following:
private static final String BUNDLE_NAME = "com.foo.bar.messages"; //$NON-NLS-1$
public static String getString(String key) {
...
}
The package "com.foo.bar" must contain the file "messages.properties". You can run "Find Broken Externalized Strings" on any source file (or on the package) that you add these lines to.