Java Forum / General / November 2007
HashMap toString, what about the other way?
Bas - 14 Nov 2007 01:21 GMT Hi,
is there a way to reconstruct a HashMap from the output of toString?
E.g.
HashMap m = new HashMap();
// put some stuff in it
String s = m.toString();
// s contains something like {blah=123, lalanana=hutsefluts}
HashMap c = (HashMap)somethingThatICantFind(s);
Or I'm a hoping for something that just doesn't work that way? ;)
cheers,
bas.
Lew - 14 Nov 2007 01:56 GMT > Hi, > [quoted text clipped - 7 lines] > > String s = m.toString(); This is already pathological.
> // s contains something like {blah=123, lalanana=hutsefluts} > > HashMap c = (HashMap)somethingThatICantFind(s); > > Or I'm a hoping for something that just doesn't work that way? ;) You could hack (or read the source code for) the HashMap String representation and develop a parse algorithm, but it's possible that the HashMap toString() implementation could change between JVMs or between JVM versions. Unlikely, but possible.
String seems like an incredibly bad choice for object serialization.
 Signature Lew
Patricia Shanahan - 14 Nov 2007 02:09 GMT >> Hi, >> [quoted text clipped - 20 lines] > HashMap toString() implementation could change between JVMs or between > JVM versions. Unlikely, but possible. It is not necessary to read the code, just the API documentation. HashMap inherits toString from AbstractMap, and AbstractMap's documentation says exactly what it produces.
It would work if, and only if, there is enough additional data to recreate each key and value from its toString. For example, "42" is the toString result for both "42" and new Integer(42). For many classes the toString result is clearly insufficient to recreate the object.
> String seems like an incredibly bad choice for object serialization. Especially since HashMap is Serializable.
Patricia
Gordon Beaton - 14 Nov 2007 06:54 GMT >> is there a way to reconstruct a HashMap from the output of toString? >> > String seems like an incredibly bad choice for object serialization. On the other hand, it's not fundamentally different than what java.util.Properties (isa Hashtable) already does with store()/load() and storeToXML()/loadFromXML().
/gordon
--
Lew - 14 Nov 2007 07:24 GMT Lew wrote:
>> String seems like an incredibly bad choice for object serialization.
> On the other hand, it's not fundamentally different than what > java.util.Properties (isa Hashtable) already does with store()/load() > and storeToXML()/loadFromXML(). Exactly the same, except that Properties assumes everything is a String.
> The Properties can be saved to a stream or loaded from a stream. > Each key and its corresponding value in the property list is a string. String.toString() tends to be readily invertible.
Since the question was asked of a HashMap, one must account for non-invertible toString() methods from non-String objects.
I suppose you could argue that that is not a /fundamental/ difference, but I'd beg to differ.
Given certain conventions, one could come up with some sort of Java API for XML Binding (JAXB) or similar, and use it to map object graphs to an XML representation.
Hmm, I wonder if that might solve the OP's problem ...
 Signature Lew
