This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2024-07-16
Channels
- # beginners (110)
- # calva (9)
- # cider (9)
- # clojure (24)
- # clojure-europe (13)
- # clojure-mexico (7)
- # clojure-nl (2)
- # clojure-norway (29)
- # clojure-portugal (1)
- # clojure-uk (6)
- # community-development (2)
- # cursive (10)
- # data-science (8)
- # datalevin (2)
- # fulcro (7)
- # graalvm (1)
- # humbleui (4)
- # hyperfiddle (38)
- # instaparse (2)
- # integrant (4)
- # malli (23)
- # missionary (2)
- # overtone (1)
- # polylith (2)
- # reitit (2)
- # releases (1)
- # shadow-cljs (24)
- # testing (6)
- # uncomplicate (4)
I’ve been trying to use compojure-swagger, but I always get this error when I try to access the API pages:
java.lang.AbstractMethodError: Method linked/map/LinkedMap.isEmpty()Z is abstract
or on newer Java,
java.lang.AbstractMethodError: Receiver class linked.map.LinkedMap does not define or inherit an implementation of the resolved method 'abstract boolean isEmpty()' of interface java.util.Map.
Does anyone know why this happens?java.lang.AbstractMethodError: Receiver class linked.map.LinkedMap does not define or inherit an implementation of the resolved method 'abstract boolean isEmpty()' of interface java.util.Map.
at com.fasterxml.jackson.databind.ser.std.MapSerializer.serializeWithoutTypeInfo(MapSerializer.java:752)
at com.fasterxml.jackson.databind.ser.std.MapSerializer.serialize(MapSerializer.java:720)
at com.fasterxml.jackson.databind.ser.std.MapSerializer.serialize(MapSerializer.java:35)
at com.fasterxml.jackson.databind.ser.std.MapSerializer.serializeFields(MapSerializer.java:808)
at com.fasterxml.jackson.databind.ser.std.MapSerializer.serializeWithoutTypeInfo(MapSerializer.java:764)
at com.fasterxml.jackson.databind.ser.std.MapSerializer.serialize(MapSerializer.java:720)
at com.fasterxml.jackson.databind.ser.std.MapSerializer.serialize(MapSerializer.java:35)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:479)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:318)
at com.fasterxml.jackson.databind.ObjectMapper._writeValueAndClose(ObjectMapper.java:4719)
at com.fasterxml.jackson.databind.ObjectMapper.writeValueAsBytes(ObjectMapper.java:3987)
at jsonista.core$write_value_as_bytes.invokeStatic(core.clj:229)
at jsonista.core$write_value_as_bytes.invoke(core.clj:221)
at muuntaja.format.json$encoder$reify__101519.encode_to_bytes(json.clj:43)
at muuntaja.core$create_coder$encode__101918.invoke(core.clj:344)
at clojure.core$update.invokeStatic(core.clj:6233)
at clojure.core$update.invoke(core.clj:6223)
at muuntaja.core$create$_handle_response__101985.invoke(core.clj:443)
at muuntaja.core$create$reify__101987.format_response(core.clj:486)
at muuntaja.middleware$wrap_format_response$fn__102058.invoke(middleware.clj:132)
at muuntaja.middleware$wrap_format_negotiate$fn__102051.invoke(middleware.clj:96)
so it’s trying to serialize a description to JSON
but this type should be serializable and it should extend Map, just as far as sources say
There's a chance you have some ancient version of, I assume, frankiesardo/linked
on your classpath that doesn't implement isEmpty
.
yeah you are right, metosin/compojure-api
includes both frankiesardo/linked
and ikitommi/linked
why the hell
it includes ikitommi/linked
directly and frankiesardo/linked
via metosin/ring-swagger
I think that the newest alpha solves this by upgrading dependencies
oh nope
still uses old library
Yeah, the way a fork of linked
was introduced is not ideal. Partially because it makes things harder for pretty much everyone, including the maintainers of compojure-api
themselves.
but it’s the same people so why not just change it to the ikitommi
version in metosin/ring-swagger
, that’s an easy fix
Because one has to remember why that dependency has been added there in the first place, 6 years ago. :) That's why I said it makes things harder even for the maintainers.
Secret multimethod feature they don't want you to know about! When you work with multimethods and get a stacktrace (as an error or in a profiler), it can be hard to figure out which exact method was being called. Sometimes, you have a line number to trace it back to the real method, sometimes you don't. Continued in the thread.
Consider this example:
(defmulti countdown (fn [x] (cond (zero? x) :zero
(odd? x) :odd
:else :even)))
(defmethod countdown :odd [x] (countdown (dec x)))
(defmethod countdown :even [x] (countdown (dec x)))
(defmethod countdown :zero [x] (throw (Exception. "BOOM")))
(countdown 5)
Exception BOOM
user/eval5945/fn--5946 (NO_SOURCE_FILE:1)
clojure.lang.MultiFn.invoke (MultiFn.java:229)
user/eval5941/fn--5942 (NO_SOURCE_FILE:1)
clojure.lang.MultiFn.invoke (MultiFn.java:229)
user/eval5949/fn--5950 (NO_SOURCE_FILE:1)
clojure.lang.MultiFn.invoke (MultiFn.java:229)
user/eval5941/fn--5942 (NO_SOURCE_FILE:1)
clojure.lang.MultiFn.invoke (MultiFn.java:229)
user/eval5949/fn--5950 (NO_SOURCE_FILE:1)
clojure.lang.MultiFn.invoke (MultiFn.java:229)
user/eval5941/fn--5942 (NO_SOURCE_FILE:1)
clojure.lang.MultiFn.invoke (MultiFn.java:229)
Here, all method implementations have these opaque user/eval5945/fn--
names that don't even hint they are multimethod implementations. But what if I told you that you can name your methods to distinguish them in the stacktrace?
(defmethod countdown :odd I-am-odd! [x] (countdown (dec x)))
(defmethod countdown :even I-am-even! [x] (countdown (dec x)))
(defmethod countdown :zero I-am-zero! [x] (throw (Exception. "BOOM")))
Exception BOOM
user/eval5965/I-am-zero!--5966 (NO_SOURCE_FILE:1)
clojure.lang.MultiFn.invoke (MultiFn.java:229)
user/eval5957/I-am-odd!--5958 (NO_SOURCE_FILE:1)
clojure.lang.MultiFn.invoke (MultiFn.java:229)
user/eval5961/I-am-even!--5962 (NO_SOURCE_FILE:1)
clojure.lang.MultiFn.invoke (MultiFn.java:229)
user/eval5957/I-am-odd!--5958 (NO_SOURCE_FILE:1)
clojure.lang.MultiFn.invoke (MultiFn.java:229)
user/eval5961/I-am-even!--5962 (NO_SOURCE_FILE:1)
clojure.lang.MultiFn.invoke (MultiFn.java:229)
user/eval5957/I-am-odd!--5958 (NO_SOURCE_FILE:1)
clojure.lang.MultiFn.invoke (MultiFn.java:229)
See? The stacktrace now clearly distinguishes between different dispatches of the multimethod.
WHAT THE HELL???
Figuring out why this works is left as an exercise for the curious reader:bulb:.named "anonymous" functions are actually a feature I end up using a lot; although lambdas should be kept short and sweet, having an immediate description of what a moderately complex lambda does helps readability a lot in my experience