Search code examples
javaclojurehashmapcompojure

Clojure: hash-map and array-map type conflicts in defined schema


I'm working on a Clojure API but ran into this issue regarding Clojure's automatic "type-switching" between HashMap and ArrayMap when the item count inside the map changes.

Read doc: https://clojuredocs.org/clojure.core/array-map#example-57392e25e4b071da7d6cfd0c

Let's say I have a POST request like this:

  (POST "/" []
    :body [foo FooSchema]
    (create-response ok {:message "foo!"}))

With FooSchema defined like this:

(def ArrayMap clojure.lang.PersistentArrayMap)

(def Bar ArrayMap)

(s/defschema FooSchema
  {:id    s/Str
   :bar   Bar})

:bar is sent as a javascript object that has structure like this:

{
  id: 1,
  fh: 1,
  rdstr: "flying"
}

As stated in the documentation, if the :bar object returns in the body with less than 9 items then it'll yield ArrayMap, which works fine. Anyway, when the :bar object scales and return more than 9 items, the request fails, return error:

(not (instance? clojure.lang.PersistentArrayMap a-clojure.lang.PersistentHashMap))

because :bar was switched to HashMap automatically (magically).

Vice versa, if I set the schema type of :bar to HashMap, then objects with less than 9 items doesn't work neither.

Anyway we can always force the type to HashMap?


Solution

  • Both types are too specific. You should use a more general type, representing anything map-like. The obvious choice is clojure.lang.IPersistentMap.