I have a Scala project and I would like to export it as a jar.
*1. At first I tried creating a Java class for the project as an entry point
public class JMain {
public static void main(String[] args) {
System.out.println("Java main calling Scala main");
SMain.main(new String[] {""}); //SMain.main is the actual *main*
and this worked fine and dandy when launched from Eclipse, but when I export it as jar it'll give me 18 exceptions or so. I do now know how to replicate then "environment" in which Eclipse manages to launch this and I'm prety sure it relies on the fact that Scala is on my system already - I need a self contained jar with everything packed in there.
*2. My second try consisted of trying what lach suggested here How to deploy a Scala project from Eclipse?
namely:
public class JMain {
public static void main(String[] args) {
System.out.println("Java Main");
List<String> argList = new ArrayList<String>();
argList.add("fully.qualified.ClassName"); //???
for (String s : args) argList.add(s);
scala.tools.nsc.MainGenericRunner.main(argList.toArray(new String[0]));
This time it won't even run from Eclipse, although it gives only 6 or so exceptions starting with the famous NoClassDefFoundError. I have a feeling I'm not getting fully.qualified.ClassName right. *3. If the main Scala class is called "Dis.scala" and is located in package "pack" shouldn't this fully.qualified.ClassName be "pack.Dis"?
I'm using Jre 1.6 and Scala 2.9.2
EDIT: I have included all external imported jars, even scala-library.jar - everything is nice and packed in the jar
P.S. I am not familiar with Ant or Maven or Sbt. I just want my Scala project jared - if possible without getting into hairy things.
Here is what worked for me:
1. Create scala project
2. Create Wrapper java project
3. Add the scala-library.jar to you java project build path.
So you only need the 3rd step in addition since the rest looks similar to what I did. Then you can happily use: java - jar file.jar
EDIT:
How to create a JAR File which contains Scala/Code which can be consumed by another Java Project, using Scala - Eclipse IDE.
Create a new Scala Project and define an object with a main method as entry point.
Now create a new Java Project and add your Scala Project to the new ones buildpath. Additionally add the scala-library.jar to the Java project.
Now create a Wrapper class in the java project which calls your entry point class from the scala lib. Run the wrapper class to create a eclipse run configuration and test if you can call the scala project.
Use the Export->Java->Runnable JAR file, Wizard now on the wrapper project.The eclipse run configuration will be used as entrypoint into the JAR. Depending on your needs you may want to :
extract required libraries into generated JAR
or
Package required libraries into generated JAR
Finally you get a complete packaged JAR which you can use like this:
java - jar wrapped.jar
For me, it was relatively straightforward.
Develop and test the project using the scala IDE (or eclipse for java).
once ready, generate the jar for the project using file -> export method.
for submitting the spark (i was writing something for spark), i just had to mention --class option for specifying the main class for the jar.
hope to help.
Related
I know there are a lot of questions that seem similar. I have also spent a few hours getting to grips with Gradle multiprojects. But I still don't understand what the best course of action is here. Incidentally I am using Groovy as my coding language, but explanations referencing Java would be just as good.
I have developed an Eclipse Gradle project, "ProjectA", which in particular has a class, IndexManager, which is responsible for creating and opening and querying Lucene indices.
Now I am developing a new Eclipse Gradle project, "ProjectB", which would like to use the IndexManager class from ProjectA.
This doesn't really mean that I would like both projects to be part of a multiproject. I don't want to compile the latest version of ProjectA each time I compile ProjectB - instead I would like ProjectB to be dependent on a specific version of ProjectA's IndexManager. With the option of upgrading to a new version at some future point. I.e. much as with the sorts of dependencies you get from Maven or JCenter...
Both projects have the application plugin, so ProjectA produces an executable .jar file whose name incorporates the version. But currently this contains only the .class files, the resource files, and a file called MANIFEST.MF containing the line "Manifest-Version: 1.0". Obviously it doesn't contain any of the dependencies (e.g. Lucene jar files) needed by the .class files.
The application plugin also lets you produce a runnable distribution: this consists of an executable file (2 in fact, one for *nix/Cygwin, one for Windows), but also all the .jar dependencies needed to run it.
Could someone explain how I might accomplish the task of packaging up this class, IndexManager (or alternatively all the classes in ProjectA possibly), and then including it in my dependencies clause of ProjectB's build.gradle... and then using it in a given file (Groovy or Java) of ProjectB?
Or point to some tutorial about the best course of action?
One possible answer to this which I seem to have found, but find a bit unsatisfactory, appears to be to take the class which is to be used by multiple projects, here IndexManager, and put it in a Gradle project which is specifically designed to be a Groovy library. To this end, you can kick it off by creating the project directory and then:
$ gradle init --type groovy-library
... possible to do from the Cygwin prompt, but not from within Eclipse as far as I know. So you then have to import it into Eclipse. build.gradle in this library project then has to include the dependencies needed by IndexManager, in this case:
compile 'org.apache.lucene:lucene-analyzers-common:6.+'
compile 'org.apache.lucene:lucene-queryparser:6.+'
compile 'org.apache.lucene:lucene-highlighter:6.+'
compile 'commons-io:commons-io:2.6'
compile 'org.apache.poi:poi-ooxml:4.0.0'
compile 'ch.qos.logback:logback-classic:1.2.1'
After this, I ran gradle jar to create the .jar which contains this IndexManager class, initially without any fancy stuff in the manifest (e.g. name, version). And I put this .jar file in a dedicated local directory.
Then I created another Gradle project to use this .jar file, the critical dependency here being
compile files('D:/My Documents/software projects/misc/localJars/XGradleLibExp.jar' )
The file to use this class looks like this:
package core
import XGradleLibExp.IndexManager
class Test {
public static void main( args ) {
println "hello xxx"
Printer printer = new Printer()
IndexManager im = new IndexManager( printer )
def result = im.makeIndexFromDbaseTable()
println "call result $result"
}
}
class Printer {
def outPS = new PrintStream(System.out, true, 'UTF-8' )
}
... I had designed IndexManager to use an auxiliary class, which had a property outPS. Groovy duck-typing means you just have to supply anything with such a property and hopefully things work.
The above arrangement didn't run: although you can do build and installdist without errors, the attempt to execute the distributed executable fails because the above 6 compile dependency lines are not present in build.gradle of the "consumer" project. When you put them in this "consumer" Gradle project's build.gradle, it works.
No doubt you can add the version to the generated .jar file, and thus keep older versions for use with "consumer" projects. What I don't understand is how you might harness the mechanism which makes the downloading and use of the dependencies needed by the .jar as automatic as we are used to for things obtained from "real repositories".
PS in the course of my struggles today I seem to have found that Gradle's "maven-publish" plugin is not compatible with Gradle 5.+ (which I'm using). This may or may not be relevant: some people have talked of using a "local Maven repository". I have no idea whether this is the answer to my problem... Await input from an über-Gradle-geek... :)
You should be able to update the Eclipse model to reflect this project-to-project dependency. It looks something like this (in ProjectB's build.gradle):
apply plugin: 'eclipse'
eclipse {
classpath.file.whenMerged {
entries << new org.gradle.plugins.ide.eclipse.model.ProjectDependency('/ProjectA')
}
project.file.whenMerged {
// add a project reference, which should show up in /ProjectB/.project's <projects> element
}
}
These changes may be to the running data model, so they may not actually alter the .classpath and .project files. More info can be found here: https://docs.gradle.org/current/dsl/org.gradle.plugins.ide.eclipse.model.EclipseModel.html
This issue is discussed here: http://gradle.1045684.n5.nabble.com/Gradle-s-Eclipse-DSL-and-resolving-dependencies-to-workspace-projects-td4856525.html and a bug was opened but never resolved here: https://issues.gradle.org/browse/GRADLE-1014
I am try to migrate my current project to be able to compile and run it on java 9. I am trying first to just move a java8 based project to java9 without not much effort which means not moving to jigsaw basically.
The project structure is something like
myjava-service [myjava-service-parent] parent-pom with the following modules
- myjava-service
- myjava-service-common
- myjava-service-test
it compiles perfectly with mvn clean package and it runs when I execute that fat.jar
the nightmare starts when I try to run it using intellij,to run on intellij i have to set the module I want to execute which is myjava-service but then apparently intellij understand it as java 9 module and well a lot of split packages issues, classes not found and other issues that I am struggling to fix, so my question is there a way to run the service on intellij under the java 9 environment without the new java module system being triggered somehow?
for the record issues like
java.lang.module.ResolutionException: Modules javax.annotation.api and annotations export package javax.annotation to module javax.el
So, apparently someone stepped into the same issue that I was facing, so what happens is that when your service start by a class which is not part of your sources (in my case my service is started by Starter class from the Vertx jar) then IDEA end up using the module path instead of class path. luckily Intellij team was quite helpful, follow up the ticket
https://youtrack.jetbrains.com/issue/IDEA-187390 , for the next version IDEA will abstain from using module path when there is no module-info file in sources.
Also for those who need desperately run a service in java 9 there's a work around which is basically create a Main class and Invoke it inside the class that starts your service, in my Case it looked like
public class Start {
public static void main(String[] args) {
Starter.main(args);
}
}
I have an existing web application, A, which is a Maven project in Eclipse. It is run on a Tomcat 8 localhost server. Now I have a Java application, B, that was a separate project on its own. I have imported B into my workspace with A as another project. I am trying to run a main class (called App.java) which exists in B from a class within A. The class within A is below:
public void runOrgReportUtility() throws IOException {
int k = runProcess("javac /Users/ag/utilities/org-report-utility/src/main/java/com/vs/orgreport/App.java", null);
if (k==0) {
log.info("Compiled. Now trying to run class.");
String commandStr = "java -cp /Users/ag/utilities/org-report-utility/src/main/java/com/vs/orgreport/ App";
log.info("Command String: ");
log.info(commandStr);
runProcess(commandStr);
}
public int runProcess(String command, String[]) throws Exception {
Process pro = Runtime.getRuntime().exec(command);
pro.waitFor();
return pro.exitValue();
}
When I tried running A, the console gave me a bunch of error: cannot find symbol, for various classes within B. This made me realize that only the App.java was being compiled and run, and not the other dependent classes in B.
How can my second java application be compiled and run when I start up my original web application?
Things I have tried:
Set (original) project references to include secondary Java app
Add Java app project to Java build path (in Projects tab) of original project
Added Java app to Deployment Assembly of original project
Do not compile the application when you want to call it. This is bad:
Compiling with javac is hard due to all the dependencies. As you found out, it is not a simple matter of invoking javac on a single java file.
Why wait until you try to run it to find out that you have an error that keeps it from compiling?
Why incur the overhead of compiling it every time you run it?
You normally would use maven to compile B and probably use the maven-shade-plugin to create a B.jar that contains B and all dependencies (aka a "fat" jar). Then when A invokes B, you can use the fat jar as the classpath when you invoke the app that it contains.
Other things you might consider:
You could probably also include the fat jar in your web application so that you are not dependent on having an external jar that must be in place in order for your web application to be fully functional.
Rather than execute the other application in a separate process, run it in the same JVM by just calling App.main() directly. You might want it to run in a separate thread, which is easy to do.
If you really want a separate OS process, use ProcessBuilder rather than Runtime.exec. In many cases, it is an easier API to use and get right.
I have some code in an Android project that parses HTML using Jsoup. It doesn't use anything Android specific, they're just static methods that take an InputStream, and return my model classes. The app uses Gradle to build itself in Android Studio.
Is there any way I can create a standard Java main method to do something like load HTML from a local file, run it through my parser, and output a JSON file (using Gson on my model class)? I'm thinking maybe I can add a new sourceSet to Gradle like a jvmCompatible set of classes? I would greatly prefer not to copy my code to a separate project.
EDIT:
I guess I didn't make this clear, but I would like the be able to run this locally on my dev machine from the command line, rather than on an Android device or emulator.
You don't necessarily need to do anything in the build file to set this up; the build file generates Java .class files, and you can feed them to Java directly from the command line. You can add a main method to any class:
package com.example.foo;
class MyClass {
...
public static void main(String [] args) {
...
}
}
The main method will be happily ignored util you invoke it via the Java command line. You can do this by setting your classpath to the intermediate build directory and telling the Java command line which class to start:
java -classpath app/build/intermediates/classes/debug/ com.example.foo.MyClass
where you pass in the path to the build/intermediates/classes/debug directory in your app module's build output, and the fully-qualified name of the class.
Note that if you're running a release build that uses ProGuard, this main method could get stripped out if it's not otherwise referenced in the code.
Make sure you don't access any Android classes or you'll get a runtime error.
As an aside, you might find it worthwhile to separate out your Java-only code into a Java-only module in the build. Among other things, it would let you use JUnit to write nice test cases for the classes within; if you're asking this question because you want to do some testing of your parser, you might find it convenient to do so within the auspices of a unit test.
I have two Eclipse plugins:
plugin-1: provides a package in .jar to other plugins. (a Java Wrapper for a C++ library) This plugin was created by clicking File->New->Other->Plug-in from Existing JAR Archives.
plugin-2: has the native library .so for plugin-1 (Bundle-NativeCode directive is in MANIFEST.MF) and instantiates a class from plugin-1
(I actually tried putting the .so in plugin-1, but I cannot seem to load the library, even with the Bundle-NativeCode directive in the plugin-1 MANIFEST.MF, outside of the plugin project that contains the .so, so I guess I have to bundle the .so with any plugin that uses plugin-1.)
I am running a JUnit tests from plugin-2 which instantiates MyClass from plugin-2 which, in turn, instantiates MyLibraryClass from plugin-1. MyClass successfully loads the native library and instantiates MyLibraryClass without an UnsatisfiedLinkError or other exception being thrown from either the loading of the native library or from instantiating MyLibraryClass. I am not running a plugin in this case -- just the JUnit tests.
When I run plugin-2 (using a product configuration) and instantiate MyClass, the native library loads fine but I get an UnsatisifiedLinkError when MyClass instantiates MyLibraryClass. In this case, I believe the library is being loaded based on the output I get from using the class described in the posting How do I get a list of JNI libraries which are loaded?
NOTE: I'm using Eclipse 3.6.1.
Here is a code sample that shows the essence of what I'm trying to do:
package com.mylibrary;
import com.external_library.MyLibraryClass;
public class MyClass {
public static void loadLibrary() {
// Without Bundle-NativeCode in MANIFEST.MF I get
// "java.lang.UnsatisfiedLinkError: no mylibrary_java in java.library.path"
System.loadLibrary("mylibrary_java"); // Loads libmylibrary_java.so.
// Works fine from JUnit Test
// When I run the plugin, I get an UnsatisfiedLinkError:
// "java.lang.UnsatisfiedLinkError:
// com.external_library.MyLibrary_javaJNI.new_MyLibraryClass__SWIG_3()J"
MyLibraryClass instance = new MyLibraryClass();
}
}
I have replicated your setup and I get the same exception.
The problem could be solved by:
add the native library to plugin-1
add the Bundle-NativeCode directive to plugin-1's Manifest
load the library in the static constructor of plugins-1's Activator (you can write one and add it to the plugin)
Some other possible sources of errors:
Be aware that the package path, the class name and the method signatures should never be changed for any class with native bindings. Otherwise JNI would not be able to find the native counterpart and you get an UnsatisfiedLinkError. In your import directive you specified the following classname com.external_library.MyLibraryClass, but your error message has a different classname com.external_library.MyLibrary_javaJNI. Check for these sources of errors.
Some additional explanations:
A JUnit test in contrast to an JUnit plugin test starts no OSGi environment. Therefore you have a plain Java application with an ordinary JUnit test. If your native lib and your application are contained in the same folder (top level) the native lib will be automatically found on windows. If that is also true on UNIX systems, this would be an explanation why your JUnit test is successful. If it lies in a different folder, you have to specify the Java Library Path for an ordinary Java application.
EDIT by MrMas:
Modify plugin-2 so it doesn't depend on plugin-1 by adding the .jar file to plugin-2.
Copy the .jar file into plugin-2. I put it in the same directory as the .so.
Add the jar to the project via: Project->Properties->Libraries->Add Jar
Add the jar to the class path via plugin.xml->Runtime->ClassPath section->Add
Export the packages from the Jar (if they're needed by downstream plugins)
Remove the dependence of plugin-1 from the plugin.xml->dependencies tab
Now you can load the library with a System.loadLibrary and use the classes from within the plugin and from another plugin.
I chose not to modify plugin-1 because it was created as a plugin from an existing jar to which I couldn't discover how to add an Activator. I instead chose the path of adding the .jar to plugin-2. See Adding jars to a Eclipse PlugIn for additional discussion.
Bundle-NativeCode is an OSGI-tag. This means only OSGI classloaders are using it. In my case, I had an E4-RCP application. One plugin contained the Java class. The native code, however, I put into a fragment.
When loading and looking for a library, the OSGI classloader has a list of fragments (according to the naming of the structure involved) and examines their Bundle-NativeCode using the class NativeCodeFinder. If one has troubles, try to add breakpoints at the relevant functions. getNativePath() returns the entries as read by the OSGIpart.