What is the difference between a Hashtable and Properties? - java

What is the difference between a Hashtable and Properties?

Properties is a very specialized class that's designed to hold configuration and/or resources that are usually stored in some file.
It has several features that Hashtable doesn't have (and shouldn't have):
It supports reading and writing its content to a well-defined plain-text format (using load()/store())
It supports reading and writing its content to a well-defined XML-based format (using loadFromXML()/storeToXML())
It supports a default mechanism by providing another Properties instance at construction time.
It only supports String keys and values. While it is technically a Map<Object,Object> actually storing non-String keys or values is strongly discouraged and unsupported.
A Hashtable on the other hand is a general-purpose Map implementation (which is mostly replaced by the HashMap, however).

Properties is a subclass of Hashtable, and it is designed for string to string mappings. It also adds the ability to store the mapping into a text file, and read it back.

1.Properties is the subclass of Hashtable. It is more like a map which stores key value pair.
2.In properties both key and value are string
3.In properties we can store the key and value pair in a properties file .
4.Properties class has the ability to load and save the properties file while Hashtable doesn't have this method.
5.Properties files are mostly used to store configuration or localization data. They are used to externalize the data which is configurable to the application.

Related

Java object serializer which is based on field order

Does anyone know a reflection based Java object graph serializer, which stores the fields identified by field order instead name of the field? This is what I want to do:
load a JSON file with Jackson JSON deserializer
save it in binary format which doesn't contain the field names...
load the previously serialized object with the OBFUSCATED version of the application.
The serialized content won't be transferred to any other JVM. Excluding serialized POJOs from obfuscation is not an option for now.
Protostuff by default orders fields from top to bottom as defined in your pojo. You can additionally control the field number using annotations.
Note that the order is not guaranteed on some (non-sun) vms (especially dalvik).
Sun jdk6 or higher is recommended for guaranteed ordering.

Putting objects into java.util.Properties

