I'm trying to use Google protocol buffer for Java(I'm a newbie about Java, just trying).
First of all, I'm using OSX and I've installed protocol buffer with brew install protobuf command.
protoc command works okay.
I've generated MyProtocol.java by protoc.
I've installed protocol buffer for Java as its instruction(README.txt).
mvn install command created .m2 directory and I can find protobuf-java-2.4.1.jar file somewhere in the directory.
I wrote simple test Java code just importing MyProtocol.java and it complains could not find package com.google.protobuf.
So, I've just make jar file mvn package and add its directory as CLASSPATH and it compiled well.
javac -classpath <protobuf-dir>/jara/target/classes Test.java ./com/example/tutorial/AddressBookProtos.java
If I use maven's repository directory (~/.m2/repository), it complains again.
Doesn't maven make CLASSPATH for me if I install the package?
If not, how can I use installed package by maven to compile my code?
The Maven Dependency Plugin has a goal called build-classpath which does what you need. You can get usage hints on the Usage page
Maven doesn't change your setup, so it's up to you to set your CLASSPATH according to your need.
However there are at least two ways in which Maven can halp you:
You can use the Maven Assembly plugin to collect all your dependencies in a directory or an archive, so that you only need to add a single directory to your CLASSPATH in order to run your program;
You can use the Exec Maven plugin to add the running of your program as a goal in your POM and then run it with Maven.
Related
How can I compile a java file located inside a maven project only using javac commands and output the resulting class file to the appropriate package under target folder? Giving -d flag seems to be the right thing to do in terms of giving the directory in which the class file will be outputted to but I get linker errors (symbol not found). I tried to pass imported classes by using flag -cp path2class/importedClass1.java:path2class/importedClass2.java but that doesn't seem to eliminate linker errors.
I am aware of the existence of mvn compile but what I am specifically looking for a way to do this using javac.
May be you need to describe your scenario more specific
mvn is a tool for compile \ build \ pacakge your java projects, which should be a combination of java classes.
mvn also support some task plugin like maven ant plugin to do some task during the maven building process
I guess you could check the ant plugin to reach your desitination.
https://maven.apache.org/plugins/maven-antrun-plugin/
TL;DR: Is there a standard way in the Java world, to have the build tools install the executables they just built (like the make install of the C world)?
(I would be happy with a solution that would work only on Linux)
More details:
I have a Java project distributed via github. Compilation and dependencies are managed with maven 2. Running mvn package builds a tarball with my jar and the dependencies needed at runtime, plus an executable script which set the classpath and launch the main jar:
#!/bin/bash
cpBase="$(dirname "$0")"
java -cp "$cpBase/*" dw.cli.Program $#
So, if someone wants to install this on her computer, one need to:
run mvn package
and then to unpack the tarball and to copy the content in a directory on her PATH.
On the other hand I like the way the autotools are working: the user doesn't need to copy anything manually, because the build step make install handles the installation for her.
I could emulate this behaviour using cp through ant tasks in my pom.xml, but I'm more interested in learning the Java good practices than to provide non standard behaviors.
It seems maven doesn't provide this behavior. On the other hand, I'm totally ignorant of what the other Java build tool can do wrt to this.
Edit:
As far as I understand mvn install and mvn deploy don't fit my need, because they will install my jar in my local or remote repository. Whereas I want to install my executables on my PATH (eg: to install my wrapper script in /usr/local/bin)
The question is tagged "gradle", so I'll supply the Gradle answer.
I take it you're building an application, not a library. In that case, Gradle is thoughtfully supplying the application plugin.
apply plugin: 'application'
The plugin will supply you the run, distZip, distTar and installDist tasks, which do just what they sound like. Check out the documentation at
the official web site.
Note that the installDist task doesn't, by default, put the software anywhere centrally on the system. Rather, it will install in a subdirectory of build, where temporary files are kept. You could set the destinationDir property on the task to remedy this.
You can created a distribution archive (zip, tar.gz) which can be downloaded by the user and only needed to unpack and add the bin folder to the path.
The problem is that you can't automatically enhance you path environment variable. But if you use the generated scripts from appassembler-maven-plugin you can simply can call directly the generated scripts without enhancing your path. This works on linux as well as on windows.
This can be achieved by a combination of appassembler-maven-plugin and maven-assembly-plugin.
The appassembler-maven-plugin will create the appropriate shell/bat/cmd files for you and the maven-assembly-plugin can create the appropriate archives (tar.gz, zip) for you.
As an example you can take a look here:
https://github.com/khmarbaise/supose/tree/master/supose-assembly
"make install" works by copying your built artefacts into their target location. This behaviour is quite easy to emulate in ANT, because like make it allows you to specify your own build logic:
<target name="install" description="Copy binaries into install location">
<mkdir dir="/opt/myapp/bin"/>
<copy file="${dist.dir}/myproject.jar" todir="/opt/myapp/bin"/>
<copy file="${dist.dir}/myproject.sh" todir="/opt/myapp/bin"/>
<chown owner="${install.owner}">
<fileset dir="/opt/myapp" include="**/*"/>
</chown>
</target>
Course you'd have to run this target as root:
ant build
sudo ant install
Maven on the other hand is a highly opinionated build tool that does not support this kind of workflow. Why? This is really a deployment action. Of course you can customize the Maven setup using ant ANT plugin, but I'd advise to just have a shell script you run afterwards. Lot easier to understand:
mvn install
sudo install_myapp.sh
The script can pickup the built jar from the Maven local repository "$HOME/.m2/repository" or better still download it from a Maven repository!
You have other mvn goals like 'mvn deploy' and 'mvn install' that do what you need.
I want to be set an archetype for a stable JavaFX (Java 8) Maven build that will produce an executable JAR that (always) runs from the command line. And preferable without needing to build an UberJar or similar.
When we use the Netbeans 'Maven JavaFX' archetype the resultant JAR file following a build runs. As a project grows we find that sometimes the JAR won't run from the command line. Some Maven POM edits have been needed to 'encourage' the program to run from the command line again. This applies to Linux and Windows.
This also happens directly with the ZenJava JavaFX archetype, e.g. a project artifactId=xx:
java -jar target\xx.jar
no main manifest attribute, in target\xx.jar
This is just from the mavan generate command. The details of the two archetypes in question are:
zenjava
archetypeArtifactId=javafx-basic-archetype
archetypeGroupId=com.zenjava
netbeans
archetypeArtifactId=javafx
archetypeGroupId=org.codehaus.mojo.archetypes
Comparing the resulting POM files shows these that the codehaus.mojo (netbeans) uses these plugins in the build:
maven-dependency-plugin
maven-compiler-plugin
exec-maven-plugin
Either project runs happily from within Netbeans IDE. The challenges occur when we want to test on command line. It isn't really the best look externally when the build looks unstable to outsiders like that.
The questions arising are about what are the requirements to make a JavaFX command-line executable JAR file? For JDK 8 and beyond.
Is there an alternative JavaFX archetype available that will build projects with dependent JAR-s and run from the command line?
What allows Netbeans (say) to execute JAR when the same the built JAR won't run on the command-line?
What 'magic' does Netbeans be add to the execute step?
What is needed for the zenjava archetype to run "Java -jar"?
The JAR resulting from the follow steps doesn't run on the console.
mvn archetype:generate -DarchetypeGroupId=com.zenjava -DarchetypeArtifactId=javafx-basic-archetype ... -DartifactId=xx
mvn install
java -jar target/xx-001.jar
What influences the: maven-dependency-plugin and maven-compiler-plugin when building the JAR for bigger projects?
In other words, what assumptions might be being broken a project grows and bind with other JAR files.
Needless to say, the Maven generate and build steps are using the JDK Java environment. The execution though, java -jar target/xx-001.jar, need to run under the simple JRE (without the JDK). I guess question #4 is a long stretch unless you are someone who has a biggish JavaFX project and solved this already. Suggestions welcome.
just to mention: I'm the maintainer of the javafx-maven-plugin (and the archetype).
To answer your question 3:
You have to call the GENERATED jar-file from the plugin, which is located at target/jfx/app/yourapp.jar
The generated jar-file will reference all required dependencies, which are noted inside the META-INF/MANIFEST.MF-file inside it. While creating that jar-file, the pom is scanned for runtime-dependencies, these will be placed at the target/jfx/app/lib-folder. When bundling your app into native bundle, the JRE is put aside of the generated launcher under the target/jfx/native/-folder.
What confuses me about your problem: mixing CLI- and GUI-application might result in problems, but i guess it's just your special requirement :)
EDIT:
Calling mvn install does NOT generate jfx-jar without special configuration, you have to call mvn jfx:jar or mvn jfx:native to call the MOJOs of the plugin. For easier configuration, please visit our configuration-website: http://javafx-maven-plugin.github.io/
If I know the coordinates of an artifact, and a name of the class inside that artifact, can I make Maven run the class, including all of its dependencies on the Java classpath?
For example, suppose a coworker told me about a tool I can run, which is published to our internal Nexus with the artifact coordinates example:cool-tools:1.0.0. I used this answer to download the artifact. Now, I know that the main class name is example.Main. But if I just go to the artifact's download location and run java -cp cool-tools-1.0.0.jar example.Main, I get NoClassDefFoundErrors for any dependencies of cool-tools.
I'm aware of the maven-exec-plugin, but as far as I can tell that's only for projects where you have the source. Suppose I don't have access to the source, only the Nexus containing the tool (and all its dependencies). Ideally, I'd do something like mvn exec:exec -DmainArtifact='example:cool-tools:1.0.0' -DmainClass='example.Main', but I don't think the exec plugin is actually capable of this.
ETA: To be clear, I do not have a local project / POM. I want to do this using only the command line, without writing a POM, if possible.
There is no out-of-the-box solution for your task. But you can create a simple script to solve it:
Download pom.xml of your tool from the repo.
Download jar of your tool.
Download all its dependencies.
Run java against resolved libraries.
Command line:
> mvn dependency:copy -Dartifact=<tool.group.id>:<tool.artifact.id>:<tool.version>:pom -DoutputDirectory=target
> mvn dependency:copy -Dartifact=<tool.group.id>:<tool.artifact.id>:<tool.version> -DoutputDirectory=target
> mvn dependency:copy-dependencies -f target/<tool.artifact.id>-<tool.version>.pom -DoutputDirectory=target
> java -cp target/* <tool.main.class>
Directory ./target will contain your tool + all dependencies.
See details on dependency:copy and dependency:copy-dependencies mojos.
Edit
As alternative, you can build classpath using libraries in the local repo by:
> mvn dependency:build-classpath -DincludeScope=runtime -f target/<tool.artifact.id>-<tool.version>.pom [-Dmdep.outputFile=/full/path/to/file]
See details on build-classpath mojo.
You could download the pom from the repository using wget, for instance. Then resolve the dependencies, and build the classpath exporting it to a file using Maven. Finally, execute with Java and the built classpath using something like bash backticks to use the content of the file.
Just like in this answer.
For me the first anwer almost worked, but I needed to slightly adjust the script. In the end I came (on windows machine) to following solution:
> mvn dependency:copy -Dartifact=<tool.group.id>:<tool.artifact.id>:<tool.version>:pom -DoutputDirectory=target
> mvn dependency:copy -Dartifact=<tool.group.id>:<tool.artifact.id>:<tool.version> -DoutputDirectory=target
> mvn dependency:copy-dependencies -f target/<tool.artifact.id>-<tool.version>.pom -DoutputDirectory=target
> cd target
> java -cp target/*;<tool.artifact.id>-<tool.version>.jar <tool.main.class>
On Unix/Linux machine in the last command the semicolon ";" must be replaced with colon ":".
When input arguments must be provided, just put them in the last script line:
> java -cp target/*;<tool.artifact.id>-<tool.version>.jar <tool.main.class> arg1 arg2 ...
u can use IDEs like Intellij idea which automatically resolve dependencies as u write them in your pom
As it has been mentioned by others already there is no solution without creating an extra POM.
One solution could be to use the Maven Shade Plugin in this POM: "This plugin provides the capability to package the artifact in an uber-jar, including its dependencies"
I think the Executable JAR is close to that what you'd like to achieve.
I'm hacking on a Maven-based project with a lot of dependencies; the project is normally meant to be developed in Eclipse but I need to work on it from the command line.
How to build+execute the project in a sane way? Something like mvn run, but of course Maven is not meant for running Java projects (for some reason).
The problem is specifying all the dependencies on java's commandline, I don't even know how to autogenerate that. I can currently deal with it using the assembly:single maven plugin (using the jar-with-dependencies descriptor) which will package the dependencies to a single .jar for me.
However, there really is a lot of dependencies and the assembly phase can take about two minutes, greatly disrupting my hack-test cycles so I'm looking for other ways to run the project with minimum build overhead - any recommendations, please?
Note: One possibility is running it in Eclipse once and capturing the java commandline. However, that's just a one-time hack, not a general solution in case I change pom.xml later or come to another project from the suite without Eclipse access anymore.
Have a look at the maven exec plugin
mvn exec:java -Dexec.mainClass="com.example.Main"
if you do this frequently, you can of course configure it via plugin configuration.
Regarding finding out project dependencies - you can use maven dependency plugin
http://maven.apache.org/plugins/maven-dependency-plugin/list-mojo.html
If you want to put them into file it'd be smth like
mvn dependency:list > dependencies.txt
See this question: How can I create an executable JAR with dependencies using Maven?. You can use the dependency-plugin to generate all dependencies in a separate directory before the package phase and then include that in the classpath of the manifest.
I see three solution to this:
onejar-maven-plugin - faster than assemlby with jar-with-dependencies descriptor
With onejar-maven-plugin, you'll (...) get a nice clean super jar with the dependency jars inside.
Spring Boot Maven Plugin - but this is dedicated to Spring projects
Maven Assembly Plugin with custom descriptor. This custom descriptor should grab all dependencies into lib folder, maven-jar-plugin should set Class-Path in Manifest.fm according to this new location. After this you can simply execute your program or zip your jar with lib folder as distribution.
After this is possible to run your program on your computer or any other with one command:
java -jar myjar.jar