Clojure interop with Java: how to call a class?

641 views Asked by At

I have a Java app that has a class at this address, inside a standard Maven layout:

src/main/java/com/ollio/nlp/Transformer.java 

The class and method that I want looks like this:

package com.ollio.nlp;

public class Transformer {
    public String transform(String JSONInput) {

I store the jar artifact locally in my Clojure app at this address:

maven_repository/local/nlp/1.0-SNAPSHOT/nlp-1.0-SNAPSHOT.jar 

I have tried a dozen variations to import it into my Clojure app, such as:

 (:import
    [com.ollio.nlp.Transformer])

But I keep getting the error "No such namespace".

What is the correct way to import this?

EDITED:

Here is how I currently try to do the import statement:

(ns slick.query
  (:import
    [nlp.*])

I also tried:

(ns slick.query
  (:import
    [com.ollio.nlp.*])

I tried a few other variations.

The project.clj file looks like this:

(defproject slick "0.1"
  :description "slick is  an API for other ollio services, such as our mobile app."
  :dependencies [[org.clojure/clojure "1.6.0"]
             [com.taoensso/timbre "3.2.1"]
             [dire "0.5.1"]
             [slingshot "0.10.3"]
             [ring "1.4.0-RC1"]
             [clj-time "0.6.0"]
             [org.clojure/data.json "0.2.5"]
             [compojure "1.3.4"]
             [com.novemberain/monger "2.0.1"]
             [org.clojure/tools.namespace "0.2.4"]
             [manifold "0.1.0"]
             [me.raynes/fs "1.4.4"]
             [org.clojure/core.incubator "0.1.3"]
             [clj-stacktrace "0.2.7"]
             [overtone/at-at "1.2.0"]
             [ring/ring-json "0.3.1"]
             [clj-http "1.1.2"]
             [org.clojure/core.cache "0.6.4"]
             [cheshire "5.5.0"]
             [org.clojure/core.match "0.3.0-alpha4"]
             [local/nlp "1.0-SNAPSHOT"]]
  :repositories {"local" ~(str (.toURI (java.io.File. "maven_repository")))}
  :disable-implicit-clean true
  :source-paths      ["src/clojure"]
  :java-source-paths ["src/java"]
  :main slick.core
  :aot :all
  :jvm-opts ["-Xms100m" "-Xmx1000m" "-XX:-UseCompressedOops"])
2

There are 2 answers

4
Mars On BEST ANSWER

You probably want to change the last period in your :import statement into a space:

(ns mynamespace
  (:import [com.ollio.nlp Transformer]))

(EDIT: You can't use wildcards here. Every class that in com.ollio.nlp must be listed explicitly, separated by spaces.) That will allow you to use Transformer unqualified:

(.transform (Transformer. <add constructor args here>) my-json-input)

As @noisesmith said, the :import statement should be part of an ns declaration.

There's also a good chance that there are problems with the way that the project is set up. You've given no indication that that is likely, but it often happens when one is starting to use Java interop, I believe. (It happened to me, in any event.) So @AlanThompson's advice may be relevant.

You an also simply remove the :import statement, and use the Java class name in fully qualified form, e.g.:

(.transform (com.ollio.nlp.Transformer. <add constructor args here>) my-json-input)

If you get an error when you do that, then there's probably a problem with the setup (unless you're using the class incorrectly).

(I'm not sure how helpful any of this. Alan Thompson's answer is probably the appropriate one.)

1
Alan Thompson On

If you are mixing java and clojure source code in one project, you should first review the lein docs: https://github.com/technomancy/leiningen/blob/master/doc/MIXED_PROJECTS.md

Also, if you posted your project.clj and the layout of your java/clojure sources, it would be easier to spot what is missing.