Gen-Class does not generate a .class file - java

I'd like to use Clojure code within Java. The Clojure code itself should implement a Java-interface (TestGenClassInterface).
My project.clj is:
(defproject com.stackoverflow.clojure/tests "0.1.0-SNAPSHOT"
:description "Tests of Clojure test-framework."
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.6.0"]
[instaparse "1.3.4"]]
:source-paths ["src/main/clojure"]
:java-source-paths ["src/main/java"]
:test-paths ["src/test/clojure"]
:java-test-paths ["src/test/java"]
;:aot :all
)
The Java interface looks like this:
package com.stackoverflow.clojure;
public interface TestGenClassInterface {
public String addToString(String text, String appendText);
}
The Clojure code is:
(ns com.stackoverflow.clojure.testGenClass
(:gen-class
:name com.stackoverflow.clojure.TestGenClass
:implements com.stackoverflow.clojure.TestGenClassInterface
:prefix "java-"))
(def ^:private pre "START: ")
(defn java-addToString [this text post]
(str pre text post))
(java-addToString "TexT" " :END")
I expected, that after running lein compile or "Run as Clojure-Application" in eclipse+CounterClockwise a .class file (named TestGenClass.class) is generated an saved within *compile-path* (here: target/classes/com/stackoverflow/clojure/). Unfortunately it's not.
When adding :aot :all to my project.clj, I get the following stacktrace:
Compiling com.stackoverflow.clojure.testGenClass
Exception in thread "main" java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.lang.Symbol, compiling:(com/stackoverflow/clojure/testGenClass.clj:1:1)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6651)
at clojure.lang.Compiler.analyze(Compiler.java:6445)
at clojure.lang.Compiler.analyze(Compiler.java:6406)
at clojure.lang.Compiler$BodyExpr$Parser.parse(Compiler.java:5782)
at clojure.lang.Compiler$TryExpr$Parser.parse(Compiler.java:2191)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6644)
at clojure.lang.Compiler.analyze(Compiler.java:6445)
at clojure.lang.Compiler.analyze(Compiler.java:6406)
at clojure.lang.Compiler$BodyExpr$Parser.parse(Compiler.java:5782)
at clojure.lang.Compiler$FnMethod.parse(Compiler.java:5217)
at clojure.lang.Compiler$FnExpr.parse(Compiler.java:3846)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6642)
at clojure.lang.Compiler.analyze(Compiler.java:6445)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6632)
at clojure.lang.Compiler.analyze(Compiler.java:6445)
at clojure.lang.Compiler.analyze(Compiler.java:6406)
at clojure.lang.Compiler$InvokeExpr.parse(Compiler.java:3665)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6646)
at clojure.lang.Compiler.analyze(Compiler.java:6445)
at clojure.lang.Compiler.analyze(Compiler.java:6406)
at clojure.lang.Compiler.compile1(Compiler.java:7221)
at clojure.lang.Compiler.compile1(Compiler.java:7216)
at clojure.lang.Compiler.compile(Compiler.java:7292)
at clojure.lang.RT.compile(RT.java:398)
at clojure.lang.RT.load(RT.java:438)
at clojure.lang.RT.load(RT.java:411)
at clojure.core$load$fn__5066.invoke(core.clj:5641)
at clojure.core$load.doInvoke(core.clj:5640)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invoke(core.clj:5446)
at clojure.core$compile$fn__5071.invoke(core.clj:5652)
at clojure.core$compile.invoke(core.clj:5651)
at user$eval9.invoke(form-init4595004281107083893.clj:1)
at clojure.lang.Compiler.eval(Compiler.java:6703)
at clojure.lang.Compiler.eval(Compiler.java:6693)
at clojure.lang.Compiler.load(Compiler.java:7130)
at clojure.lang.Compiler.loadFile(Compiler.java:7086)
at clojure.main$load_script.invoke(main.clj:274)
at clojure.main$init_opt.invoke(main.clj:279)
at clojure.main$initialize.invoke(main.clj:307)
at clojure.main$null_opt.invoke(main.clj:342)
at clojure.main$main.doInvoke(main.clj:420)
at clojure.lang.RestFn.invoke(RestFn.java:421)
at clojure.lang.Var.invoke(Var.java:383)
at clojure.lang.AFn.applyToHelper(AFn.java:156)
at clojure.lang.Var.applyTo(Var.java:700)
at clojure.main.main(main.java:37)
Caused by: java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.lang.Symbol
at clojure.lang.RT.seqFrom(RT.java:505)
at clojure.lang.RT.seq(RT.java:486)
at clojure.core$seq.invoke(core.clj:133)
at clojure.core$map$fn__4245.invoke(core.clj:2551)
at clojure.lang.LazySeq.sval(LazySeq.java:40)
at clojure.lang.LazySeq.seq(LazySeq.java:49)
at clojure.lang.RT.seq(RT.java:484)
at clojure.core$seq.invoke(core.clj:133)
at clojure.core$map$fn__4245.invoke(core.clj:2551)
at clojure.lang.LazySeq.sval(LazySeq.java:40)
at clojure.lang.LazySeq.seq(LazySeq.java:49)
at clojure.lang.Cons.next(Cons.java:39)
at clojure.lang.RT.boundedLength(RT.java:1654)
at clojure.lang.RestFn.applyTo(RestFn.java:130)
at clojure.core$apply.invoke(core.clj:624)
at clojure.core$mapcat.doInvoke(core.clj:2586)
at clojure.lang.RestFn.invoke(RestFn.java:423)
at clojure.core$generate_class.invoke(genclass.clj:164)
at clojure.core$gen_class.doInvoke(genclass.clj:638)
at clojure.lang.RestFn.invoke(RestFn.java:1557)
at clojure.lang.Var.invoke(Var.java:519)
at clojure.lang.AFn.applyToHelper(AFn.java:270)
at clojure.lang.Var.applyTo(Var.java:700)
at clojure.lang.Compiler.macroexpand1(Compiler.java:6552)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6630)
... 46 more
Compilation failed: Subprocess failed

