Difference between "get' VS "getProperty" - java

Properties myProp = new Properties();
myProp.put("material", "steel");
Properties prop1 = new Properties(myProp);
System.out.println(prop1.get("material") + ", " + prop1.getProperty("material"));
// outputs "null, steel"
Isn't get similar to getProperty in the sense that it returns the entries/attributes of
an Object? Why is it not returning 'steel' when using get?

get is inherited from Hashtable, and is declared to return Object.
getProperty is introduced by Properties, and is declared to return String.
Note thatgetProperty will consult the "defaults" properties which you can pass into the constructor for Properties; get won't. In most cases they'll return the same value though. In the example you've given, you are using a default backing properties:
prop1 doesn't directly contain an entry for "material", hence why get is returning null.
myProp does contain an entry for "material", so when you call prop1.getProperty("material"), it will find that it doesn't have it directly, and check in myProp instead, and find "steel" there.

A look at the docs shows that get is inherited, and returns Object whereas getProperty is a member of Properties and returns the String.
Seemingly they should return the same, however from the docs again:
If the key is not found in this property list, the default property list, and its defaults, recursively, are then checked.
So it is best to use getProperty as it will return the default if it is not found.

Your second Properties object (props or prop1?), has no properties added directly to it. It only uses myProp as defaults. So those values never get added to the backing HashMap. Properties.getProperty() doesn't find "material" in the backing HashMap so it can look in the defaults. But the inherited HashMap.get() only looks in the backing HashMap and not in the defaults that you passed into the constructor.

Related

Migration from JDK8 to JDK11 causing java.lang.UnsupportedOperationException

