I am not able to find any documentation (or blogs) regarding this. Is it possible to call package protected methods from clojure? We have a huge java code base and I was thinking if its possible to start developing some clojure libraries around them.
I tried making the namespace same as that of the package in java but the method (static) was not found.
Here's a quick code example:
(def a (ref 0))
(def klass (class a))
(def m (.getDeclaredMethod klass "currentVal" (into-array Class [])))
(.setAccessible m true)
(.invoke m a (into-array []))
You should probably have a look at the reflect API
Although, I would recommend only using the publicly declared fields and methods from your old java code base.
Related
I'd like to hide the details of my persistence layer behind some sort of interface. In Java I would just create an interface and choose the correct implementation in some sort of bootup function. I'm still struggling on how to do that in Clojure. I don't necessarily need any type-safety here, I trust in my unit tests to find any issues there. The best thing I could come up with was to create a map containing anonymous functions with specific keys, like so:
(def crux-db {
:get-by-id (fn [id] (get-obj...))
:save (fn [id obj] (store-obj...))
})
(def fs-db {
:get-by-id (fn [id] (get-obj...))
:save (fn [id obj] (store-obj...))
})
If I'm not missing something, this would allow me to replace the database implementation by def-ing (def db crux-db) or (def db fs-db), as long as all the functions exist in all implementation maps. Somehow I feel like this is not the clojure way but I can't put my finger on it. Is there another way to do this?
Protocols are a way to do that. They let you define what functions should be there. And
you can later implement them for different things with e.g.
a defrecord.
A protocol is a named set of named methods and their signatures, defined using defprotocol:
(defprotocol AProtocol
"A doc string for AProtocol abstraction"
(bar [a b] "bar docs")
(baz [a] [a b] [a b c] "baz docs"))
No implementations are provided
Docs can be specified for the protocol and the functions
The above yields a set of polymorphic functions and a protocol object
all are namespace-qualified by the namespace enclosing the definition
The resulting functions dispatch on the type of their first argument, and thus must have at least one argument
defprotocol is dynamic, and does not require AOT compilation
defprotocol will automatically generate a corresponding interface, with the same name as the protocol, e.g. given a protocol my.ns/Protocol, an interface my.ns.Protocol. The interface will have methods corresponding to the protocol functions, and the protocol will automatically work with instances of the interface.
Since you mentioned crux in your code, you can have a peek at how they
use it
here
and then using defrecords to implement some of
them
There are several ways to achieve this. One way would be to use protocols. The other way would be to just use higher-order functions, where you would "inject" the specific function and expose it like so:
(defn get-by-id-wrapper [implementation]
(fn [id]
(implementation id)
...))
(defn cruxdb-get-by-id [id]
...)
(def get-by-id (get-by-id-wrapper cruxdb-get-by-id))
Also worth mentioning here are libraries like component or integrant which are used to manage the lifecylce of state.
I have a protocol and several deftypes implementing it within one workspace. How can I list all deftypes that implement following protocol?
I've came to the solution that filters data from (ns-public), but I don't like it, because it uses some "magic" to get the work done, as I haven't found proper way to achieve my goal with satisfies? and extends?.
Any ideas?
(defprotocol Protocol
(foo[this] "just an interface method"))
(deftype Dummy [] Protocol
(foo[this] "bar"))
(defn implements? [protocol atype] "fn from clojure sources"
(and atype (.isAssignableFrom ^Class (:on-interface protocol) atype)))
(defn list-types-implementing[protocol]
(filter (fn[x] (let [[a b] x]
(when (.startsWith (str a) "->") ; dark magic
(implements? protocol
(resolve (symbol
(.replace (str a) "->" "")))))
))
(ns-publics *ns*)))
(list-types-implementing Protocol) ; => ([->Dummy #'user/->Dummy])
(let [[a b] (first(list-types-implementing Protocol))]
(foo (b)) ; => "bar"
)
In general, this is going to be a hairy problem to solve because there are two different ways a type can satisfy a protocol. You can extend any existing Java class to a protocol using the extend-type and extend-protocol functions (this is a very powerful feature because it allows you to extend your code to work with built-in Java or Clojure types, or other third-party types that you don't control). Or, you can specify a protocol implementation directly as part of a type definition in deftype or defrecord. These two mechanisms are implemented differently.
The first case (extension via extend-type or extend-protocol) is going to be easier for you to solve because the type being extended is going to be attached to the protocol itself (a protocol essentially amounts to a generated Java interface plus a Clojure map with metadata about the protocol). You can find the types that extend the protocol by looking at the :impls key in the protocol map:
user=> (defprotocol MyProtocol (foo [this] "Protocol function"))
user=> (deftype MyType [])
user=> (extend-type MyType MyProtocol (foo [_] "hello foo!"))
user=> (keys (:impls MyProtocol))
(user.MyType)
The second case (directly implementing a protocol via deftype or defrecord) is more difficult because what's happening is the Java class generated for the type or record will directly implement the Java interface defined by the protocol (you can implement any Java interface in a deftype or defrecord, not just a protocol). Any approach to find types that extend a protocol in this manner is going to require some deal of scanning and reflection. Essentially what you're asking is, "how can I find all the Java classes implementing a given interface?"
In a typical Java application, you might do something along the lines of scanning the directories of the classpath for .class files and introspecting on them, but this won't work in Clojure because there very well might not be .class files for your types (the bytecode is generated dynamically). If you're not satisfied with your own implementation, you might check out the answer in this question and see if it's more to your liking:
Find Java classes implementing an interface
I'm learning Clojure. I wrote this code to recursively walk a directory.
(tree-seq #(.isDirectory %1) #(.listFiles %1) (File. "/my-directory"))
Why can't I use .isDirectory as a first-class function in Clojure? Is there a better way to rewrite this code?
Joost is spot on about Java methods not being first class functions.
As an approach to dealing with this, I usually like to wrap Java functions in a Clojure function (or find a library that does this already), then it is easy to use them in an idiomatic first-class way:
(defn directory? [^java.io.File file]
(.isDirectory file))
(defn list-files [^java.io.File file]
(.listFiles %1))
(tree-seq directory? list-files (File. "/my-directory"))
This is a few more lines of code, but has the following advantages:
You can add type hints in your functions to avoid reflection (as above)
The final code is cleaner and more idiomatic
You have abstracted away from the underlying Java interop
Java methods aren't clojure functions because you can't call a method on its own; you have to call a method on an object, and it has to be an object of the type that the method expects. In other words, in java, a method cannot be fully separated from its defining class (at least not efficiently).
An alternative to #(.foo %) would be (memfn foo), which hardly anyone uses anymore after #(...) was introduced.
You could have a look at the sourcecode of file-seq (which uses a tree-seq) to see how it works.
By the way: your code works perfectly well for me. I just have to use java.io.File instead of File in the REPL so it knows the Java class.
You've already been given the correct answers, but just to add a bit more Clojure idiomatic code, I'd also use
#(.foo %)
as Joost Diepenmaat did (yet I believed it might've been overlooked).
I would also suggest reading Listing files in a directory in Clojure.
I don't really understand how the bean function works when I am using it on beans. This code here throws an exception:
(import java.lang.management.ManagementFactory)
(def runtime (bean (ManagementFactory/getRuntimeMXBean))
(:name runtime)
;; =>
Class clojure.core$bean$fn__5177$fn__5178 can not access a member of class sun.management.RuntimeImpl with modifiers "public"
[Thrown class java.lang.IllegalAccessException]
but the class does have a method called getName(). http://docs.oracle.com/javase/6/docs/api/java/lang/management/RuntimeMXBean.html
You must have missed it, it's right there.
getName() Returns the name representing the runn
(import java.lang.management.ManagementFactory)
(def runtime (bean (ManagementFactory/getRuntimeMXBean))
(:name runtime)
;; =>
Class clojure.core$bean$fn_5177$fn_5178 can not access a member of class sun.management.RuntimeImpl with modifiers "public"
[Thrown class java.lang.IllegalAccessException]
but the class does have a method called getName(). http://docs.oracle.com/javase/6/docs/api/java/lang/management/RuntimeMXBean.html
ing Java virtual machine.
Edit1:
This issue is very similar to one here and response to it is here.
Class RuntimeImpl returned by ManagementFactory.getRuntimeMXBean is only package visible but it implements public visible interface RuntimeMXBean. So what happens is that function bean tries to call a method on the class RuntimImpl but it can't as class is only package visible. I think if it tried to call getMethod on interface RuntimeMXBean it would have worked.
Yeap this works:
(def mx-bean (ManagementFactory/getRuntimeMXBean))
(def interface-method
(.getMethod RuntimeMXBean "getName" (into-array java.lang.Class [])))
(.invoke interface-method mx-bean (into-array []))
I'm not sure if it's a bug or feature. I would recommend asking on Clojure mailing list.
I think this is captured by a bug right here: http://dev.clojure.org/jira/browse/CLJ-978?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
Upvote it!
You can roll-your-own bean function using the available patch.
In Clojure, how to use a java Class that is stored in a variable?
How should I fix the following code?
(def a java.lang.String)
(new a "1"); CompilerException java.lang.IllegalArgumentException: Unable to resolve classname: a
And why this one works fine?
(def a str)
(a "1")
The most elegant solution is to write construct that does the same as new but is able to receive a class dynamically:
(defn construct [klass & args]
(clojure.lang.Reflector/invokeConstructor klass (into-array Object args)))
(def a HashSet)
(construct a '(1 2 3)); It works!!!
This solution overcomes the limitation of #mikera's answer (see comments).
Special Thanks to #MichaĆ Marczyk that made me aware of invokeConstructor answering another question of mine: Clojure: how to create a record inside a function?.
Another option is to store the call to the constructor as an anonymous function. In our case:
(def a #(String. %1))
(a "111"); "111"
When you define a in this way, you get a var containing a java.lang.Class
(def a java.lang.String)
(type a)
=> java.lang.Class
You then have 2 options:
A: Construct the new instance dynamically by finding the Java constructor using the reflection API. Note that as Yehonathan points out you need to use the exact class defined in the constructor signature (a subclass won't work as it won't find the correct signature):
(defn construct [klass & args]
(.newInstance
(.getConstructor klass (into-array java.lang.Class (map type args)))
(object-array args)))
(construct a "Foobar!")
=> "Foobar!"
B: Construct using Clojure's Java interop, which will require an eval:
(defn new-class [klass & args]
(eval `(new ~klass ~#args)))
(new-class a "Hello!")
=> "Hello!"
Note that method A is considerably faster (about 60x faster on my machine), I think mainly because it avoids the overhead of invoking the Clojure compiler for each eval statement.
The problem is that Clojure implements Java interop using a number of special forms:
user=> (doc new)
-------------------------
new
Special Form
Please see http://clojure.org/special_forms#new
nil
this basically means the "normal" Clojure syntax is altered to allow for handier constructs when calling Java. As a naive reflection solution to your dynamic Java needs, you can leverage eval:
user=> (def a String) ; java.lang package is implicitly imported
#'user/a
user=> `(new ~a "test") ; syntax quote to create the correct form
(new java.lang.String "test")
user=> (eval `(new ~a "test")) ; eval to execute
"test"
The same strategy works with all the other interop special forms, like method invocation.
EDIT: look also at the answer from #mikera for a more performing alternative via the Java reflection API.