Fork me on GitHub
#clojure
<
2024-06-02
>
hifumi12304:06:28

How does one set! variables like *print-length* in deps.edn projects? I have the following in my user.clj file (minimal project, brainstorming stuff right now).

(set! *print-length* 10)
but restarting the REPL fails with this message:
Exception in thread "main" Syntax error macroexpanding at (user.clj:10:1).
...
Caused by: java.lang.IllegalStateException: Can't change/establish root binding of: *print-length* with set
...
In Leiningen projects, I make use of the :repl-options setting in project.clj to set a default print-length for my initial namespace. It doesn't seem that deps.edn has this feature, so I've decided to include the code in my namespace directly. On a semi-related note: I understand that *print-length* is a dynavar, not a proper special variable like *assert*. So what makes (set! *print-length* ...) in the REPL work? Does the Clojure REPL implicitly wrap expressions within a binding ?

p-himik09:06:53

Some prior discussion: https://clojurians.slack.com/archives/C03S1KBA2/p1654280379777659 I think I saw a discussion about some plans on extending the set of built-in dynavars that the REPL binds at the start, but can't find it now.

igrishaev17:06:06

I've been looking for the same: to have *warn-on-reflection* set to true in ANY project. It looks like it's not possible with dep.edn, only Lein (this is one of the reasons I still prefer Lein over deps)

hifumi12322:06:09

