java mixed with clojure in maven and eclipse - java

i created a sample polyglot program. i have a sensor and a robot implemented in java and AI implemented in clojure. and i can't connect maven properly
--src/main/java/clojuretest
|
DistanceSensor.java
AI.clj (uses DistanceSensor)
Robot.java (uses AI)
DistanceSensor.java:
package clojuretest;
public class DistanceSensor {
public int getValue() {return 5;}
}
AI.clj:
(ns clojuretest.AI
(:gen-class :methods [[isObstacleAhead [] boolean]]))
(defn -isObstacleAhead [this] (< (.getValue (clojuretest.DistanceSensor.)) 10))
Robot.java:
package clojuretest;
public class Robot {
public boolean shouldStop() {
return new AI().isObstacleAhead();
}
}
i can even manually force maven to compile it:
mvn clean clojure:compile produces error - no DistanceSensor class (but for some reason creates AI.class). so then
mvn compile sees AI.class and compiles everything correctly and tests pass. but what can i do to make mvn clean compile pass? how should my pom.xml look like? also what can i do to make eclipse stop complaining about non existing AI.class?

You need to change layout of source code in your project. Clojure maven plugin requires, that clojure code went to separate directory, so you should have following layout:
src/
main/
java/
java-code
clojure/
clojure code
test/
java/
java tests code
clojure/
clojure tests code
More details you can find in following article

I think :gen-class is usually a code smell, as is trying to instantiate such a class from Java code with new AI().
Here's an alternative approach that can solve this problem of cyclic dependencies:
Define AI as a Java interface in your Java code
Write a Clojure function to create an instance conforming to the interface using reify
Dynamically invoke the Clojure function from Java (e.g. using the technique outlined in this blog post)
You now have an instance of the AI interface that you can use however you like in Java
The advantage is this approach is that everything will work smoothly, in particular:
The Java code base can be compiled independently of the Clojure code
The Clojure code base can access all the defined Java classes and interfaces
You don't need any special IDE / Maven config. In fact, you can treat is as just a regular Java app that happens to include clojure.jar as a dependency.

You have an inter-dependency between Java code and Clojure code. No matter which type of classes you'll compile first, you'll get an error.
Since it's not an actual cyclic dependency, you can still fix this by splitting the Java compilation part in two.
First, compile DistanceSensor, which doesn't depend on anything else.
Second, compile AI, which depends on DistanceSensor.
Finally, compile Robot which depends on AI.
To split the java compilation in two steps, you need to configure the default execution of the maven-compiler-plugin so that it excludes Robot, and add another execution after the clujure:compile goal that excludes DistanceSensor. You'll probably have to misuse the phases to properly order the three executions.

Related

Scala 2.11 -> 2.12 -- Unit test fails in sbt, works in IntelliJ

I have a project that has been working under Scala 2.11, and I'm in the process of upgrading it to use Scala 2.12. I've got a unit test that fails when I run it on the command line through sbt, but it works fine when I run it through IntelliJ IDEA.
The error I get is:
java.lang.NoSuchMethodError: scala.Product.$init$(Lscala/Product;)V
The test is a JUnit test in Java, and it invokes code written in Scala.
The offending line in the unit test:
String paramsJson = adapter.sendReadyMessage();
The sendReadyMessage method (also Java) attempts to create a ReadyMessage:
ReadyMessage rm = new ReadyMessage(timestamp);
And a ReadyMessage is just a Scala case class
case class ReadyMessage(Timestamp: String) extends ToJson
And ToJson is a lift-JSON helper trait that encapsulates JSON generation:
import net.liftweb.json.{DefaultFormats, Serialization}
trait ToJson {
private implicit val formats = DefaultFormats
def toJson = Serialization.write(this)
}
The error appears to happen on the case class ReadyMessage line. The ToJson block is there for context.
Like I said, it works when I run it from within IntelliJ. It fails when I run it under sbt. It fails when it's part of the whole batch of tests in sbt, and it fails when I run it on its own in sbt.
Short of pasting my entire build.sbt file, I'm not sure what other information to include here that might be useful. It seems like it's some kind of version conflict, but I went through and updated all of the software version numbers I can find.
I realize this question covers an issue that may be more complex than can be reasonably debugged over SO. But even a "make sure you've updated XX in your build.sbt" response is helpful.
The answer turned out to be as annoying as the problem itself.
After many hours of searching my build, I realized that there was a "lib" directory in the subproject that was failing. I opened it up, and sure enough, it contained old versions of Scala and some other libs. I deleted those, made sure the libraryDependencies took care of them, and now everything builds and tests just fine.
Thanks to everyone for keeping me on board the "it's a Scala version mismatch" train. And let this be a cautionary tale, kids. Mix your managed and unmanaged dependencies at your own peril.

