Export to GitHub

spymemcached - issue #320

Booleans contained in Clojure maps deserialized as new instances of java.lang.Boolean - breaks "if"


Posted on Apr 14, 2015 by Massive Dog

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 Dog

Ok 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