Yeah, in the end I just converted the project over to lein. There's a lot more ceremony involved in setting up a project.clj compared to deps.edn, but I am dealing with a pretty large XML dataset, so I don't want me (or the person I'm working with) accidentally freezing their Clojure REPL because their code returns a seq with over 250,000 maps (each of which contain even more maps due to the structure of the data) That was my motivation for setting an aggressively low *print-length* , basically to make sure that the REPL doesnt blow up if the user forgets to set *print-length* themselves

oyakushev04:06:22

Just in case, if you use any nrepl-based REPL (or IDE on top of it), the REPL will not freeze when printing any value regardless of the state of *print-length*. You can try it yourself, in CIDER:

user=> (range)
Or evaluate (range) in a code buffer.

roklenarcic08:06:00

I am running some tests in REPL (that use Carmine and Redis) and sporadically I get this:

Error handling response - class java.lang.ClassCastException: class clojure.lang.Symbol cannot be cast to class clojure.lang.Associative (clojure.lang.Symbol and clojure.lang.Associative are in unnamed module of loader com.intellij.ide.plugins.cl.PluginClassLoader @2eaa99)
acd4-fce24cd45579" nil
Error handling response - class java.lang.ClassCastException: class clojure.lang.Symbol cannot be cast to class clojure.lang.Associative (clojure.lang.Symbol and clojure.lang.Associative are in unnamed module of loader com.intellij.ide.plugins.cl.PluginClassLoader @2eaa99)
acd4-fce24cd45579" nil
Error handling response - class java.lang.ClassCastException: class clojure.lang.Symbol cannot be cast to class clojure.lang.Associative (clojure.lang.Symbol and clojure.lang.Associative are in unnamed module of loader com.intellij.ide.plugins.cl.PluginClassLoader @2eaa99)
acd4-fce24cd45579" nil
Error handling response - class java.lang.ClassCastException: class clojure.lang.Symbol cannot be cast to class clojure.lang.Associative (clojure.lang.Symbol and clojure.lang.Associative are in unnamed module of loader com.intellij.ide.plugins.cl.PluginClassLoader @2eaa99)
acd4-fce24cd45579" nil
Error handling response - class java.lang.ClassCastException: class clojure.lang.Symbol cannot be cast to class clojure.lang.Associative (clojure.lang.Symbol and clojure.lang.Associative are in unnamed module of loader com.intellij.ide.plugins.cl.PluginClassLoader @2eaa99)
acd4-fce24cd45579" nil
Error handling response - class java.lang.ClassCastException: class clojure.lang.Symbol cannot be cast to class clojure.lang.Associative (clojure.lang.Symbol and clojure.lang.Associative are in unnamed module of loader com.intellij.ide.plugins.cl.PluginClassLoader @2eaa99)
acd4-fce24cd45579" nil
Error handling response - class java.lang.ClassCastException: class clojure.lang.Symbol cannot be cast to class clojure.lang.Associative (clojure.lang.Symbol and clojure.lang.Associative are in unnamed module of loader com.intellij.ide.plugins.cl.PluginClassLoader @2eaa99)
acd4-fce24cd45579" nil
Error handling response - class java.lang.ClassCastException: class clojure.lang.Symbol cannot be cast to class clojure.lang.Associative (clojure.lang.Symbol and clojure.lang.Associative are in unnamed module of loader com.intellij.ide.plugins.cl.PluginClassLoader @2eaa99)
The issue is that I cannot find the spot where this is thrown. I have started JVM in debug mode and I’ve added a breakpoint for ClassCastException exception and it’s never triggered. It’s baffling.

roklenarcic08:06:21

Could this be some sort of an artifact of REPL processing? But it should still trigger the breakpoint.

vemv09:06:15

What's your stack? com.intellij hints it's intellij-based, surely it's a bug somewhere in that stack? (debuggers have bugs too!)

roklenarcic09:06:57

The intellij classloader is mentioned because I started it with their runner

roklenarcic09:06:36

Hm I think it’s interaction between Cursive plugin and repl response

john11:06:14

Something is probably calling assoc, merge, get, etc, on a thing that should be a data structure but is actually just the symbol name of the data structure. Is there some data structure being read out from a string somewhere?

john11:06:52

Some process that reads stuff out of a string might not be going far enough with one of the tokens being read out

john11:06:20

Possibly. Just spit balling

p-himik16:06:52

@U66G3SGP5 Where do you see those errors? In logs, in the REPL output, somewhere else? Can you get to the stacktrace of those exceptions? If not, can you find on your classpath where the message "Error handling response" comes from and put a breakpoint there?

roklenarcic16:06:41

It seems that it’s a Cursive thing

roklenarcic16:06:08

That’s why Exception breakpoint didn’t work, it didn’t happen in my application

p-himik16:06:24

Probably worth asking in #C0744GXCJ then, maybe Colin knows.

roklenarcic16:06:35

Already did

👍 1
Eugen16:06:05

hi, how can I import a SecurityManger ? it conflicts with the existing one in Java that is being deprecated

(ns shiro-exploration
  (:refer-clojure :exclude [java.lang.SecurityManager])
  (:import (org.apache.shiro.mgt SecurityManager)))

; Execution error (IllegalStateException) at shiro-exploration/eval10881$loading (shiro_exploration.clj:1).
; SecurityManager already refers to: class java.lang.SecurityManager in namespace: shiro-exploration
; Evaluation of file shiro_exploration.clj failed: class clojure.lang.Compiler$CompilerException

hiredman16:06:41

You can't, just use the full class name

hifumi12323:06:07

Is there a way to extend the content-handler in clojure.xml? I want to customize entity resolution, so I have written the following code.

(defn custom-entity-resolver []
  (reify EntityResolver
    (resolveEntity [this publicId systemId]
      (throw (Exception. "it works!")))))

(defn use-custom-resolver ^SAXParser [^SAXParser parser]
  (let [reader (.getXMLReader parser)]
    (.setEntityResolver reader (custom-entity-resolver))
    parser))

(defn startparse-custom [s ch]
  (.parse (use-custom-resolver (xml/sax-parser)) s ch))
The problem: xml/parse passes xml/content-handler to the startparse function, and the SAXParser java class has the following block in its parse method.
public void parse(InputSource is, DefaultHandler dh) {
  // ...
  XMLReader reader = this.getXMLReader();
  if (dh != null) {
    reader.setContentHandler(dh);
    reader.setEntityResolver(dh);
    reader.setErrorHandler(dh);
    reader.setDTDHandler(dh);
  }
  reader.parse(is);
}
so my EntityResolver gets overriden with that of xml/content-handler, which has no entity resolver (thus uses the SAXParser's default resolver).

1
hifumi12302:06:57

OK, after some investigation, I have found a mailing list thread that claims the SAXParser is not aware of entity resolvers, but the underlying XMLReader is, so one must parse with the underlying XMLReader. https://www.stylusstudio.com/xmldev/handler.asp?/xmldev/200311/post00360.html

hifumi12302:06:05

I have attempted to use reflection to access the ContentHandler instance from clojure.xml/content-handler then attempt parsing with an XMLReader like so.

(defn use-custom-resolver ^XMLReader [^SAXParser parser]
  (let [reader (.getXMLReader parser)]
    (.setContentHandler reader (private-field xml/content-handler "h"))
    (.setEntityResolver reader (custom-entity-resolver))
    reader))

(defn startparse-custom [s ch]
  (.parse (use-custom-resolver (xml/sax-parser))
          (InputSource. s)))
Unfortunately, the custom entity resolver is still not being called.

hifumi12302:06:49

However, the resolver is clearly present in the XMLReader

user> (use-custom-resolver (xml/sax-parser))
#object[com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser ...]
user> (.getEntityResolver *1)
#object[user$custom_entity_resolver$reify__19194 ...]

hifumi12302:06:33

OK turns out "EntityResolver" is exclusively for external entities. Not internal entities. I should've read the documentation more carefully...