Compiling java class from non-java file

I have a set of ruby files where I have some string of type:
#something = [Whatever.new('1rabbit'),
Whatever.new('2rabbit'),
Whatever.new('3rabbit')]
I would like to parse out this information from the ruby file during compilation phase (javac run with maven - but i think it is no difference how javac is run), and create a .class enum of type:
public enum Something {
1RABBIT,
2RABBIT,
3RABBIT
}
and store it into the target folder. Then, I can use this enum whatever I want (after this initial compilation). I looked into AnnotationProcessors, and bytecode generation, but the first requires annotations, and the second is done during runtime. And I cannot find out how to do it properly.
What is the correct tool to do this, and how?
mavens life cycle has a generate sources phase. There you cold use the exec-maven-plugin to run a script generating the enums.

Jruby extend java class in another directory using Rubymine

I am somewhat new to RubyMine but here is my problem. I have a JRUBY Class that I want to extend from a Java class. My Java class is part of a submodule I have imported using git. This is my project structure:
src --> Submodule --> <Directories> --> ClassIWantToExtend.java
--> Ruby Code --> <Directories> --> JRubyClassThatExtendsJava.rb
However, when using RubyMine I have been unable to figure out how to extend this Java class. It can't seem to find it. My current class is blank. This is all I have:
require 'java'
class JRubyClassThatExtendsJava
end
I have tried using '<' and 'include' but when autofilling RubyMine can't seem to find my Java Class. I did just add the submodule using a CLI Git Command. Is it possible I have to add something for RubyMine to see it?
Thanks for any help in advance.
RubyMine, as far as I know (bought a license but never actually used it due this) does not include support for .java (not even a syntax highlighter) - the motivation seems to be that they have a separate product that is a Java IDE. thus this answer is not going to be RubyMine specific :
first you'll need to compile the .java sources and either pack them in a .jar or simply keep in mind what directory the .class files are (javac -d OUT_DIR)
than in your .rb you can either require 'path/to/packed.jar' or simply $CLASSPATH << 'path/to/classes/OUT_DIR'
... than you should be able to load the Java class and extend it in Ruby

How to make Gradle compile Groovy tests before Java tests

The Groovy plugin for Gradle claims that it "supports joint compilation, which allows to freely mix and match Groovy and Java code, with dependencies in both directions".
However, I don't think this applies to test code.
I have a Java 'sample' test in src/test/java... which uses a class which is located in src/test/groovy.
When trying to build with Gradle, I get an error like this:
SwingJavaFXSampleAppTestInJava.java:23: error: cannot find symbol
SwingJavaFXSampleAppTest swingJavaFx = new SwingJavaFXSampleAppTest();
Notice that SwingJavaFXSampleAppTest is a Groovy class that has not been compiled yet (in the Gradle output I can see that it did not run the compileTestGroovy before it tried compileTestJava because the former depends on the latter).
I am able to build this same project with Maven using the groovy-eclipse plugin.
Why does it not work in Gradle when it claims to support compilation in any order, and how can I make it work?
As explained in the Gradle User Guide, only code passed to GroovyCompile tasks is joint-compiled. So either you put both Java and Groovy code into src/main/groovy, or you reconfigure the source sets:
sourceSets.main.java.srcDirs = []
sourceSets.main.groovy.srcDirs = ["src/main/java", "src/main/groovy"]
For tests, replace all occurrences of main with test.
You should be able to move your java tests into src/test/groovy.

