
spymemcached - issue #320
Booleans contained in Clojure maps deserialized as new instances of java.lang.Boolean - breaks "if"
What version of the product are you using? On what operating system?
Using in Clojure, on a Mac, via the https://github.com/clojurewerkz/spyglass project. Their currently released versions use version 2.8.10.
Tell me more...
Apologies that this is a Clojure example, but I'm guessing it must also affect other Java nested structures. My Java isn't hot enough to work out the culprit though.
If you persist a Clojure map that contains a boolean into memcached, when you read it in, the boolean is deserialized as a new instance of java.lang.Boolean - so a false value does not have object identity to the false literal, which breaks if expression etc. This doesn't happen when you persist just a boolean by itself - so it seems to be something to do with the serialization/deserialization of a datastructure that contains a boolean.
Here's a REPL session to illustrate what I mean:
user=> (.set c "abc" 3000 {:superuser false})
<OperationFuture net.spy.memcached.internal.OperationFuture@2b66969c>
user=> (def user (.get c "abc"))
'user/user
user=> user {:superuser false}
user=> (when (:superuser user) (println "Do very secure thing!")) Do very secure thing! nil
user=> (class (:superuser user)) java.lang.Boolean
user=> (identical? (:superuser user) false) false
user=> (.set c "abc" 3000 false)
<OperationFuture net.spy.memcached.internal.OperationFuture@3bba6d59>
user=> (.get c "abc" ) false
user=> (identical? (.get c "abc" ) false) true
Comment #1
Posted on Apr 14, 2015 by Massive DogOk this seems quite fundamental so I'm assuming it's my lack of Java knowledge and is known, if strange, behaviour, rather than a bug. But as far as I can see, SpyMemcached uses an ObjectInputStream/OutputStream to serialize/deserialize any java objects it is sent (I'm looking in BaseSerializingTranscoder.java, lines 95-144).
So I tried serializing a java.util.HashMap containing a boolean value using an ObjectInputStream, then deserialized it using an ObjectOutputStream, and got the same problem - a new instance of java.lang.Boolean is created. Here's my REPL session (again, apologies for the non-Java):
user=> (def bos (ByteArrayOutputStream.))
'user/bos
user=> (def os (ObjectOutputStream. bos))
'user/os
user=> (def hm (HashMap.))
'user/hm
user=> (.put hm "abc" false) nil
user=> (.get hm "abc") false
user=> (identical? false (.get hm "abc")) true
user=> (.writeObject os hm) nil
user=> (def ba (.toByteArray bos))
'user/ba
user=> ba
user=> (def bis (ByteArrayInputStream. ba))
'user/bis
user=> (def is (ObjectInputStream. bis))
'user/is
user=> (def newhm (.readObject is))
'user/newhm
user=> (.get newhm "abc") false
user=> (identical? false (.get newhm "abc")) false
Status: New
Labels:
Type-Defect
Priority-Medium