Properties file : Use key as variable - java

I want to use a key defined in properties file as a variable like this :
key1= value1
key2= value2
key3= key1
I try :
key3= {key1}
or
key3= ${key1}
But it dosn't work !
Any idea please ?

Java's built-in Properties class doesn't do what you're looking for.
But there are third-party libraries out there that do. Commons Configuration is one that I have used with some success. The PropertiesConfiguration class does exactly what you're looking for.
So you might have a file named my.properties that looks like this:
key1=value1
key2=Something and ${key1}
Code that uses this file might look like this:
CompositeConfiguration config = new CompositeConfiguration();
config.addConfiguration(new SystemConfiguration());
config.addConfiguration(new PropertiesConfiguration("my.properties"));
String myValue = config.getString("key2");
myValue will be "Something and value1".

When you define the value of a key in properties file, it will be parsed as literal value. So when you define key3= ${key1}, key3 will have value of "${key1}".
http://docs.oracle.com/javase/1.4.2/docs/api/java/util/Properties.html#load(java.io.InputStream)
I agree with csd, the plain configuration file may not be your choice. I prefer using Apache Ant ( http://ant.apache.org/ ), where you can do something like this:
<property name="src.dir" value="src"/>
<property name="conf.dir" value="conf" />
Then later when you want to use key 'src.dir', just call it something like this:
<dirset dir="${src.dir}"/>
Another good thing about using Apache Ant is you also can load the .properties file into Ant build file. Just import it like this:
<loadproperties srcFile="file.properties"/>

.xmlEven better: use the latest Maven.
You can do some neat stuff with maven. In this case you can make an .properties file with this lines in it:
key1 = ${src1.dir}
key2 = ${src1.dir}/${filename}
key3 = ${project.basedir}
in the maven's pom.xml file (placed in the root of your project) you should do something like this:
<resources>
<resource>
<filtering>true</filtering>
<directory>just-path-to-the-properties-file-without-it</directory>
<includes>
<include>file-name-to-be-filtered</include>
</includes>
</resource>
</resources>
...
<properties>
<src1.dir>/home/root</src1.dir>
<filename>some-file-name</filename>
</properties>
That way you would have keys values changed in build time, which means that after compiling you will have this values inside your properties file:
key1 = /home/root
key2 = /home/root/some-file-name
key3 = the-path-to-your-project
compile with this line when you are in the same dir as pom.xml file:
mvn clean install -DskipTests

Related

How to include all files in a directory while using maven-replacer-plugin?

I want to replace token value in all the files inside a specific directory (say dir1):
Few examples:
/dir1/helloworld.jsp
/dir1/dir2/sample.jsp
/dir1/dir2/dir3/produtinfo.jsp
/dir1/random/dir3/dir4/random.jsp
I tried using following configuration which does not seem to be working
<configuration>
<delimiters>
<delimiter>#</delimiter>
</delimiters>
<basedir>target/dir1</basedir>
<filesToInclude>*.jsp</filesToInclude>
<tokenValueMap>/usr/home/output.properties</tokenValueMap>
</configuration>
Am I missing something here?
Also, I have two properties something like
prop1.value=10
prop2.prop1.value=20
so this plugin replaces "sample text ${prop2.prop1.value}" with "sample text prop2.10". How do I fix this?
It should update it with "sample text 20" instead.
In short, I want to replace some property values present in all the jsp files present inside src/main/webapp/jsp while building maven project so if there are any alternatives, please feel free to suggest.

decode URL in ANT

I am developing an ANT build script that should be invoked via another application (the Oxygen XML editor). This application passes some properties, one of which is a path, encoded as an URL (note: I don't have control over this input; it just is an URL). For example, the property ${project.url} is assigned file:/F:/projectpath/. In my ANT script, I'm stripping the file:/ part to get a path I can use in ANT tasks like <mkdir dir="${project.path}/_temp/>.
Yet, this appears to be too simplistic for more complex URLs. Suppose the project path contains a space. Then the ${project.url} property will be assigned file:/F:/project%20path/. Just stripping out the 'file:/ part results in a path that is still problematic to ANT tasks. In this case, the URL encoded space character (%20) should be decoded again to a space for the <mkdir/> task above to work.
Of course, this problem isn't limited to spaces, but applies to all characters that will end up escaped in the encoded URL. Therefore, the URL should be properly decoded in order to be of use in ANT tasks.
Is there an easy way in ANT (preferably without ANT-contrib) to:
decode a URL
assign this decoded URL to another property
...so that, given the property ${project.url} with value file:/F:/project%20path/, I can derive another property ${project.path} with value F:/project path/?
You can always run a <script> task to set a variable, then use that variable later in your build.xml.
For example:
https://ant.apache.org/manual/Tasks/script.html
<script language="groovy">
xmlfiles = new java.io.File(".").listFiles().findAll{ it =~ "\.xml$"}
xmlfiles.sort().each { self.log(it.toString())}
</script>
FoggyDay's excellent suggestion has set me on the right path to solve my problem. I've defined a <scriptdef> task that can be used to:
decode URLs to paths, and
store them in properties that can be used in the ANT file.
I can't program Java, so I've resorted to JavaScript and used its decodeURIComponent() function. Since this task works as a counterpart of the <makeurl> ANT task, I've named it 'makepath'.
Here's a working sample build file:
<project>
<property name="project.url" value="file:/F:/project%20path"/>
<scriptdef name="makepath" language="javascript">
<attribute name="url"/>
<attribute name="property"/>
<![CDATA[
var decodedUrl = decodeURIComponent(attributes.get("url"));
var path = decodedUrl.replace(/^[^:]+:\/+/g, "");
self.project.setProperty( attributes.get("property"), path )
]]>
</scriptdef>
<makepath url="${project.url}" property="project.path"/>
<echo>$project.path: ${project.path}</echo>
</project>
Of course this is just an illustrative example (otherwise there wouldn't be much point in explicitly declaring a URL if you need a path). But when you don't have control over the value of the ${project.url} property (which in my case is passed via an external program), this seems a handy way to convert it to something useful for the ANT context.

Building a unified config.properties. What if there are multiple properties with the same key in a properties file in Java?

We have a situation where there are a dozen of files called config.properties in our build process:
config.properties.dev
config.properties.qa
config.properties.prod1
config.properties.prod2
Our current install process copies the config.properties for that environment to config.properties. (I'm not thrilled about this, but this is what I have to work with now.)
All of these files are exactly the same except for three or four properties. Unfortunately, these aren't always the same property across all of the files. What we'd like to do is setup a master config.properties like this:
Master config.properties
prop1 = value1
prop2 = value2
prop3 = value3
prop4 = value4
Then have a separate `config.properties for each environment that contains only the properties that differ from the master:
config.properties.prod:
prop3 = value3.1
prop4 = value4.1
config.properties.qa
prop2 = value2.1
prop3 = value3.2
We thought it might be possible to concatenate the two files together when we do a deployment:
cat config.properties.$env >> config.properties
And get a combined properties file this way:
Combined config.properties
prop1 = value1
prop2 = value2
prop3 = value3
prop4 = value4
prop2 = value2.1
prop3 = value3.2
Unfortunately, we don't know how Java handles such a file. Does it take the first defined property, or the last defined property, or is the behavior completely undefined?
If this won't work, what's the best way in a configuration script (which is usually a BASH script) to combine multiple properties into a single property file?
As #home mentioned, Properties is a Map, so last one (last in the file) wins.
However, it seems to me that it would be better to resolve the proper values while consolidating the files, so that the result has exactly one instance of each property. That way, once the properties file is in use, there will be no guessing.
How you resolve these is, of course, up to you.
You might also take a look at apache commons-configuration project. It has build in facilities to combine different configuration files.

How do generate a directory path with double-backslash or forward-slash separators?

I am writing a directory path to a text file from ant, which is later read by a Java Application to find another file.
In my ant script I have:
<property name="fulltrainer.dir" location="${trainer.dir}" />
<echo file="${trainer.dir}/properties/commonConfig.properties"># KEY VALUE
CurrentBuildFile=${fulltrainer.dir}\current_build</echo>
in the build.properties file trainer.dir is set to:
trainer.dir=../trainer
It ends up writing:
# KEY VALUE
CurrentBuildFile=C:\Workspaces\ralph\trainer\current_build
to the commonConfig.properties file.
I need it to write:
# KEY VALUE
CurrentBuildFile=C:\\Workspaces\\ralph\\trainer\\current_build
or, I need it to write:
# KEY VALUE
CurrentBuildFile=C:/Workspaces/ralph/trainer/current_build
How can I do that?
This looks a lot like this question: Ant produces jsfl with backslashes instead of slashes
So, try using the pathconvert task.
<pathconvert targetos="unix" property="fulltrainer.unix_dir">
<path location="${trainer.dir}"/>
</pathconvert>
<property name="cf.props" value="${trainer.dir}/properties/commonConfig.properties"/>
<echo file="${cf.props}" message="# KEY VALUE"/>
<echo file="${cf.props}" append="yes" message="CurrentBuildFile=${fulltrainer.unix_dir}/current_build"/>

Java "constant string too long" compile error. Only happens using Ant, not when using Eclipse

I have a few really long strings in one class for initializing user information. When I compile in Eclipse, I don't get any errors or warnings, and the resulting .jar runs fine.
Recently, I decided to create an ant build file to use. Whenever I compile the same class with ant, I get the "constant string too long" compile error. I've tried a number of ways to set the java compiler executable in ant to make sure that I'm using the exact same version as in Eclipse.
I'd rather figure out how to get the same successful compile I get in Eclipse in Ant than try to rework the code to dynamically concatenate the strings.
Someone is trying to send you a message :-) In the time you've spend fiddling with compiler versions you could have loaded the data from a text file - which is probably where it belongs.
Check out:
java.util.Properties
Apache Commons FileUtils.readFileToString()
I found I could use the apache commons lang StringUtils.join( Object[] ) method to solve this.
public static final String CONSTANT = org.apache.commons.lang.StringUtils.join( new String[] {
"This string is long",
"really long...",
"really, really LONG!!!"
} );
Nothing of above worked for me. I have created one text file with name test.txt and read this text file using below code
String content = new String(Files.readAllBytes(Paths.get("test.txt")));
The length of a string constant in a class file is limited to 2^16 bytes in UTF-8 encoding, this should not be dependent on the compiler used. Perhaps you are using a different character set in your ant file than in eclipse, so that some characters need more bytes than before. Please check the encoding attribute of your javac task.
A workaround is to chunk your string using new String() (yikes) or StringBuilder, e.g.
String CONSTANT = new String("first chunk")
+ new String("second chunk") + ...
+ new String("...");
Or
String CONSTANT = new StringBuilder("first chunk")
.append("second chunk")
.append("...")
.toString();
These can be viable options if you're producing this string e.g. from a code generator. The workaround documented in this answer where string literals are concatenated no longer works with Java 11
String theString2 = IOUtils.toString(new FileInputStream(new
File(rootDir + "/properties/filename.text")), "UTF-8");
Another trick, if I'm determined to put a long string in the source, is to avoid the compiler detecting it as a constant expression.
String dummyVar = "";
String longString = dummyVar +
"This string is long\n" +
"really long...\n" +
"really, really LONG!!!";
This worked for a while, but if you keep going too far the next problem is a stack overflow in the compiler. This describes the same problem and, if you're still determined, how to increase your stack - the problem seems to be the sheer size of the method now. Again this wasn't a problem in Eclipse.
I was able to resolve this issue in a similar way like Lukas Eder.
String testXML = "REALLY LONG STRING...............................";
textXML += "SECOND PART OF REALLY LONG STRING..........";
textXML += "THIRD PART OF REALLY LONG STRING............";
Just split it up and add it together;
Did you try this? Never tried it myself, but here is the relevant section:
Using the ant javac adapter
The Eclipse compiler can be used inside an Ant script using the javac adapter. In order to use the Eclipse compiler, you simply need to define the build.compiler property in your script. Here is a small example.
<?xml version="1.0" encoding="UTF-8"?>
<project name="compile" default="main" basedir="../.">
<property name="build.compiler" value="org.eclipse.jdt.core.JDTCompilerAdapter"/>
<property name="root" value="${basedir}/src"/>
<property name="destdir" value="d:/temp/bin" />
<target name="main">
<javac srcdir="${root}" destdir="${destdir}" debug="on" nowarn="on" extdirs="d:/extdirs" source="1.4">
<classpath>
<pathelement location="${basedir}/../org.eclipse.jdt.core/bin"/>
</classpath>
</javac>
</target>
</project>
I would really consider making your classes standards compatible. I believe the official limit is 65535, and the fact that Eclipse is more lenient is something that could change on you at the most inconvenient of times, and either way constantly having to get the project compiled with Eclipse can really start to limit you in too many ways.
Add your string to values/strings.xml than call getResources.getString(R.string.yourstring)
permanent solution would be for this is getting long string from file specially when you are writing test case in spring projects.
the below one worked for me
File resource = new ClassPathResource(
"data/employees.dat").getFile();
String employees = new String(
Files.readAllBytes(resource.toPath()));
You can try this,
public static final String CONSTANT = new StringBuilder("Your really long string").toString();

Categories