Skip to content

Instantly share code, notes, and snippets.

@hkupty
Last active February 20, 2020 06:15
Show Gist options
  • Select an option

  • Save hkupty/783a89820fdc10d9a525cdf7cd2abac2 to your computer and use it in GitHub Desktop.

Select an option

Save hkupty/783a89820fdc10d9a525cdf7cd2abac2 to your computer and use it in GitHub Desktop.
Transforming java proto instances in clojure maps
;; The main function is `protobuf->map`, which performs the transformation.
;; Runtime reflection can be avoided if class is known beforehand.
;; The macro is completely optional, though it makes things *slightly* easier to read:
;; (protobuf->clj instance OuterClass$InnerClass) vs (protobuf->map instance (OuterClass$InnerClass/getDescriptor))
(defn- *proto->fields
"Get fields from protobuf object's descriptor as clojure keywords"
[descr]
(map #(keyword (.getName %))
(.getFields descr)))
(defn protobuf->map
"Returns a map representation of the proto object.
Single-arity version will perform reflection to get fields"
([proto-obj]
(protobuf->map proto-obj
(.invoke
(.getMethod (.getClass proto-obj)
"getDescriptor"
(into-array Class []))
nil
(into-array Object []))))
([proto-obj descr]
(let [b (bean proto-obj)]
(select-keys b
(*proto->fields descr)))))
(defmacro protobuf->clj
"Provides syntactic sugar to avoid runtime reflections if class is known."
[object clazz]
`(protobuf->map ~object (~(symbol (name clazz) "getDescriptor"))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment