https://github.com/casidiablo/ganjika
Java interop glue
https://github.com/casidiablo/ganjika
Last synced: 9 months ago
JSON representation
Java interop glue
- Host: GitHub
- URL: https://github.com/casidiablo/ganjika
- Owner: casidiablo
- License: epl-1.0
- Created: 2015-03-11T05:45:21.000Z (almost 11 years ago)
- Default Branch: master
- Last Pushed: 2016-02-18T15:35:57.000Z (almost 10 years ago)
- Last Synced: 2025-04-09T23:13:11.833Z (9 months ago)
- Language: Clojure
- Size: 203 KB
- Stars: 2
- Watchers: 2
- Forks: 1
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# ganjika
Ganjika is a library that makes Java interop more clojurish. It provides
the `def-java-fns` macro which will define clojure-like functions out of
a Java class or object. This is what it does for you:
- Makes unnecessary to write/use the usual boilerplate associated with
wrapping Java libraries
- Optional and customizable layer of type coercion
- Optional currying
- Optional namespacing
- Optional type-hinting
## Usage
Add to leiningen `[ganjika 0.3.1]`. Then:
```clojure
(use 'ganjika.core)
;; This defines clojure-like functions in the current namespace, which are
;; curried with the provided instance:
(def robot (new java.awt.Robot))
(def-java-fns #'robot)
;; This means now you can do: (mouse-move 200 50) instead of the usual
;; way (.mouseMove robot 200 50). Notice that the instance was curried.
;; You can specify a namespace to define the functions:
(def-java-fns #'robot :using-ns 'my.robot)
(my.robot/mouse-move 30 400)
;; Use refer (instead of require/use) to avoid the namespace prefix
(refer 'my.robot :only ['mouse-move])
;; In some scenarios currying is not desirable:
(def-java-fns java.awt.Robot :disable-currying)
(mouse-move robot 30 400)
;; By default the functions are defined using type hinting. This
;; behavior can be changed by doing:
(def-java-fns #'robot :disable-type-hinting)
;; By default functions parameters are coerced to the underlying method
;; types. If that's a problem it can be disabled:
(def-java-fns #'robot :disable-coercion)
;; It is possible to filter which functions will be defined by providing
;; a predicate that must return false or nil when the provided method
;; must be ignored:
(def-java-fns #'robot
:method-predicate #(not= "someIgnoredMethod" (.getName %)))
```
## Coercion
Imagine a Java class defined like this:
```java
public void someMethod(String[] list) {
// something
}
```
In order to call this from clojure you might have to do something like:
```clojure
(def obj (new SomeClass))
(def arr (make-array String 2))
(aset arr 0 "foo")
(aset arr 1 "bar")
(.someMethod obj arr)
```
ganjika will coerce the function parameters by default, which means you an just do:
```clojure
;; the vector will be coerced to an array of strings
(some-method ["foo" "bar"])
```
Coercion is driven by an internal map that looks like this:
```clojure
{src-type-1 {dest-type1 fn1
dest-type2 fn2}}
```
Each top entry in the map represents a supported source type; the inner
map represents the supported destination types providing functions that
will coerce src-type to dest-type.
This map can be modified via :coercions-transformer
```clojure
(def-java-fns #'something
:coercions-transformer #(assoc % additional-src-type {des-type fn}))
```
### TODO
- Take into account repeated arities for methods with the same name but
different modifiers (static/non-static)