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.
Related
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.
Is it possible to make ObjectMapper convert only the actual object without converting the rest of the object tree recursively ?
So that :
Map<String,Object> props = new ObjectMapper().convertValue(obj, Map.class);
results in a map of [field, value] where values are the actual references to instances of the fields of obj instead of Maps ?
There is no such feature right now with Jackson. You can probably achieve this with a custom Serializer/Deserializer pair that could share some data and "protocol". But, why bother doing this when the easier (and a LOT faster) way would be to have a generic way to go from POJO to Map, probably using reflection.
I am not sure I understand what you are really trying to do here.
But one thing that may help is to keep in mind that java.lang.Object type (as well as JsonNode) can be freely included in the structure, to get sort of "untyped" binding deeper in the structure. With these types, you can avoid rigid data-binding for some subsets of the object model; and possibly convert to POJOs using ObjectMapper.convertValue() more dynamically.
JAXB doesn't let you unmarshal already existing xml structures into HashMaps if they are not exactly the way JAXB expects them.
JAXB is fine with handling e.g. LinkedLists and filling them.
I was thinking of creating a interface with a getKey() method and a wrapper around the HashMap taking all objects that implement that interface. The wrapper can then use the getKey() method for all key related features of the map. The wrapper could then easily implement the Collection or List interface.
Because this idea doesn't seem to innovative to me I presume that it already exists in some package, but I'm not googling correctly for it... Can someone please name a good lib that can do this, or do I have to code this myself?
You might consider extending ForwardingList of guava, and using a HashMap in the back. I don't know of any implementation that will leave you only the actual mapping.
Another alternative is creating JAXB XmlAdapter to adapt the values to your map. I think this one is more appropriate.
If all you are trying to pass the information content of a Map as a Collection, use Map.entrySet(). That gives you a Set<Map.EntrySet<K,V>> object; i.e. a collection whose elements are the key/value pairs of the Map. To reconstruct a Map from the collection, you will need to iterate the set and perform an put for each element.
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.
I'm looking for an implementation of java.util.Map that has a method that will return all they keys mapped to a given value, that is, there are multiple keys map to the same value. I've looked at Google Collections and Apache Commons and didn't notice anything. Of course, I could iterate through the keyset and check each corresponding value or use two maps, but I was hoping there was something available already built.
I don't know if that solution is good for you, but you can implement easily that by using a standard map from keys to values and a MultiMap from values to key.
Of course you'll have to take care of the syncronization of the two structures, IE when you remove a key from the map, you have to remove the key itself from the set of keys mapped to the value in the multimap.
It doesn't seems difficult to implement, maybe a bit heavy from the memory overhead aspect.
What you're looking for here is a bidirectional map, for which there is an implementation in commons collections.
Your value objects could have a property (of type ArrayList maybe) that holds all the keys.
Then you extend HashMap (or whatever Map impl you use) and override put so that when you put and object for a key you also add the key to your object's list of keys.
I can't find a ready made class that supports values with multiple keys. However you could re-implement the Apache Commons DualHashBidiMap using a MultiHashMap in place of one of the HashMaps.