To fix that, we can take a snapshot of system property keys:
final Properties systemProperties = System.getProperties()
final Set<String> keys = systemProperties.stringPropertyNames()
for (final String key : keys) {
System.out.println("key: " + key)
final String value = systemProperties.getProperty(key)
System.out.println("value: " + value) // value can be null!
}
Notice the value comment - while stringPropertyNames states set of keys in this property list where the key and its corresponding value are strings, the system property could have been changed in the meantime.
Why so much legwork?
System properties are an instance of java.util.Properties, and its methods getProperty, setProperty are thread-safe.
Unfortunately, Properties' entry set's iterator (which I had used in question) is not thread-safe:
If the map is modified while an iteration over the set is in progress (except through the iterator's own remove operation, or through the setValue operation on a map entry returned by the iterator) the results of the iteration are undefined
So actually when I was iterating over that map, some system property was modified (= that entry said was modified), which caused CME to be thrown.
This q&a pair also applies to any generic Properties usage - just system properties make it trickier, with ability to access them directly with statics such as java.lang.System.setProperty(String, String) - so controlling all accesses (especially in shared code) gets harder.
To fix that, we can take a snapshot of system property keys:
final Properties systemProperties = System.getProperties()
final Set<String> keys = systemProperties.stringPropertyNames()
for (final String key : keys) {
System.out.println("key: " + key)
final String value = systemProperties.getProperty(key)
System.out.println("value: " + value) // value can be null!
}
Notice the value comment - while stringPropertyNames states set of keys in this property list where the key and its corresponding value are strings, the system property could have been changed in the meantime.
Why so much legwork?
System properties are an instance of java.util.Properties, and its methods getProperty, setProperty are thread-safe.
Unfortunately, Properties' entry set's iterator (which I had used in question) is not thread-safe:
If the map is modified while an iteration over the set is in progress (except through the iterator's own remove operation, or through the setValue operation on a map entry returned by the iterator) the results of the iteration are undefined
So actually when I was iterating over that map, some system property was modified (= that entry said was modified), which caused CME to be thrown.
This q&a pair also applies to any generic Properties usage - just system properties make it trickier, with ability to access them directly with statics such as java.lang.System.setProperty(String, String) - so controlling all accesses (especially in shared code) gets harder.
You could wrap your properties in a ConcurrentHashMap so that any of your compound actions such as iteration, navigation, check-and-act, etc.. will be thread-safe.
e.g.
ConcurrentHashMap<String, String> props = new ConcurrentHashMap<>(
(Map<String, String>)(Object)System.getProperties());
for(Map.Entry<String, String> entry: props.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
Note that the iterators returned by the ConcurrentHashMap are weekly consistent, which means it may or may not reflect the changes to the collection after the construction of the iterator. If this is not what you wanted, you could use the Collections.synchronizedMap() instead, which pays some penalties in concurrency.
Videos
You can pass an InputStream to the Property, so your file can pretty much be anywhere, and called anything.
Properties properties = new Properties();
try {
properties.load(new FileInputStream("path/filename"));
} catch (IOException e) {
...
}
Iterate as:
for(String key : properties.stringPropertyNames()) {
String value = properties.getProperty(key);
System.out.println(key + " => " + value);
}
You can store the file anywhere you like. If you want to keep it in your jar file, you'll want to use
Class.getResourceAsStream()orClassLoader.getResourceAsStream()to access it. If it's on the file system it's slightly easier.Any extension is fine, although .properties is more common in my experience
Load the file using
Properties.load, passing in anInputStreamor aStreamReaderif you're using Java 6. (If you are using Java 6, I'd probably use UTF-8 and aReaderinstead of the default ISO-8859-1 encoding for a stream.)Iterate through it as you'd iterate through a normal
Hashtable(whichPropertiesderives from), e.g. usingkeySet(). Alternatively, you can use the enumeration returned bypropertyNames().
Actually if you need only to read properties from a file and not to use these properties in Spring's property placeholders, then the solution is simple
public class Test1 {
@Autowired
Properties props;
public void printProps() {
for(Entry<Object, Object> e : props.entrySet()) {
System.out.println(e);
}
}
...
<util:properties id="props" location="/spring.properties" />
The @Value mechanism works through the PropertyPlaceholderConfigurer which is in turn a BeanFactoryPostProcessor. The properties used by it are not exposed at runtime. See this previous answer of mine for a possible solution.
System properties are set on the Java command line using the
-Dpropertyname=valuesyntax. They can also be added at runtime usingSystem.setProperty(String key, String value)or via the variousSystem.getProperties().load()methods.
To get a specific system property you can useSystem.getProperty(String key)orSystem.getProperty(String key, String def).Environment variables are set in the OS, e.g. in Linux
export HOME=/Users/myusernameor on WindowsSET WINDIR=C:\Windowsetc, and, unlike properties, may not be set at runtime.
To get a specific environment variable you can useSystem.getenv(String name).
I think the difference between the two boils down to access. Environment variables are accessible by any process and Java system properties are only accessible by the process they are added to.
Also as Bohemian stated, env variables are set in the OS (however they 'can' be set through Java) and system properties are passed as command line options or set via setProperty().
keywordsList.addAll(Arrays.asList(prop.getProperty("keywordsList").split(","));
Should work.
Properties extends HashTable implements Map, so you can get all the keys as a Set<String> using keySet().
Any property value is a String. You can split the String given a delimiter.
If you're asking how to add that Object back into the Properties, the answer is "you can't". Properties uses a String key and a String value. If you want multi-map behavior (String key, List value), you'll have to implement your own.
You can use the -XshowSettings flag in the Hotspot JVM version 1.7 and up (not supported in 1.6):
java -XshowSettings:properties -version
OpenJDK has had support for this flag since late 2010.
Seen in http://marxsoftware.blogspot.de/2016/02/hotspot-jvm-XshowSettings.html
EDIT 14 Dec 2016
The Oracle JVM ships with the tool jcmd which allows you to see the flags present in a running JVM. See:
https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/tooldescr006.html
For this use case, you could use:
jcmd <pid> VM.system_properties
But there are also many other useful commands. For example:
jcmd <pid> VM.flags
jcmd <pid> VM.command_line
jcmd <pid> GC.run
You can use jps a tool that comes with the jdk. It can print out the system properties that were passed to a java process.
For example: On my system eclipse is running and
$ jps -v
outputs
6632 -Dosgi.requiredJavaVersion=1.6 -Xms1024m -Xmx2048m -XX:MaxPermSize=512m
jps is located in JDK_HOME/bin
EDIT
If you want all the properties use the jinfo tool that is also located in JDK_HOME/bin. To use it you must know the process id of the java process you want to get information from. E.g.
$ jinfo 6632
This tool also prints out the java.ext.dirs