I am trying to build server-side rendering for om.next (1.0.0-alpha47). At some point I have to create a reconciler from Clojure:
(om/reconciler {})
(om/reconciler
{:state (atom {})
:normalize true
:parser (om/parser {})})
However evaluating any of these in my REPL gives:
Unhandled java.lang.IllegalArgumentException Multiple methods in
multimethod 'print-method' match dispatch value: class
om.next.Reconciler -> interface clojure.lang.IDeref and interface
clojure.lang.IRecord, and neither is preferred
How do I fix that?
I came to this solution via trial and error:
(prefer-method print-method clojure.lang.IPersistentMap clojure.lang.IDeref)
This seems to solve the conflict, sorry that I can't explain any details.
Related
I have a basic Java interface defined as follows:
public interface Action {
void execute(Metadata var1, Parameter var2);
}
I'm trying to extend it in Clojure but keep getting errors. After importing the class into my namespace, I've tried using reify as follows:
(defn action [action-fn]
(reify Action
(execute [metadata parameter] (action-fn metadata parameter))))
but that throws a compiler illegal argument exception:
CompilerException java.lang.IllegalArgumentException: Can't define method not in interfaces: execute
Next I tried using proxy
(defn action [action-fn]
(proxy [Action] []
(execute [metadata parameter] (action-fn metadata parameter))))
That compiles successfully, and my editor (IntelliJ + Cursive) navigates to the interface definition via a border decoration, but trying to invoke execute on a generate proxy fails:
(.execute (action (fn [_ _] "Test action")))
throws the following:
IllegalArgumentException No matching field found: execute for class
Finally I tried using deftype as follows:
(deftype cljAction [action-fn]
Action
(execute [metadata parameter] (action-fn metadata parameter)))
which throws the same compiler error as for reify, e.g:
CompilerException java.lang.IllegalArgumentException: Can't define method not in interfaces: execute
Trawling through various blog posts and SO answers seems to suggest it's a problem with the arity of arguments, but I'm not sure how to resolve it. What am I doing wrong??
You are missing the this reference from the function. So what you want is this:
(defn action [action-fn]
(reify Action
(execute [this metadata parameter] (action-fn metadata parameter))))
Obviously because you are not using it you can just call it _ or whatever makes the most sense in your opinion. When you are calling the function you want this:
(.execute (action action-fn) metadata parameter)
This differs slightly from when you are implementing a protocol. See https://clojuredocs.org/clojure.core/definterface for more information.
ponzao's answer is correct. But note that Cursive can actually fill in the stubs for you: you can write (reify Action) and then (with the cursor in that form somewhere) choose Code->Generate... and choose to implement methods. Cursive will then fill in the stubs with the correct form. This currently only works when implementing interfaces, not protocols.
I would like to write tests for a Pedestal web-service.
If I have :
(defn pong
[request]
(ring-resp/response "pong"))
(defroutes routes[[["/" {:get pong}]]])
How would I write a test for that ?
(deftest alive-system
(testing "ping-pong route"
;; How do I test my route ?
;; If possible :
;; - I would like to have direct access to it
;; ie. no need to bind pedestal to a port would be nice
;; - The ability to omit some interceptors would be nice also,
;; as it would allow me to receive plain Clojure data structures
;; instead of, for instance, JSON which I would have to parse.
...)
Edit:
Here is what I tried :
(deftest alive-system
(testing "ping-pong route"
(let [response (my-other.ns/routes (mock/request :get "/ping"))]
(is (= (:status response) 200))
(is (= (:body response) "pong")))))
But I get an exception :
ERROR in (alive-system) (service_test.clj:13)
Uncaught exception, not in assertion.
expected: nil
actual: java.lang.ClassCastException: clojure.lang.LazySeq cannot be cast to clojure.lang.IFn
So after asking on the issue I linked ohpaulez replied :
#nha - Thanks for using Pedestal! Sorry your question didn't get an
answer on StackOverflow - I don't think anyone monitors SO for
Pedestal questions. The best place to ask those kinds of questions is
on the mailing list.
Pedestal ships with its own utility for making requests directly to
the servlet (similar to ring/mock, although I've never used mock
myself) called response-for. The Pedestal Service template produces a
test automatically for you. Check out one of the samples for an
example.
Also note that said response-for doesn't yet support asynchronous responses (so my routes that uses asynchronous interceptors with core.async failed - I had to make them synchronous).
I'm trying to implement an interface that has properties but can't quite seem to get it to work and I also have not found any relevant examples via Google (yet). I'm sure I'm doing something completely wrong here but have no idea how to fix it.
(System.Reflection.Assembly/LoadWithPartialName "System.Web")
; naive, just trying to figure out how to implement the IHttpHandler interface in Clojure
(defn foo-handler []
(reify System.Web.IHttpHandler
(IsReusable [] false)
(ProcessRequest [context] ())))
IsReusable is a property and I don't know how to tell reify that it is not a traditional function.
CompilerException clojure.lang.CljCompiler.Ast.ParseException: Must supply at least one argument for 'this' in: IsReusable
Okay, I supply 'this' for IsReusable
CompilerException clojure.lang.CljCompiler.Ast.ParseException: Can't define method not in interfaces: IsReusable
I've also tried proxy but I get similar results.
I've also tried naming IsReusable to get_IsReusable which doesn't actually make a difference and I get the same compiler errors as above.
I've also tried deftype but I get a completely different error:
(deftype foo-handler []
System.Web.IHttpHandler
(get_IsReusable [this] false)
(ProcessRequest [this context] ()))
Compiler error:
InvalidCastException Unable to cast object of type 'clojure.lang.Var' to type 'System.Type'. clojure.lang.Namespace.ReferenceClass
Update:
The code posted for deftype works, I cannot reproduce the error that I posted above. I have no idea now what I was doing wrong at the time.
This took me a few hours of research and trial and error but I finally have success!
user=> (def foo-handler
(reify System.Web.IHttpHandler
(get_IsReusable [this] false)
(ProcessRequest [this context] ())))
#'user/foo-handler
user=>
Success!
user=> (instance? System.Web.IHttpHandler foo-handler)
true
This way is better and works fine from an ASP.NET application:
(deftype foo-handler []
System.Web.IHttpHandler
(get_IsReusable [this] false)
(ProcessRequest [this context]
(.Write (.Response context) "Hello, From Clojure CLR!")))
I'm placing Clojure into an existing Java project which heavily uses Jersey and Annotations. I'd like to be able to leverage the existing custom annotations, filters, etc of the previous work. So far I've been roughly using the deftype approach with javax.ws.rs annotations found in Chapter 9 of Clojure Programming.
(ns my.namespace.TestResource
(:use [clojure.data.json :only (json-str)])
(:import [javax.ws.rs DefaultValue QueryParam Path Produces GET]
[javax.ws.rs.core Response]))
;;My function that I'd like to call from the resource.
(defn get-response [to]
(.build
(Response/ok
(json-str {:hello to}))))
(definterface Test
(getTest [^String to]))
(deftype ^{Path "/test"} TestResource [] Test
(^{GET true
Produces ["application/json"]}
getTest
[this ^{DefaultValue "" QueryParam "to"} to]
;Drop out of "interop" code as soon as possible
(get-response to)))
As you can see from the comments, I'd like to call functions outside the deftype, but within the same namespace. At least in my mind, this allows me to have the deftype focus on interop and wiring up to Jersey, and the application logic to be separate (and more like the Clojure I want to write).
However when I do this I get the following exception:
java.lang.IllegalStateException: Attempting to call unbound fn: #'my.namespace.TestResource/get-response
Is there something unique about a deftype and namespaces?
... funny my hours on this problem did not yield an answer until after I asked here :)
It looks like namespace loading and deftypes was addressed in this post. As I suspected the deftype does not automatically load the namespace. As found in the post, I was able to fix this by adding a require like this:
(deftype ^{Path "/test"} TestResource [] Test
(^{GET true
Produces ["application/json"]}
getTest
[this ^{DefaultValue "" QueryParam "to"} to]
;Drop out of "interop" code as soon as possible
(require 'my.namespace.TestResource)
(get-response to)))
I have a Clojure proxy statement that was getting large and messy, so I decided to try factoring the code of the beginDrag method redefinition out of the proxy statement, like this:
(defn enhanced-start-drag
""
[pie]
(let [pobj (. pie getPickedNode)
pobj-coll (seq (.. pie getInputManager
getKeyboardFocus getSelection))]
(println pobj)
(println pobj-coll)
(println "----------")
(proxy-super startDrag pie))) ; THIS IS LINE 94 (SEE ERROR MSG)
(defn custom-selection-event-handler [marqueeParent selectableParent]
(proxy [PSelectionEventHandler] [marqueeParent selectableParent]
(decorateSelectedNode [node]
(let [stroke-color (Color/red)]
(.setStrokePaint node stroke-color)))
(undecorateSelectedNode [node]
(let [stroke-color (Color/black)]
(.setStrokePaint node stroke-color)))
(startDrag [pie] ; pie is a PInputEvent
(enhanced-start-drag pie))
(endStandardSelection [pie] ; pie is a PInputEvent
(let [pobj (.getPickedNode pie)
slip (. pobj getAttribute "slip")
]
(swap! *last-slip-clicked*
(fn [x] slip))))))
I get the following compile error:
cd /Users/gw/tech/clojurestuff/cljprojects/infwb/src/infwb/
1 compiler notes:
Unknown location:
error: java.lang.Exception: Unable to resolve symbol: this in this context
core.clj:94:5:
error: java.lang.Exception: Unable to resolve symbol: this in this context
(core.clj:94)
Compilation failed.
As soon as I restore the body of enhanced-start-drag into the body of the proxy statement, everything works.
My question: Is there a way to move the messy details out to a separate function to improve the readability of my code?
Thanks for all your ideas and solutions.
UPDATE, 10/27/11: See the comments below. Arthur Ulfeldt was sharp in pointing out that the issue is captured references, and Dave Ray is also correct in saying that all you have to do is add this as a parameter to enhanced-start-drag and then proxy-super will work correctly. When I made the following two changes (without any changes to the body of enhanced-start-drag), my code was working again:
(defn enhanced-start-drag
""
[pie this]
and
(startDrag [pie] ; IN THE PROXY STMT IN custom-selection-event-handler
(enhanced-start-drag pie this))
BTW, my project uses Dave Ray's seesaw project to get a Java Swing UI. seesaw is awesome, as are its docstrings and sample code (which are much better than most commercial software). I highly recommend it! And thank you, Dave!
You have been bitten by symbol capture. In this case it is intentaional though you need to stay aware of it. From the doc for proxy-super
Use to call a superclass method in the body of a proxy method.
Note, expansion captures 'this`
proxy is creating a class that calls a function, when the call gets into enhanced-start-drag the value of this is not where proxy-super expects
you may needs to pass this as another argument into enhanced-start-drag and then call (. saved-this ...) instead of using proxy-super.