The proximate issue you have is a missing :aot :all in your project.clj file. Without that the ahead-of-time compilation will not be attempted.
Once you put that in, you'll have the following further issues:
you must prefix the names of the functions designated to become Java methods (default prefix is -);
you must include this as an explicit first argument of each such method (this is the recommended convention, but any name is acceptable);
you must correct your :implements clause: it takes a vector as the value, even if it has a single member.

According to http://clojure.org/compilation
... the implementation functions for instance methods will always take an
additional first arg corresponding to the object the method is called
upon, called by convention 'this' here.
Try adding 'this' to each function definition.
(defn java-addToString [this text post]
...

http://clojure.org/compilation mentions the compilation process makes use of
... *compile-path*, which must be in the classpath
The default location is a classes folder.
The second answer to Stack Overflow question Compiling Clojure? mentions that this path is relative to the jvm startup folder. If you did lein repl from the main project folder (the folder where project.clj lives) then creating a classes folder there should make it work.

Related

Standard Method TEXT is undefined when compiling jasper report

When I package my stand-alone-java-application, that compiles, renders and prints Jasper-Reports, in a fat jar with all dependencies, I get the error that the function TEXT – a function used in the report and defined in the net.sf.jasperreports-functions-library is not found.
The method TEXT(Integer, String) is undefined for the type [...]
value = IF(LEN(TEXT(((java.lang.Integer)parameter_X.getValue()),"#"))==2,"***",REPT("*",6-LEN(TEXT(((java.lang.Integer)parameter_X.getValue()),"#")))) //$JR_EXPR_ID=58$
Other functions from the same library work. When I run the application with gradle run, the function is found and the report can be printed. The library is on my classpath.
There are several similar questions on this site and Stackoverflow, but neither provided answers, that worked for me. In the following, I will explain what I tried:
In my build.gradle-File I defined dependencies to the following libraries:
implementation('net.sf.jasperreports:jasperreports:6.18.1')
implementation('net.sf.jasperreports:jasperreports-functions:6.18.1')
In my java-Files, I created a DesignFile and statically imported the functions into it. I tried two methods:
Method 1 as given in an answer in this thread: Unresolved symbols when compiling jasper report
/*…*/
designFile = JRXmlLoader.load(sourceFile.getAbsolutePath());
designFile.addImport("static net.sf.jasperreports.functions.standard.TextFunctions.*");
designFile.addImport("static net.sf.jasperreports.functions.standard.MathFunctions.*");
designFile.addImport("static net.sf.jasperreports.functions.standard.DateTimeFunctions.*");
designFile.addImport("static net.sf.jasperreports.functions.standard.LogicalFunctions.*");
JasperReport compiledReport = JasperCompileManager.getInstance(ctx).compile(designFile);
/*…*/
Method 2: importing each function on its own
public static String[] textFunctions(){
return new String[]{"BASE", "CHAR", "CLEAN", "CODE", "CONCATENATE", "DOUBLE_VALUE",
"EXACT", "FIND", /*"FIXED", */"FLOAT_VALUE", "INTEGER_VALUE", "LEFT", "LEN", "LONG_VALUE",
"LOWER", "LTRIM", "MID", "PROPER", "REPLACE", "REPT", "RIGHT", "RTRIM", "SEARCH", "SUBSTITUTE",
"T", /*"TEXT",*/ "TRIM", "UPPER"};
}}
/*…*/
designFile = JRXmlLoader.load(sourceFile.getAbsolutePath());
for (String textFunction : textFunctions()){
designFile.addImport("static net.sf.jasperreports.functions.standard.TextFunctions." + textFunction);
}/* similarly for logical functions, numeric functions and datetime functions*/
}
JasperReport compiledReport = JasperCompileManager.getInstance(ctx).compile(designFile);
/*…*/
As you can see, the function TEXT is commented out. That’s because the program fails at runtime when run with “gradle run”, when I comment it in:
net.sf.jasperreports.engine.JRException: Errors were encountered when compiling report expressions class file:
1. The import net.sf.jasperreports.functions.standard.TextFunctions.TEXT cannot be resolved
import static net.sf.jasperreports.functions.standard.TextFunctions.TEXT;
The same thing is true with most datetime-functions, in fact, only TIME can be imported to the DesignObject without error at runtime
In addition to that, when I type net.sf.jasperreports.functions.standard.TextFunctions. in my IDE, the content-assist shows a list of available functions, yet TEXT is missing.
I suspected, that the function is simply missing in the library, but it is there. In the .gradle/cache/modules-2/files-2.1/… directory, there is the jar with the TextFunctions.java, that contains the function TEXT:
When building the FatJar with dependencies, I have a TextFunctions.class-File in it, that contains the TEXT-Function as well.
In my jar, there are two jasperreports_extension.properties on the root level:
with the smaller one (from the jasperreport-functions-dependency) containing the following lines:
net.sf.jasperreports.extension.registry.factory.functions=net.sf.jasperreports.functions.FunctionsRegistryFactory
net.sf.jasperreports.extension.functions.datetime=net.sf.jasperreports.functions.standard.DateTimeFunctions
net.sf.jasperreports.extension.functions.math=net.sf.jasperreports.functions.standard.MathFunctions, net.sf.jasperreports.functions.standard.LogicalFunctions
net.sf.jasperreports.extension.functions.text=net.sf.jasperreports.functions.standard.TextFunctions
net.sf.jasperreports.extension.functions.report=net.sf.jasperreports.functions.standard.ReportFunctions
Funnily enough, commenting out TEXT, running it locally with gradle run, it works without problems. But packaging it and running it with java -jar it fails to find this function. And statically importing this function leads to gradle run failing as well.
What is happening and how can I fix this? I want to distribute my FatJar on a server and run it, but this problems makes it impossible for me.

