4

I have a Clojure library that I would like to use in Java, but I'm having trouble getting the correct class generated. I would like to generate a class that is effectively:

public class TokenStore {
    public static TokenStore Sns(Map<String, String> services) { /* ... */ }

    public String addToken(String token, String username, String service) { /* ... */ }
    public String findToken(String username, String service) { /* ... */ }
    public String sendNotification(String username, String service, String message) { /* ... */ }
}

Here's what I'm trying to do in Clojure:

(ns my.lib.token-java
  (:require [my.lib.token :refer :all])
  (:gen-class
   :name my.lib.TokenStore
   :methods [#^{:static true} [Sns [java.util.Map] TokenStore]]))

(defprotocol TokenStore
  (addToken [this token username service])
  (findToken [this username service])
  (sendNotification [this username service message]))

(defn -Sns [services]
  (let [ts (token-store (apply concat (for [[k v] (into {} coll)] [(keyword k) v]))]
    (reify TokenStore
      (addToken [this token username service]
        (add-token this token username service))
      (findToken [this username service]
        (find-token this username service))
      (sendNotification [this username service message]
        (send-notification this username service message)))))

But when I try to compile it, I get:

: jmglov@alhana; lein jar
Compiling orron-iii.push-java
Exception in thread "main" java.lang.ClassNotFoundException: java.lang.TokenStore, compiling:(orron_iii/push_java.clj:1:1)

Can anybody give me a simple example of how to do this?

3
  • Try changing TokenStore in the :methods section to my.lib.TokenStore. Commented Apr 8, 2014 at 17:12
  • 1
    Nope, that didn't help. Commented Apr 9, 2014 at 13:34
  • 1
    Yeah, the fact that your protocol and class have the same name is likely to lead to conflicts, since the protocol causes an interface of its own to be generated. My suggestion would have been to define the TokenStore interface in Java with the method signatures that you want, and then make a factory class in Clojure that produces an implementation of that interface. But your way works as well. Commented Apr 9, 2014 at 14:44

1 Answer 1

3

This is not a direct answer to my question, but it may be a better way of accomplishing what I wanted. It's a bit of a "Doctor, it hurts when I do this." "Then stop doing that!" sort of thing. :)

I used standard gen-class foo to create a class that extends java.lang.Object and neatly wraps my Clojure token store stuff (as defined in the pure-Clojure my.lib.token file).

(ns my.lib.token-java
  (:require [my.lib.token :as t])
  (:gen-class
   :name my.lib.TokenStore
   :constructors {[java.util.List] []}
   :init initialise
   :state localstate
   :methods [[addToken [String String String] String]
             [findToken [String String] String]
             [sendNotification [String String String] String]]))

(defn- keywordise [coll]
  (flatten (map (fn [[k v]] [(keyword k) v]) (partition 2 coll))))

(defn -initialise [services]
  (let [token-store (apply t/sns-token-store (keywordise services))]
    [[] (ref token-store)]))

(defn -addToken [this service username token]
  (t/add-token @(.localstate this) (keyword service) username token))

(defn -findToken [this service username]
  (t/find-token @(.localstate this) (keyword service) username))

(defn -sendNotification [this service username message]
  (p/send-notification @(.localstate this) (keyword service) username message))

I can now use this from Java like this:

import my.lib.TokenStore;
import java.util.Arrays;

public class TokenTool {
    public static void main(String[] args) {
        TokenStore tokenStore = new TokenStore(Arrays.asList("APNS", "arn:aws:sns:..."));

        String deviceId = tokenStore.findDevice("APNS", "foo");
        System.out.println("Device is: " + deviceId);

        tokenStore.sendNotification("APNS", "foo", "Test for echo");
    }
}

This seems to work pretty well.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.