14
votes

I have created a record like this:

(defrecord User [user-id email])

:but when I try to access it from another name-space I get the error:

(User. "name" "email")

java.lang.IllegalArgumentException: Unable to resolve classname: User

It works when I do:

(oe.model.modelcore.User. "name" "email")

: I know I will need to import the Java class, but is there any way for clojure to do this automatically when I do:

(use 'oe.model.modelcore :reload)
4

4 Answers

16
votes

Technically you must require it (don't necessarily need to use it) so that the file containing the record definition is compiled and the class is created. Then you must import it so that it is available to construct as a Java class. If you create a constructor function in the first ns like

(defn new-user [id email] 
  (User. id email))

then you will not need to import it in the calling ns.

I wrote this up a while back here:

14
votes

It could be really tricky if you have - (dash) in your name space.

As it turns out there were two errors:

– Importing defrecord from another namespace is not just :use. I had to first :require the namespace, then import the defrecord. This was a trivial problem to solve and I figured it out quickly. Only this did not work in my case

– Dashes “-” and Underscores “_” are a nuisance since we are mixing Lisp with Java. While the file system uses underscores Clojure converts things to dashes. Brilliant.

So to fix the second error I use the follow in the ns block

(ns adder.core
    (:require building-blocks.activity)
    (:import [building_blocks.activity Activity]))

https://cyrax.wordpress.com/2013/07/22/clojure-importrequireuse-defrecord-from-another-namespace/

11
votes

In your question you are creating a record, then invoking the constructor for the class generated as a side effect. To do so you need to import that class as mentioned in another answer.

However, imho the preferred path (since Clojure 1.4) is to use the constructor functions generated by defrecord (here they'll be named ->User and map->User). These functions allow you to avoid the interop forms and just refer in the constructor functions like any other function. By avoiding interop, this is a more portable less-hosty solution:

(ns some-ns 
  (:require [oe.model.modelcore :refer (->User)]))

(def user (->User "name" "email"))
10
votes

You have to import the record like this:

(ns some-ns
  (:import [oe.model.modelcore User]))