Using lmdbjava in Clojure

I'm trying to use lmdbjava in Clojure, but I'm struggling.
(import '[org.lmdbjava Env])
(def path (clojure.java.io/file "/tmp"))
(.open (.setMaxDbs (.setMapSize (Env/create) 10485760) 1) path)
(p.s. I realise there are cleaner ways. This is just for testing purposes.)
This is the error:
IllegalArgumentException No matching method found: open for class java.lang.Class clojure.lang.Reflector.invokeMatchingMethod (Reflector.java:53)
I've also tried this:
(.open (.setMaxDbs (.setMapSize (Env/create) 10485760) 1) path org.lmdbjava.EnvFlags/MDB_NOLOCK)
and this:
(.. (Env/create) (setMapSize 10485760) (setMaxDbs 1) (open path org.lmdbjava.EnvFlags/MDB_NOLOCK))
And I get this error:
ClassCastException org.lmdbjava.EnvFlags (in module: Unnamed Module) cannot be cast to [Lorg.lmdbjava.EnvFlags; (in module: Unnamed Module) user/eval1339 (form-init2868059116743223586.clj:1)
I realise I'm probably doing something daft, because I'm new to both Java and Clojure. Any help would be greatly appreciated!
By the way, this is the tutorial I'm following:
https://github.com/lmdbjava/lmdbjava/blob/master/src/test/java/org/lmdbjava/TutorialTest.java
Thanks!
From the signature of the Env.Builder class:
Env<T> open(File path, int mode, EnvFlags... flags)
you also have to supply a EnvFlags varargs parameter. This is how you do it in Clojure:
(.open (.setMaxDbs (.setMapSize (Env/create) 10485760) 1) path (into-array org.lmdbjava.EnvFlags []))
Also see How to handle java variable length arguments in clojure?

Why doesn't figwheel pass the compiled app to the browser?

I'm using Leiningen 2.5.2 (Java 1.8.0_45-internal Open JDK 64-bit), and the reagent-template (i.e. lein new reagent foo).
This runs okay with lein figwheel as expected.
Next, the first thing I do is break out the "Views" functions into separate files and add them to the app namespace:
core.cljs snippet:
;; -------------------------
;; Views
(:require home-page)
home-page.cljs (whole file):
(ns foo.core)
(defn home-page []
[:div [:h2 "Welcome to foo"]
[:div [:a {:href "#/about"} "go to about page"]]])
When I go to view the app in the browser (chromium or firefox), it gets stuck at "ClojureScript has not been compiled!" despite seemingly compiling successfully in the terminal. If I enter commands in the figwheel REPL, I see the green Clojure logo when it is working in the browser, so I know it's connected.
I had this working in a reagent app some months ago--what happened? How should I separate my view code? (A single file is unmanageable; that's a lot of Hiccup.)
If you really have only the line (:require home-page) in core.cljs, this should be the culprit. The colon notation :require is only valid inside a namespace declaration with ns. Also, you declare the core namespace in the wrong file (home-page.cljs, not core.cljs). Take a look at this article on namespaces in Clojure for a thorough explanation.
You will want the following in core.cljs:
(ns foo.core
(:require [foo.home-page :as hp :refer [home-page]]))
.... more core.cljs code ...
and then simply in home-page.cljs:
(ns foo.home-page
(:require ....reagent namespaces as needed ....
(defn home-page [] ....

Clojure interop with Java: how to call a class?

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"])
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.
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.)

How to put javaScript code in Java program/application?

Trying to put in your application code of Ace Editor: http://ace.c9.io/#nav=embedding.
I found something like this: http://metoojava.wordpress.com/2010/06/20/execute-javascript-from-java/
and I put this code:
engine.eval(new java.io.FileReader("ace-builds/src-noconflict/ace.js"));
But I have build errors.
Exception in thread "main" javax.script.ScriptException: sun.org.mozilla.javascript.internal.EcmaError: ReferenceError: "window" is not defined. (<Unknown source>#1513) in <Unknown source> at line number 1513
at com.sun.script.javascript.RhinoScriptEngine.eval(RhinoScriptEngine.java:224)
at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:249)
at javaapplication9.JavaApplication9.main(JavaApplication9.java:28)
Caused by: sun.org.mozilla.javascript.internal.EcmaError: ReferenceError: "window" is not defined. (<Unknown source>#1513)
at sun.org.mozilla.javascript.internal.ScriptRuntime.constructError(ScriptRuntime.java:3770)
at sun.org.mozilla.javascript.internal.ScriptRuntime.constructError(ScriptRuntime.java:3748)
at sun.org.mozilla.javascript.internal.ScriptRuntime.notFoundError(ScriptRuntime.java:3833)
at sun.org.mozilla.javascript.internal.ScriptRuntime.nameOrFunction(ScriptRuntime.java:1826)
at sun.org.mozilla.javascript.internal.ScriptRuntime.name(ScriptRuntime.java:1765)
at sun.org.mozilla.javascript.internal.Interpreter.interpretLoop(Interpreter.java:1785)
at sun.org.mozilla.javascript.internal.Interpreter.interpret(Interpreter.java:849)
at sun.org.mozilla.javascript.internal.InterpretedFunction.call(InterpretedFunction.java:162)
at sun.org.mozilla.javascript.internal.ContextFactory.doTopCall(ContextFactory.java:430)
at com.sun.script.javascript.RhinoScriptEngine$1.superDoTopCall(RhinoScriptEngine.java:116)
at com.sun.script.javascript.RhinoScriptEngine$1.doTopCall(RhinoScriptEngine.java:109)
at sun.org.mozilla.javascript.internal.ScriptRuntime.doTopCall(ScriptRuntime.java:3160)
at sun.org.mozilla.javascript.internal.InterpretedFunction.exec(InterpretedFunction.java:173)
at sun.org.mozilla.javascript.internal.Context.evaluateReader(Context.java:1169)
at com.sun.script.javascript.RhinoScriptEngine.eval(RhinoScriptEngine.java:214)
... 2 more
Do any of you know how can I do this?
Thans for help and Happy Holidays!
Keep in mind that you are executing a Javascript file out of context.
This Javascript file is usually executed with the browser JS engine so if you are not in that context you could not access to some objects like navigator, window... etc.

Categories

Resources