5

(I'm aware this is related to How can I embed Clojure in an RCP application, but that thread is old and my setup is somewhat different)

I'm using Eclipse 3.7.1 and for days now have been trying to write an Eclipse/RCP app in Clojure (as much as possible). I've tried building the source version of clojure.osgi and CCW, have tried the RCPClojure demo project and several other things. Each one of them didnt work (mainly seemingly "unfixable" build/classpath errors, lack of up-to-date docs/response, version conflicts etc...)

My own steps to bring me at least 50% success:

  1. Create a new plugin project wrapping the Clojure 1.3.0 jar file, set plugin ID org.clojure.v1.3.0

  2. Create a new plugin project org.cljtest42 using RCP Hello template

    1. Adding org.clojure plugin dependency
    2. Adding CCW project nature (to enable AOT compiling), this step adds the /classes folder
    3. Edit plugin.xml to add /classes folder to runtime classpath, also add org.cljtest42 to exported packages.
  3. Add two simple Clojure files in the org.cljtest42 package/namespace:

    TestClass.clj:

    (ns org.cljtest42.TestClass
    (:gen-class))
    
    (defn -main [greet] (println greet))
    

    compile.clj

    (ns org.cljtest42.compile)
    (dorun (map compile ['org.cljtest42.TestClass]))
    
  4. Trigger AOT compilation by selecting project node and choose Run > Clojure application (the /classes folder should now be populated with compiled clojure classes).

  5. Reference TestClass from the Activator class (e.g. in start() - also tried in Perspective.createInitialLayout())

So far so good. However, trying to run this project as an Eclipse application always fails with this:

java.io.FileNotFoundException: Could not locate org/cljtest42/TestClass__init.class or org/cljtest42/TestClass.clj on classpath:
at clojure.lang.RT.load(RT.java:430)
at clojure.lang.RT.load(RT.java:398)
at clojure.core$load$fn__4610.invoke(core.clj:5386)
at clojure.core$load.doInvoke(core.clj:5385)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.lang.Var.invoke(Var.java:401)
at com.pspctclr.cljtest42.TestClass.<clinit>(Unknown Source)

It would be outstanding if someone more knowledgable could share some pointers on how this issue could be overcome. Could it be that it's either because the AOT compiled classes don't actually end up in the classpath (not sure why?, /classes is explicitly added) or that the separate Clojure plugin can't access them due to the way Equinox/OSGI works?

Thanks!

1 Answer 1

1
+50

The problem seems that the Clojure bundle doesn't see your bundle's classes, although you've exported them. This is, because, in OSGi (as you probably know), in order for a bundle to be able to see a class, its package needs to be imported.

But what about cases, where a bundle needs to load a class from a bundle, which has called it. In order for this to work, Eclipse has implemented buddy policies, which are designed exactly for this case:

  1. Your Clojure bundle needs to have manifest header Eclipse-BuddyPolicy: [dependent|registered].
  2. If you've added Eclipse-BuddyPolicy: registered, you'll need to add manifest header to the bundles, which uses Clojure: Eclipse-RegisterBuddy: <clojure-bundle-name>

Disclaimer: I don't have any experience with Clojure, but I wanted to take a shot at this.

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

3 Comments

This works. Here are some additional notes. 1) In your Clojure runtime plugin, you must export all packages in the jar. 2) You should probably use Eclipse-BuddyPolicy: registered in the runtime plugin and then the corresponding Eclipse-RegisterBudy entry in the dependent plugin. 3) If your dependent plugin is called by other plugins that don't directly depend on your Clojure runtime plugin, then your dependent plugin must reexport the Clojure runtime dependency.
This is probably a good enough workaround, but the proper way to do this is for the Clojure AOT to actually inject the necessary imports into the bundle, so you don't have to use the Eclipse buddies as it's going around the OSGi specification. But this would require Clojure AOT to do the right thing.
That presupposes that you're willing to AOT your clojure code.

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.