Roedy Green - 14 Nov 2007 02:13 GMT >is there a way to reconstruct a HashMap from the output of toString? // Build a HashMap, convert to String, and recreate the HashMap. import java.util.HashMap; import java.util.regex.Pattern; public class HashString {
/** * test harness * * @param args not used */ public static void main ( String[] args ) {
HashMap<String,String >h1 = new HashMap<String,String>( 11 ); h1.put ("apple","red"); h1.put ("peach","yellow"); h1.put ("mango","orange"); String everything = h1.toString(); System.out.println( everything ); // prints {apple=red, mango=orange, peach=yellow}
// take the answer apart Pattern p = Pattern.compile("[\\{\\}\\=\\, ]++"); String[] split = p.split( everything ); for ( String s: split ) { System.out.println( '\"' + s + '\"' ); } // prints: // "" // "apple" // "red" // "mango" // "orange" // "peach" // "yellow"
// put it back together again. HashMap<String,String >h2 = new HashMap<String,String>( 11 ); for ( int i=1; i< split.length; i+=2 ) { h2.put( split[i], split[i+1] ); } System.out.println( h2.toString() ); // prints: {apple=red, peach=yellow, mango=orange} } }
Also see http://mindprod.com/jgloss/serialization.html
 Signature Roedy Green Canadian Mind Products The Java Glossary http://mindprod.com
Lasse Reichstein Nielsen - 14 Nov 2007 06:06 GMT >>is there a way to reconstruct a HashMap from the output of toString? ...
> HashMap<String,String >h1 = new HashMap<String,String>( 11 ); If all you have is a Map from String to String, then you might as well use a Properties object with its more specialized save and load methods.
Even in this very restricted case (String->String), a fromString method cannot work for all map values
> h1.put ("apple","red"); > h1.put ("peach","yellow"); > h1.put ("mango","orange"); then add: h1.put("foo = bar, baz", " zip, zap = zup"); and try to retrieve the original values.
/L
 Signature Lasse Reichstein Nielsen - lrn@hotpop.com DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html> 'Faith without judgement merely degrades the spirit divine.'
Roedy Green - 15 Nov 2007 23:24 GMT >If all you have is a Map from String to String, then you might as well >use a Properties object with its more specialized save and load methods. There are ways to save and restore your entire HashMap that would be simpler and more general than parsing that toString mess with a regex.
1. Properties (a Lasse suggested). 2. serialisation as I mentioned earlier. 3. saving one string per line 4. saving as a CSV file. See http://mindprod.com/jgloss/csv.html 5. as DataOutputStream pairs.
 Signature Roedy Green Canadian Mind Products The Java Glossary http://mindprod.com
raymondpendergraph@yahoo.com - 14 Nov 2007 02:13 GMT > Hi, > [quoted text clipped - 17 lines] > > bas. Quick answer is strip the braces from the beginning and end with methods in String, split that string based on the commas, String.split each one of those strings by = (name/value pair). Put the trimmed value on the left as the key and the trimmed value on the right as the value.
I would use a wrapper to build a cleaner toString based on the values.
Bas - 14 Nov 2007 03:02 GMT I was afraid of this.
I'll figure it out another (i.e. a "better") way. It seemed so obvious to go from the output of HashMap's toString back to a HashMap. But it's java, not perl ;)
cheers,
bas.
Curt Welch - 14 Nov 2007 03:13 GMT > I was afraid of this. > [quoted text clipped - 5 lines] > > bas. Also, the toString() output was never designed to be reversed. You can't parse it correctly if the strings contain comma, equals, spaces, or braces in the data:
import java.util.*;
class HashMapTest { public static void main(String args[]) { HashMap<String,String> h = new HashMap<String,String>();
h.put("key1=value1, key2", "value2"); h.put("key3=value3}\n{key4=value4, key5", "value5");
System.out.println(h);
// The hashmap with only two keys in it produces // this output: // // {key1=value1, key2=value2, key3=value3} // {key4=value4, key5=value5} // } }
 Signature Curt Welch http://CurtWelch.Com/ curt@kcwc.com http://NewsReader.Com/
bugbear - 14 Nov 2007 14:34 GMT > I was afraid of this. > > I'll figure it out another (i.e. a "better") way. It seemed so obvious > to go from the output of HashMap's toString back to a HashMap. But > it's java, not perl ;) Are you thinking of the (rather remarkable) behaviour of Data::Dumper() ?
BugBea
Daniel Pitts - 14 Nov 2007 02:24 GMT > Hi, > [quoted text clipped - 17 lines] > > bas. The problem with that is that HashMap can contain other things that aren't reconstructible from a String. Usually, toString should not be used to produce something that is intended to be parsed. The best use of toString is to create informative debug information.
So, what is your actual use case? Where does this string come from that you can't get the original map instead?
 Signature Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>
Bas - 14 Nov 2007 04:46 GMT On Nov 14, 3:24 am, Daniel Pitts <newsgroup.spamfil...@virtualinfinity.net> wrote:
> So, what is your actual use case? Where does this string come from that > you can't get the original map instead? I'm sending a client-specific (i.e. not controllable by me) value in a javax.jms.MapMessage. The values in those can only contain primitive data types and I figured I could take a shortcut when allowing only simple text-only keys and text-only values in a HashMap.
I know, I'm lazy ;)
I'll put them in the MapMessage directly, with keys starting with CLIENT_SPECIFIC_XXX where XXX is the client-specific key. And recreate a HashMap in the jms consumer based on that.
I don't want javax.jms.ObjectMessage (I need language neutrality) and I don't want XML in a TextMessage either.
Thanks all, it's clear the obvious (well, to me at least) was a little too obvious ;)
Stefan Ram - 14 Nov 2007 13:37 GMT >is there a way to reconstruct a HashMap from the output of toString? I have written an implementation of java.util.Map to easily do serialization and parsing:
import java.lang.String; import java.lang.System; import de.dclj.ram.notation.unotal.RoomSource; import static de.dclj.ram.notation.unotal.RoomFromModule.room;
public final class Main { public static void main( final String argv[] ) { final RoomSource room = room( "< a=b c=d >" ); System.out.println( room instanceof java.util.Map ) System.out.println( room.get( "a" )); System.out.println( room.get( "c" )); System.out.println( room ); }}
true b d < a =b c =d >
The last line (serialization) can be parsed with »room( java.lang.String )« to get the same room again.
More about it can be found on the following page:
http://www.purl.org/stefan_ram/pub/junotal_tutorial
Lasse Reichstein Nielsen - 14 Nov 2007 18:08 GMT >>is there a way to reconstruct a HashMap from the output of toString? > > I have written an implementation of java.util.Map > to easily do serialization and parsing: ...
> { final RoomSource room = room( "< a=b c=d >" ); How does it handle map keys or values that contain spaces or equals? Does it escape them in the toString text?
/L
 Signature Lasse Reichstein Nielsen - lrn@hotpop.com DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html> 'Faith without judgement merely degrades the spirit divine.'
Stefan Ram - 14 Nov 2007 22:58 GMT >>I have written an implementation of java.util.Map >>to easily do serialization and parsing: >How does it handle map keys it also can handle keys that are maps itself.
For example,
import java.lang.String; import java.lang.System; import de.dclj.ram.notation.unotal.RoomSource; import static de.dclj.ram.notation.unotal.RoomFromModule.room;
public final class Main { public static void main( final String argv[] ) { final RoomSource room = room( "< < a=b c=d >=1 >" ); System.out.println( room.get( room( "< a=b c=d >" ))); }}
1
Above, the map "< a=b c=d >" is used as a key and mapped to the value "1". "room.get" then retrieves the value "1" given the map "< a=b c=d >" as a key.
The order or details of notation or redundant assertions do not matter in this case. Strings can also be written in brackets. Therefore, the notation "< c=d a = [b] c=d >" also is recognized as the same key, because it is the same map.
import java.lang.String; import java.lang.System; import de.dclj.ram.notation.unotal.RoomSource; import static de.dclj.ram.notation.unotal.RoomFromModule.room;
public final class Main { public static void main( final String argv[] ) { final RoomSource room = room( "< < a=b c=d >=1 >" ); System.out.println( room.get( room( "< c=d a = [b] c=d >" ))); }}
>or values that contain spaces or equals? >Does it escape them in the toString text? If a string value is to contain an equal sign or a space, it needs to be written in brackets. The routines will properly escape when serializing again. For example:
import java.lang.String; import java.lang.System; import de.dclj.ram.notation.unotal.RoomSource; import static de.dclj.ram.notation.unotal.RoomFromModule.room;
public final class Main { public static void main( final String argv[] ) { System.out.println( room( "< [abc=def ghi]=1 >" )); }}
< [abc=def ghi] =1 >
The serialization routine has decided to use brackets here, because they are required. The space in front of the "=1" is a minor annoyance (formatting style bug), but it does not change the semantics just the style of the notation.
If brackets are not needed, they will be omitted:
import java.lang.String; import java.lang.System; import de.dclj.ram.notation.unotal.RoomSource; import static de.dclj.ram.notation.unotal.RoomFromModule.room;
public final class Main { public static void main( final String argv[] ) { System.out.println( room( "< [abcdefghi]=1 >" )); }}
< abcdefghi =1 >
Here, the serialization routine has detected that no bracket escape is needed.
To see, how any string is escaped, you can insert it, and then serialize it. The following program adds the following two strings:
abc[]def[ghi\jkl mno\]pqr\
import java.lang.String; import java.lang.System; import de.dclj.ram.notation.unotal.Room; import static de.dclj.ram.notation.unotal.RoomFromModule.room;
public final class Main { public static void main( final String argv[] ) { Room room = new Room(); room.add( "abc[]def[ghi\\jkl" ); room.add( "mno\\]pqr\\" ); System.out.println( room ); }}
< [abc[]def\[ghi\jkl] [mno\\]pqr\|] >
Somewhat unusual, but this is specified in this way, so that brackets and backslashes can be used inside a bracketed string without escaping as often as possible. Only unpaired brackets and backslashes at the end of a string needs special handling.
This output now will be used as input to check, that it will be serialized again to the same output. Of course, Java now requires to double backslashes:
import java.lang.String; import java.lang.System; import de.dclj.ram.notation.unotal.Room; import static de.dclj.ram.notation.unotal.RoomFromModule.room;
public final class Main { public static void main( final String argv[] ) { Room room = room( "< [abc[]def\\[ghi\\jkl] [mno\\\\]pqr\\|] >" ); System.out.println( room ); }}
< [abc[]def\[ghi\jkl] [mno\\]pqr\|] >
Stefan Ram - 14 Nov 2007 23:00 GMT Supersedes: <map-keys-20071114231003@ram.dialup.fu-berlin.de>
>>I have written an implementation of java.util.Map >>to easily do serialization and parsing: >How does it handle map keys it also can handle keys that are maps itself.
For example,
import java.lang.String; import java.lang.System; import de.dclj.ram.notation.unotal.RoomSource; import static de.dclj.ram.notation.unotal.RoomFromModule.room;
public final class Main { public static void main( final String argv[] ) { final RoomSource room = room( "< < a=b c=d >=1 >" ); System.out.println( room.get( room( "< a=b c=d >" ))); }}
1
Above, the map "< a=b c=d >" is used as a key and mapped to the value "1". "room.get" then retrieves the value "1" given the map "< a=b c=d >" as a key.
The order or details of notation or redundant assertions do not matter in this case. Strings can also be written in brackets. Therefore, the notation "< c=d a = [b] c=d >" also is recognized as the same key, because it is the same map.
import java.lang.String; import java.lang.System; import de.dclj.ram.notation.unotal.RoomSource; import static de.dclj.ram.notation.unotal.RoomFromModule.room;
public final class Main { public static void main( final String argv[] ) { final RoomSource room = room( "< < a=b c=d >=1 >" ); System.out.println( room.get( room( "< c=d a = [b] c=d >" ))); }}
1
>or values that contain spaces or equals? >Does it escape them in the toString text? If a string value is to contain an equal sign or a space, it needs to be written in brackets. The routines will properly escape when serializing again. For example:
import java.lang.String; import java.lang.System; import de.dclj.ram.notation.unotal.RoomSource; import static de.dclj.ram.notation.unotal.RoomFromModule.room;
public final class Main { public static void main( final String argv[] ) { System.out.println( room( "< [abc=def ghi]=1 >" )); }}
< [abc=def ghi] =1 >
The serialization routine has decided to use brackets here, because they are required. The space in front of the "=1" is a minor annoyance (formatting style bug), but it does not change the semantics just the style of the notation.
If brackets are not needed, they will be omitted:
import java.lang.String; import java.lang.System; import de.dclj.ram.notation.unotal.RoomSource; import static de.dclj.ram.notation.unotal.RoomFromModule.room;
public final class Main { public static void main( final String argv[] ) { System.out.println( room( "< [abcdefghi]=1 >" )); }}
< abcdefghi =1 >
Here, the serialization routine has detected that no bracket escape is needed.
To see, how any string is escaped, you can insert it, and then serialize it. The following program adds the following two strings:
abc[]def[ghi\jkl mno\]pqr\
import java.lang.String; import java.lang.System; import de.dclj.ram.notation.unotal.Room; import static de.dclj.ram.notation.unotal.RoomFromModule.room;
public final class Main { public static void main( final String argv[] ) { Room room = new Room(); room.add( "abc[]def[ghi\\jkl" ); room.add( "mno\\]pqr\\" ); System.out.println( room ); }}
< [abc[]def\[ghi\jkl] [mno\\]pqr\|] >
Somewhat unusual, but this is specified in this way, so that brackets and backslashes can be used inside a bracketed string without escaping as often as possible. Only unpaired brackets and backslashes at the end of a string needs special handling.
This output now will be used as input to check, that it will be serialized again to the same output. Of course, Java now requires to double backslashes:
import java.lang.String; import java.lang.System; import de.dclj.ram.notation.unotal.Room; import static de.dclj.ram.notation.unotal.RoomFromModule.room;
public final class Main { public static void main( final String argv[] ) { Room room = room( "< [abc[]def\\[ghi\\jkl] [mno\\\\]pqr\\|] >" ); System.out.println( room ); }}
< [abc[]def\[ghi\jkl] [mno\\]pqr\|] >
Supersedes: <map-keys-20071114231003@ram.dialup.fu-berlin.de>
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|