You you can see from the class name properties.stringPropertyNames() returns an Collections$UnmodifiableCollection. Unmodifiable means you can't add, insert, remove or change something on this collection
Now that you have explained what the type of properties is java.util.Properties the answer is clear. In Java 8, Properties.stringPropertyNames() returned a set whose modifiability was unspecified:
"Returns a set of keys in this property list where the key and its corresponding value are strings, including distinct keys in the default property list if a key of the same name has not already been found from the main properties list. Properties whose key or value is not of type String are omitted."
"The returned set is not backed by the Properties object. Changes to this Properties are not reflected in the set, or vice versa.".
In Java 11, it is specified to be unmodifiable.
"Returns an unmodifiable set of keys from this property list where the key and its corresponding value are strings, including distinct keys in the default property list if a key of the same name has not already been found from the main properties list. Properties whose key or value is not of type String are omitted."
"The returned set is not backed by this Properties object. Changes to this Properties object are not reflected in the returned set."
The change happened in Java 9. This is related to bug 8059361.
(This is was an incompatible change in the sense that it could break customers' code if they relied on being able to modify the returned set. However, that code was relying on unspecified behavior, so you could argue that it was broken already.)
As i understand correctly, you have unmodifiable set and you are tying to change it here
parameterNames.removeIf(s -> !s.startsWith(seq));
that's why you getting this error/exception.
Set<String> parameterNames = new HashSet<>(properties.stringPropertyNames());
This will create a new Set with same content which can be altered.

How to get boot class path in JDK 9 or later

I have a classloader application that reads the system property sun.boot.class.path
But I've found in the JDK 9's release note that this property has been removed.
System.getProperty("sun.boot.class.path"); // In JDK 9/10 this returns null
But I still want to retrieve this property value in JDK 10. How can it be done?
I'm expecting a value like the following:
/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/resources.jar:/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/rt.jar:/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/sunrsasign.jar:/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/jsse.jar:/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/jce.jar:/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/charsets.jar:/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/jfr.jar:/usr/lib/jvm/java-8-openjdk-amd64/jre/classes
FYI:
I don't want use the -Xbootclasspath option. Just need the path value.
Delete the boot. it should work like that :
System.getProperty("java.class.path")
To understand more :
The System class has two methods used to read system properties: getProperty and getProperties.
The System class has two different versions of getProperty. Both retrieve the value of the property named in the argument list. The simpler of the two getProperty methods takes a single argument, a property key For example, to get the value of path.separator, use the following statement:
System.getProperty("path.separator");
The getProperty method returns a string containing the value of the property. If the property does not exist, this version of getProperty returns null.
The other version of getProperty requires two String arguments: the first argument is the key to look up and the second argument is a default value to return if the key cannot be found or if it has no value. For example, the following invocation of getProperty looks up the System property called subliminal.message. This is not a valid system property, so instead of returning null, this method returns the default value provided as a second argument: "Buy StayPuft Marshmallows!"
System.getProperty("subliminal.message", "Buy StayPuft Marshmallows!");
The last method provided by the System class to access property values is the getProperties method, which returns a Properties object. This object contains a complete set of system property definitions.

Using Groovy for variable expansion in Java properties

I frequently use standard Java property files for configuring my Groovy applications. One feature I have been missing is the ability to use variables as part of the property value so they can be expand dynamically during use. I thought I could provide this functionality using the following design:
Use a special format to annotate the properties that should be expanded. I have chosen to enclose such templates in double exclamation marks (!!). These property values are essentially a template to be expanded with the local variables
Before using the properties in the application, use the groovy 'evaluate' method to expand application variables in the template
Re-assign the original property key to the new value before use
So, if I have a property file config.properties with properties like:
version=2.3
local_lib=!!${env['GROOVY_HOME']}/${configProps.getProperty('version')}/lib!!
The local_lib property will be expanded from the GROOVY_HOME environment variable and the version property value.
In my application, I have coded this as follows:
//Load the environment variables and configuration file
env=System.getenv()
configFile=new File('config.properties')
configProps= new Properties()
configProps.load(configFile.newDataInputStream())
//Replace configuration property values with their expanded equivalent
configProps.each{
//if a property value is a template we evaluate it
if (it.value.startsWith('!!')){
valTemplate=it.value.replace('!!','"')
it.value=evaluate(valTemplate)
}
}
//then we use the expanded property values
This seems to work. When I do
println configProps
I see that the value is expanded and not null
However, the getProperty method for the expanded property returns null.
assert configProps.getProperty('local_lib')=='C:\\DEVTOOLS\\groovy-2.4.7/2.3/lib'
| | |
| null false
[local_lib:C:\DEVTOOLS\groovy-2.4.7/2.3/lib, version:2.3]
What is causing this discrepancy? I would have expected to return the value shown in the property map.
Your local_lib value looks like a String, but it isn't. It is a GString, only lazily coerced to String as needed (like when printing out the configProps map value).
Thus, a little known effect of Properties.getProperty() takes effect here. When the actual map value is not a String, Properties.getProperty() returns null.
So, in order to get the desired behavior, you need to coerce the GString to String before you store the value in the property map. Like so:
it.value=evaluate(valTemplate).toString()
or
it.value=evaluate(valTemplate) as String
Then you should see the desired results downstream.

Multiple default values for collections with Jersey

I'm using Jersey and want a set that, when not added as a query param, defaults to a set containing more than one object.
I basically want this:
#DefaultValue("test1", "test2")
#QueryParam("test")
private Set<MyEnum> test;
to return a set containing the enums "test1" and "test2".
I'm having no problem getting a single default value to work but I would like multiple. The docs are a bit cryptical, is it possible?
According to this source from stackoverflow and the official documentation you can only do this by manually checking if the object is null then set the default value

Are Java system properties always non-null?

There are a couple of Java system properties, among them things like java.home and path.separator, user.home. The spec does not mention any formal promises on the existence of those values.
Especially I am interested in user.home. Does it always point to some existing path?
I think you can safely assume that all the properties in that list is always available in any recent (Oracle-provided) JVM.
However, a null check is more defensive, and not expensive in this case.
I've never seen user.home to be null or be incorrectly specified by default. However, keep in mind that users can override with -Duser.home=..., so you can't rely on it to point to an existing path.
The documentation you pointed out states
The getProperty method returns a string containing the value of the property. If the property does not exist, this version of getProperty returns null.
So if the property does not exist you get a null value
The spec says that user.home contains user home directory, it does not say it may contain null. I have no doubt that JVM guarantees that it is always set.
The default properties will differ depending on OS. There will be some keys for which no values are defined. On my machine I found user.variant and user.timezone without any values! Following is the code which will list down all the key value pairs:
Properties prop = System.getProperties();
Set<Object> set = prop.keySet();
Iterator<Object> itr = set.iterator();
while(itr.hasNext()){
Object obj = itr.next();
String propVal = System.getProperty(obj.toString());
System.out.println(obj.toString()+" = "+propVal);
}
}
Regarding your specific reference about user.home, it seems it defined most of the time. Check out this interesting post where people have posted the list of system properties on different machines.

Categories

Resources