I'm trying to understand why java.util.Properties was implemented in this way. It has two interfaces: getProperty/setProperty which only accepts strings, and put/get which accepts any object as a value. These two interfaces appear to be overlapping, so a string added with put() can be retrieved using getProperty().
There seems to be some problems with this weird hybrid interface. Putting an object that overrides a string property has the side-effect of clearing the string value, producing null as the getProperty result. Adding an integer, or some other value that has a simple string translation, might be misunderstood as being a real property value (but as a property it's always null).
My question is: Is there a real, practical reason for this? Or is it a half-baked implementation as I suspect?
Joshua Bloch mentions this explicitly in Effective Java
[from Chapter 4] In the case of Properties, the designers intended that only strings be allowed as keys and values, but direct access to the underlying Hashtable allows this invariant to be violated. Once this invariant is violated, it is no longer possible to use other parts of the Properties API (load and store). By the time this problem was discovered, it was too late to correct it because clients depended on the use of nonstring keys and values.
That text is in context of using composition over inheritance. He's basically using this as an example of when composition should be used instead of inheritance. If Properties wrapped a Map instead of extending one, it could have enforced the invarient of using String as keys and values.
So the answer is: It was an oversight.
Access to put and get is a result of Properties being an extension of Hashtable, and the two method should not be used (but cannot be hidden from implementation due to their public access in the superclass).
The Javadocs have a nice note about why you shouldn't use those methods, and should instead only use strings:
Because Properties inherits from Hashtable, the put and putAll methods can be applied to a Properties object. Their use is strongly discouraged as they allow the caller to insert entries whose keys or values are not Strings. The setProperty method should be used instead. If the store or save method is called on a "compromised" Properties object that contains a non-String key or value, the call will fail. Similarly, the call to the propertyNames or list method will fail if it is called on a "compromised" Properties object that contains a non-String key.
As #yshavit notes, it'd make more sense for Properties to extend Hashtable<String, String> than a hashtable of two objects, but this was likely a decision made to maintain backwards compatibility, as any programs using get/put with any non-String objects would have been broken by such a change.
Official documentations says
Because Properties inherits from Hashtable, the put and putAll methods can be applied to a Properties object. Their use is strongly discouraged as they allow the caller to insert entries whose keys or values are not Strings. The setProperty method should be used instead. If the store or save method is called on a "compromised" Properties object that contains a non-String key or value, the call will fail. Similarly, the call to the propertyNames or list method will fail if it is called on a "compromised" Properties object that contains a non-String key.
http://docs.oracle.com/javase/8/docs/api/java/util/Properties.html
From the Java Docs
Because Properties inherits from Hashtable, the put and putAll methods
can be applied to a Properties object. Their use is strongly
discouraged as they allow the caller to insert entries whose keys or
values are not Strings. The setProperty method should be used instead.
If the store or save method is called on a "compromised" Properties
object that contains a non-String key or value, the call will fail.
Similarly, the call to the propertyNames or list method will fail if
it is called on a "compromised" Properties object that contains a
non-String key.
Properties extends Hashtable, so you can use Properties anywhere you can use a Hashtable.
The Hashtable class is where the get() and put() functions are coming from.
put(key, value) and get(key) are remainders of a questionable decision to have Properties extend Hashtable back in the day. This behavior can't be changes since it will break backwards compatibility, but any half decent style guide, including the API documentation itself, will recommend to never use these methods.
As others have said, you're only supposed to use it for Strings. There are ways of serializing an object as a string and retrieving it, but obviously it's not meant for that. I understand that it's really annoying since its the closest you can get to a cross-platform way of saving and retrieving app data. As far as I know there's no official way to save things other than strings in a folder that is hidden from the user, despite the fact that most operating systems have appdata directories.

Serializing objects with changing class source code

Note: Due to the lack of questions like this on SO, I've decided to put one up myself as a Q&A
Serializing objects (using an ObjectOutputStream and an ObjectInputStream) is a method for storing an instance of a Java Object as data that can be later deserialized for use. This can cause problems and frustration when the Class used to deserialize the data does not remain the same (source-code changes; program updates).
So how can an Object be serialized and deserialized with an updated / downgraded version of a Class?
Here are a few common ways of serializing an object that can be deserialized in a backwards-compatible way.
1. Store the data in the JSON format using import and export methods designed to save all fields needed to recreate the instance. This can be made backwards-compatible by including a version key that allows for an update algorithm to be called if the version is too low. A common library for this is the Google Gson library which can represent Java objects in JSON as well as normally editing a JSON file.
2. Use the built-in java Properties class in a way similar to the method described above. Properties objects can be later stored using a stream (store()) written as a regular Java Properties file, or saved in XML (storeToXML()).
3. Sometimes simple objects can be easily represented with key-value pairs in a place where storing them in a JSON, XML, or Properties file is either too complicated or not neccessary (overkill one could say). In this case, an effective way of serializing the object could be using the ObjectOutputStream class to serialize a HashMap object containing key-value pairs where the key could be a String and the value could be an Object (HashMap<String,Object>). This allows for all of the object's fields to be stored as well as including a version key while providing much versatility.
Note: Although serializing an object using the ObjectOutputStream for persistence storage is normally considered bad convention, it can be used either way as long as the class' source code remains the same.
Also Note about versioning: Changes to a class can be safely made without disrupting deserialization using an ObjectOutputStream as long as they are a compatible change. As mentioned in the Versioning of Serializable Objects chapter of the Object Serialization Specification:
A compatible change is a change that does not affect the contract
between the class and its callers.

How to build a generic map that could hold various data types as values whose type is known only during runtime?

Some background: I'm modifying a class for an object that needs to hold properties which are added to it during runtime by the user. There is a list of property definitions that I've built in which each element contains a name for the property (unique) and its type (Stored in a String).
For an Example: "Name", "String" or "Year","int"
The challenge I'm facing now is translating this list to a map in which the name of the property is the key and the value variable type depends on what the user described. This map would hold the actual content of the properties described in the list (The content would be entered by the user on a later stage).
What would be the best way to deal with building this map using generics?
I would just use a java.util.Properties - that's exactly what it was designed for.
It has other convenience methods, like loading from a file, dumping to XML, and other things you would probably find very useful.
And while technically it extends Hashtable<Object,Object> that's mostly for backwards compatibility. The methods on it indicate the expected usage will be String inputs.

Storing ArrayList and HashMap using java.util.properties

How can I store an ArrayList and/or a HashMap variable using java.util.properties? If it's not possible what other class can I use to store application configuration?
If you just need to serialize your collections into Strings, I highly recommend XStream. It uses reflection to serialize a class into XML. There is documentation if the default behavior doesn't work for the class you want to serialize, but the following has worked for me every time so far:
XStream xstream = new XStream();
String xml = xstream.toXML(myObject);
MyClass deserializedObject = (MyClass)xstream.fromXML(xml);
assert deserializedObject.equals(myObject);
So... if "don't do that" doesn't work for you, then you need to encode the data somehow. One common technique is to prepend some string to the name of each element. For example if I have a map MyMap containing a->1, b->2, c->3, I might store in the properties file:
MyMap.a=1
MyMap.b=2
MyMap.c=3
For lists, you can do the same, just mapping indices to values. So if MyList contains {a,b,c}
MyList.0=a
MyList.1=b
MyList.2=c
This is a hack, and everything everyone else said is true. But sometimes you gotta do what you gotta do.
Properties is basically Map<String, String> meaning both key and value must be String objects. If you want more advanced configuration, you could go with Spring. Its an excellent framework and I use it in every project. Spring config files are extremely flexible.
java.util.Properties is only intended to be used with String keys and values. It does inherit the put() and putAll() methods from Hashtable, but it's rarely a good idea to use those to "cheat". Have you considered just storing your configuration information in a HashMap rather than a Properties object? You would have to customize the serialization a bit, but you're going to have to do that in any case as you can't take advantage of the default loading functionality of the Properties class.
Storing a HashMap would be easy, since each key and value in the Map can be represented by a corresponding key and value in the Properties object (see the setProperty method in Properties.
For the ArrayList you could do something similar, the keys would be the indexes and the values the items in the corresponding indexes.
In both cases, remember that a properties file only stores strings, so you'd have to devise a way to represent the keys and values in your objects as strings.

Categories