Conditional Java compilation

I'm a longtime C++ programmer, new to Java. I'm developing a Java Blackberry project in Eclipse. Question - is there a way to introduce different configuration sets within the project and then compile slightly different code based on those?
In Visual Studio, we have project configurations and #ifdef; I know there's no #ifdef in Java, but maybe something on file level?
You can set up 'final' fields and ifs to get the compiler to optimize the compiled byte-codes.
...
public static final boolean myFinalVar=false;
...
if (myFinalVar) {
do something ....
....
}
If 'myFinalVar' is false when the code is compiled the 'do something....' bit will be missed out of the compiled class. If you have more than one condition - this can be tidied up a bit: shift them all to another class (say 'Config.myFinalVar') and then the conditions can all be kept in one neat place.
This mechanism is described in 'Hardcore Java'.
[Actually I think this is the same mechanism as the "poor man's ifdef" posted earlier.]
you can manage different classpath, for example, implement each 'Action' in a set of distinct directories:
dir1/Main.java
dir2/Action.java
dir3/Action.java
then use a different classpath for each version
javac -sourcepath dir1 -cp dir2 dir1/Main.java
or
javac -sourcepath dir1 -cp dir3 dir1/Main.java
In JDK6, you can do it by using Java's ServiceLoader interface.
Check it here.
If you want this specifically for BlackBerry, the BlackBerry JDE has a pre-processor:
You
can enable preprocessing for your
applications by updating the Eclipseâ„¢
configuration file.
In C:\Program Files\Eclipse\configuration\config.ini,
add the following line:
osgi.framework.extensions=net.rim.eide.preprocessing.hook
If you enable preprocessing after you
have had a build, you must clean the
project from the Project menu before
you build the project again.
Then you can do things in the code like:
//#ifdef SOMETHING
// do something here
//#else
// do something else
//#endif
For details see Specifying preprocessor defines
Can one call that a poor mans ifdef: http://www.javapractices.com/topic/TopicAction.do?Id=64?
No, Java doesn't have an exact match for that functionality. You could use aspects, or use an IOC container to inject different implementation classes.
You can integrate m4 into your build process to effectively strap an analogue to the C preprocessor in front of the Java compiler. Much hand-waving lies in the "integrate" step, but m4 is the right technology for the text processing job.
Besides Maven, Ant and other build tools that provide similar functionality, one would rather build interfaces in Java and switch the implementations at Runtime.
See the Strategy Pattern for more details
In opposite to C/C++ this will not come with a big performance penality, as Javas JIT-compiler optimizes at runtime and is able to inline this patterns in most cases.
The big pro of this pattern is the flexibility - you can change the underlying Implementation without touching the core classes.
You should also check IoC and the Observer Pattern for more details.
You could use maven's resource filtering in combination mit public static final fields, which will be indeed get compiled conditionally.
private static final int MODE = ${mode};
...
if (MODE == ANDROID) {
//android specific code here
} else {
}
Now you need to add a property to your maven pom called "mode", which should be
of the same value as your ANDROID constant.
The java compiler should (!) remove the if and the else block, thus leaving your android code.
Not testet, so there is no guarantee and i would prefer configuration instead of conditional compilation.
There are a couple of projects that bring support for comment-based conditional compilation to Java:
java-comment-preprocessor
JPSG
Example in JPSG:
/* with Android|Iphone platform */
class AndroidFoo {
void bar() {
/* if Android platform */
doSomething();
/* elif Iphone platform */
doSomethingElse();
/* endif */
}
}
In eclipse you could use multiple projects
Main (contains common code)
Version1 (contains version1 code)
Version2 (contains version2 code)
Main -> Select Project->Properties->Java Build Path->Projects tab
Select Add...
Add "Version1" xor "Version2" and OK back to the workspace.
Version1 and Version two contain the same files but different implementations. In Main you normally write e.g.
import org.mycustom.Version;
And if you included Version1/Version2 project as reference it will compile with the Version.java file from Version1/Version2 project.

Categories

Resources