Search code examples
clojureclasscastexceptionhiccup

ClassCastException when using clojure.string/split


I'm writing a website using clojure hiccup for html and clojure garden for css. Now I'm having trouble using clojure.string/split to split a path for the filename. So for some/path/file.md I want file.

For context here's the code snippet, where the problem is

(defn blog-card [post]
  [:a.blog-post-card-link {:href (->> (:location post)
                                      (string/split #"/")
                                      last
                                      (string/replace ".md" ""))}
    [:div.blog-post-card
      -- rest of content -- ]])

now this function gets called here

(defn blog-content []
  [:div.blog-content
    [:div.blog-post-cards-list
      (let [json-str (slurp "resources/public/markdown/posts/all-posts.json")
            posts (json/parse-string json-str true)]
        (map blog-card (reverse posts)))]])

where json is [cheshire.core :as json] and string is [clojure.string :as string]. The all-posts.json looks like this

[
  {
    "id": "0",
    "title": "Test article #1",
    "description": "This article is just a place-filler for development.",
    "image": "images/mountain.jpg",
    "date": "10 Oct 2023",
    "author": "Elías Hauksson",
    "location": "markdown/posts/test-post01.md"
  },
  -- more test entries --
]

So with this example, what I'd like to achieve is, that when the card is pressed, one gets redirected to /test-post01

Now when I try to run this code I get the following error message

HTTP ERROR 500 java.lang.ClassCastException: class java.lang.String cannot be cast to class java.util.regex.Pattern (java.lang.String and java.util.regex.Pattern are in module java.base of loader 'bootstrap')
URI:    /blog
STATUS: 500
MESSAGE:    java.lang.ClassCastException: class java.lang.String cannot be cast to class java.util.regex.Pattern (java.lang.String and java.util.regex.Pattern are in module java.base of loader 'bootstrap')
SERVLET:    -
CAUSED BY:  java.lang.ClassCastException: class java.lang.String cannot be cast to class java.util.regex.Pattern (java.lang.String and java.util.regex.Pattern are in module java.base of loader 'bootstrap')
Caused by:

java.lang.ClassCastException: class java.lang.String cannot be cast to class java.util.regex.Pattern (java.lang.String and java.util.regex.Pattern are in module java.base of loader 'bootstrap')
    at clojure.string$split.invokeStatic(string.clj:219)
    at clojure.string$split.invoke(string.clj:219)
    at eliashaukssoncom.views.blog$blog_card.invokeStatic(blog.clj:10)
    at eliashaukssoncom.views.blog$blog_card.invoke(blog.clj:8)
    at clojure.core$map$fn__5935.invoke(core.clj:2772)
    at clojure.lang.LazySeq.sval(LazySeq.java:42)
    at clojure.lang.LazySeq.seq(LazySeq.java:51)
    at clojure.lang.RT.seq(RT.java:535)
    at clojure.core$seq__5467.invokeStatic(core.clj:139)
    at clojure.core$map$fn__5935.invoke(core.clj:2763)
    at clojure.lang.LazySeq.sval(LazySeq.java:42)
    at clojure.lang.LazySeq.seq(LazySeq.java:51)
    at clojure.lang.RT.seq(RT.java:535)
    at clojure.core$seq__5467.invokeStatic(core.clj:139)
    at clojure.core$apply.invokeStatic(core.clj:662)
    at clojure.core$apply.invoke(core.clj:662)
    at hiccup.compiler$fn__3080.invokeStatic(compiler.clj:139)
    at hiccup.compiler$fn__3080.invoke(compiler.clj:133)
    at hiccup.compiler$fn__3063$G__3058__3068.invoke(compiler.clj:119)
    at clojure.core$map$fn__5935.invoke(core.clj:2770)
    at clojure.lang.LazySeq.sval(LazySeq.java:42)
    at clojure.lang.LazySeq.seq(LazySeq.java:51)
    at clojure.lang.RT.seq(RT.java:535)
    at clojure.core$seq__5467.invokeStatic(core.clj:139)
    at clojure.core$apply.invokeStatic(core.clj:662)
    at clojure.core$apply.invoke(core.clj:662)
    at hiccup.compiler$fn__3080.invokeStatic(compiler.clj:139)
    at hiccup.compiler$fn__3080.invoke(compiler.clj:133)
    at hiccup.compiler$fn__3063$G__3058__3068.invoke(compiler.clj:119)
    at hiccup.compiler$render_element.invokeStatic(compiler.clj:129)
    at hiccup.compiler$render_element.invoke(compiler.clj:123)
    at hiccup.compiler$fn__3078.invokeStatic(compiler.clj:136)
    at hiccup.compiler$fn__3078.invoke(compiler.clj:133)
    at hiccup.compiler$fn__3063$G__3058__3068.invoke(compiler.clj:119)
    at clojure.core$map$fn__5935.invoke(core.clj:2770)
    at clojure.lang.LazySeq.sval(LazySeq.java:42)
    at clojure.lang.LazySeq.seq(LazySeq.java:51)
    at clojure.lang.RT.seq(RT.java:535)
    at clojure.core$seq__5467.invokeStatic(core.clj:139)
    at clojure.core$apply.invokeStatic(core.clj:662)
    at clojure.core$apply.invoke(core.clj:662)
    at hiccup.compiler$fn__3080.invokeStatic(compiler.clj:139)
    at hiccup.compiler$fn__3080.invoke(compiler.clj:133)
    at hiccup.compiler$fn__3063$G__3058__3068.invoke(compiler.clj:119)
    at hiccup.compiler$render_element.invokeStatic(compiler.clj:129)
    at hiccup.compiler$render_element.invoke(compiler.clj:123)
    at hiccup.compiler$fn__3078.invokeStatic(compiler.clj:136)
    at hiccup.compiler$fn__3078.invoke(compiler.clj:133)
    at hiccup.compiler$fn__3063$G__3058__3068.invoke(compiler.clj:119)
    at eliashaukssoncom.views.base$base$fn__1001.invoke(base.clj:26)
    at eliashaukssoncom.views.base$base.invokeStatic(base.clj:26)
    at eliashaukssoncom.views.base$base.invoke(base.clj:25)
    at eliashaukssoncom.views.blog$blog_page.invokeStatic(blog.clj:35)
    at eliashaukssoncom.views.blog$blog_page.invoke(blog.clj:34)
    at eliashaukssoncom.handler$fn__1026.invokeStatic(handler.clj:13)
    at eliashaukssoncom.handler$fn__1026.invoke(handler.clj:13)
    at compojure.core$wrap_response$fn__2214.invoke(core.clj:158)
    at compojure.core$wrap_route_middleware$fn__2198.invoke(core.clj:128)
    at compojure.core$wrap_route_info$fn__2203.invoke(core.clj:137)
    at compojure.core$wrap_route_matches$fn__2207.invoke(core.clj:146)
    at compojure.core$routing$fn__2222.invoke(core.clj:185)
    at clojure.core$some.invokeStatic(core.clj:2718)
    at clojure.core$some.invoke(core.clj:2709)
    at compojure.core$routing.invokeStatic(core.clj:185)
    at compojure.core$routing.doInvoke(core.clj:182)
    at clojure.lang.RestFn.applyTo(RestFn.java:139)
    at clojure.core$apply.invokeStatic(core.clj:669)
    at clojure.core$apply.invoke(core.clj:662)
    at compojure.core$routes$fn__2226.invoke(core.clj:192)
    at ring.middleware.resource$wrap_resource_prefer_resources$fn__596.invoke(resource.clj:25)
    at clojure.lang.Var.invoke(Var.java:384)
    at ring.adapter.jetty$proxy_handler$fn__420.invoke(jetty.clj:27)
    at ring.adapter.jetty.proxy$org.eclipse.jetty.server.handler.AbstractHandler$ff19274a.handle(Unknown Source)
    at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
    at org.eclipse.jetty.server.Server.handle(Server.java:516)
    at org.eclipse.jetty.server.HttpChannel.lambda$handle$1(HttpChannel.java:487)
    at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:732)
    at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:479)
    at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:277)
    at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311)
    at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105)
    at org.eclipse.jetty.io.ChannelEndPoint$1.run(ChannelEndPoint.java:104)
    at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:883)
    at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1034)
    at java.base/java.lang.Thread.run(Thread.java:829)

What I've tried

  1. replace (:location post) with "some/test/path/file.md"
  2. write the function without the ->> operator. Like this
{:href (string/replace (last (string/split (:location post) #"/")) #".md" "")}

Edit: Point 2 turns out to be the correct solution (as mentioned by @Eugene_Pakhomov), it was a typo in my code that didn't make it work the first time.

Thank you in advance for your suggestions.


Solution

  • clojure.string/split accepts a string as the first argument and a regular expression as the second. The code in the "What I've tried" section should work. The code in the main section doesn't work because (->> (:location post) (string/split #"/")) is expanded into (string/split #"/" (:location post)).