Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

No implementation of method: :spec of protocol: #'schema.core/Schema

Tags:

clojure

I've written a macro

(defmacro defendpoint [msg-type url-key schema]
  `(defrecord ~msg-type []
     Create
     (create [entity#]
       (s/validate ~schema entity#)
       (create-entity (~url-key urls) entity#))))

and I'm using it like so

(defendpoint Location :locations
  {... my schema ...}})

(defendpoint LocationHierarchy :location-hierarchies
  {... my schema ...}})

The first time I use the macro, it works

(create  (map->Location
          {... data ...}))

=> { ... json response ...}

But the second time, it fails:

(create  (map->LocationHierarchy
          {... data ...}))

=> 1. Unhandled java.lang.IllegalArgumentException
 No implementation of method: :spec of protocol:
 #'schema.core/Schema found for class: ohds.client$fn__32303

I'm not sure why this is happening. I expect that the second call will work in the same way as the first, but it seems like there is an error in the validation step. In fact, if I remove (s/validate...) from the macro, it works as expected. So I'm not sure exactly what's going on here.

I've created a gist that shows the entire file I'm working with

like image 237
munk Avatar asked Mar 14 '23 07:03

munk


1 Answers

I'm going to go through how I solved my problem in hopes that the method helps somebody else.

tl;dr

;; Wrong:
(def date-schema (s/both s/Str #(re-matches #"my-regex" %)))
;; Right:
(def date-schema (s/both s/Str (s/pred #(re-matches #"my-regex" %))))

The Method

I started with the error: No implementation of method: :spec of protocol: #'schema.core/Schema found for class: ohds.client$fn__32303

I wasn't sure what this meant at first. :spec of protocol: threw me off. But I did see it was mentioning schema.core/Schema, so I read the source code. I discovered Schema was a protocol with a method spec, just like the error says :/

The next part that was confusing was for class: ohds.client$fn__32303. I was wondering why my namespace needed to implement the protocol. That didn't make any sense. Then I noticed $fn_32303. This told me there was a lambda somewhere where the mistake was!

At this point, it was my hypothesis that my schema had a problem. So I removed all the special validation from my schema and used s/Str everywhere to see if it worked. It did, so I was in the right spot! I added the special validation back, one at a time, until the test failed again. The problem was in my date-schema.

I looked at the schema I defined just above it to see what was different. There I noticed I'd failed to to wrap my lambda in s/pred.

The Moral

Clojure is well designed, so the error message is telling you exactly what's wrong. You just need to understand it.

like image 170
munk Avatar answered Mar 27 '23 18:03

munk