Shorten classpath (-cp) for command line - java

My maven build in failing on jdeps plugin (we need it to upgrade to jdk11).
The command line is too long for windows.
Here is the error I get:
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-jdeps-plugin:3.1.1:jdkinternals (default) on project myproject:
[ERROR] Exit code: 1 - La ligne de commande est trop longue.
[ERROR]
[ERROR] Command line was: cmd.exe /X /C
"
"C:\Program Files\Java\jdk-11.0.2\bin\jdeps.exe"
-cp "
C:\Users\Me\.m2\repository\com\something\firstJar.jar;
C:\Users\Me\.m2\repository\com\somethingElse\secondJar.jar;
C:\Users\Me\.m2\repository\com\somethingDifferent\someOtherJar.jar;
... and one more
... and another one
... I think you get the idea......."
--multi-release 9 D:\git\myworkspace\myproject\target\classes
"
How to shorten this command-line? (and make sure it is not user dependant)
Restriction: It is a shared project, changing anything only on my computer is not a solution.

The maven-jdeps-plugin is using plexus-utils to fork out a child process to run the jdeps executable. plexus-utils implements this by building up a command-line and passing it to cmd.exe. This is the wrong approach as it will be subject to the 8192 char limit imposed by cmd.exe. The correct approach would be to use the Java ProcessBuilder API. This itself uses ProcessImpl.create API method, which, on Windows, is implemented by a Win32 API call to CreateProcess. The latter API has a 32k char limit, which should be enough for most use cases.
There is a plexus-utils bug report for this. You may want to raise one with maven-jdeps-plugin as well - the Java ProcessBuilder API is quite usable, so there's no need to use plexus-utils just to run jdeps.

If you are using Windows 10 Anniversary Update or Windows Server 2016, or later, you can increase the maximum path length beyond the 260 character default.
You can either copy the following two lines into a file with a .reg extension and open it,
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem]
"LongPathsEnabled"=dword:00000001
Or, open the Registry Editor and browse to the location, and change the value from 0 to 1.

The best is to create empty jar file with classpath configured in manifest.
Official oracle document is at Adding Classes to the JAR File's Classpath
maven-jar plugin does support updating manifest classpath attribute: How to add Class-Path to the manifest file with maven

maybe a bit of a cheeky solution but...
what about using an env variable?
set MR=C:\Users\Me\.m2\repository\
"C:\Program Files\Java\jdk-11.0.2\bin\jdeps.exe"
-cp "
%MR%\com\something\firstJar.jar;
%MR%\com\somethingElse\secondJar.jar;
did not test, hope it works...

This is the reason Maven is meant to mange a large amount of dependency as you can simply place all of them in the .pom file. The use of the a centralized dependency list allows Maven to be able to see nearly everything you need to run your program. Take a look at this post that does what you're trying though add each of your jar's for Maven to see them. How do I package and run a simple command-line application with dependencies using maven?
Also, a good guide to the .pom basics
Read the pom guide on www.maven.apache.org.
Maven will not use cmdline arguments the way you are trying because of the Manifest specifications. This is the fundamental reason programmers, including myself, love Maven so it will really make life much simpler as it's built to do exactly what you need. As the files change you have one file to make your updated versions.

So I did struggle with this problem for a long time and finally found solution to this issue with too long classpath while doing maven build.
This is a workaround but it works perfectly.
Run build from linux - that't not a joke (sic!)
Turn on WSL(Windows Subsystem for Linux) on Windows by following
https://learn.microsoft.com/en-us/windows/wsl/install-win10
After all done just Run your Linux subsystem on windows
edit linux maven settings.xml /usr/share/maven/conf/settings.xml
Add or override <localRepository>/mnt/c/.m2</localRepository> (/mnt/c/.m2) - is my windows maven repo path seen from WSL
cd /path/to/your/project
mvn build

Related

Specifying main class via java -cp *.jar package.path.ClassName won't work

I know that there are a lot of questions for this topic out there, although I have tried a lot of things, I cannot figure out where the problem is.
Specifically I try to execute the jar file of webgraph using
java-cp webgraph-3.5.2.jar it.unimi.dsi.webgraph.ASCIIGraph
I looked in the jar-file and the class file is present in the it/unimi/dsi/webgraph folder, which seems to be OK. When running the command I still get
Error: Could not find or load main class it.unimi.dsi.webgraph.ASCIIGraph
I tried to specify all the libs separated by a semi-colon, which didn't help (I would also expect another error message for missing libs)
I run through the same problem and I finally figured it out after so many researches. Here is the way to pass that error.
step one: Download and extract Apache Maven binaries from Here
step two: Download the dependencies tarball from here and extract it
step three: Retrieve the WebGraph framework source code with extensions from this repository. The version contains the copy list and copy flags compression formats, as well as additional flags for the other compression schemes.
step four: Compile the JAR file of the framework using Maven by running "mvn install" within the WebGraph root directory.
step five: Copy the target/webgraph-3.5.2.jar file in to the same location as the JAR files from the dependencies [the tarball dependencies].
here is the trick now, you need to specify exactly where the tarball dependencies are in order to get your expected result. Hence, assuming my tarball dependencies are in my '~/webgraph-deps/' directory,
$ java -cp "~/webgraph-deps/*" it.unimi.dsi.webgraph.ASCIIGraph <WHATEVER_YOU_WANT_TO_DO>
Plus, if the above command fails, it might be because of running out of memory and use the following command [it will set initial heap size for Java to work on, I have 12GB of RAM and allocated 6GB for this process (-Xmx6G)]
$ java -Xmx6G -cp "~/webgraph-deps/*" it.unimi.dsi.webgraph.ASCIIGraph
Here is my reference, https://github.com/lhelwerd/WebGraph. check it out for more!!

Error opening zip file or JAR manifest missing : C:\Program

I'm on step "Running project on the Server" from https://developers.google.com/appengine/docs/java/webtoolsplatform#dynamic_web_project and I ran into a problem:
Error occurred during initialization of VM
agent library failed to init: instrument
Error opening zip file or JAR manifest missing : C:\Program
Another person reported a similar problem here: Error opening zip file or JAR manifest missing : C:/Program. But the solution was for a different set of technologies. I'm using Eclipse, Web Tools Platform, and Google-App-Engine.
Most likely it's because my Java is installed in C:\Program Files, a directory which contains a space. But I'm not sure how to fix this. I’m not sure how to safely move the Java\jre7 directory to a directory without a space in it.
Jordan Fish from Google Cloud Platform Support helped me solve this problem. He said:
As far as the error message when you try to start the dev_appserver, I believe this is probably due to a vm argument in the run configuration for your project. Can you please go to the run configuration (with the project selected, go to the Run menu and select Run Configurations), click on the Arguments tab, and see what is listed in the VM arguments text box?
Here was my original VM arguments:
-javaagent:C:\Program Files\eclipse\plugins\com.google.appengine.eclipse.sdkbundle_1.9.4\appengine-java-sdk-1.9.4\lib\agent\appengine-agent.jar -Xmx512m -Dappengine.fullscan.seconds=5 -Ddatastore.default_high_rep_job_policy_unapplied_job_pct=50
Here is what I changed it to (added double quotes around the directory that's passed as the -javaagent: param):
-javaagent:"C:\Program Files\eclipse\plugins\com.google.appengine.eclipse.sdkbundle_1.9.4\appengine-java-sdk-1.9.4\lib\agent\appengine-agent.jar" -Xmx512m -Dappengine.fullscan.seconds=5 -Ddatastore.default_high_rep_job_policy_unapplied_job_pct=50
This fixed my problem, I was able to complete step "Running project on the Server" from https://developers.google.com/appengine/docs/java/webtoolsplatform#dynamic_web_project
You just have to add "" to your jar file behind -javaagent:
If you use IntelliJ the solution appears to be slightly different. You need to edit the Run Configuration the same way that the Eclipse users do, but add the "VM Options" using this format instead:
-javaagent:[/absolute/path/DMEnhancerJava-1.0.jar][classes=META-INF/]
Note the formatting with the brackets after the colon with no spaces for each parameter. If you miss that you'll get a runtime error message about JavaAgent expecting that input format.
Also, remember that if you use a build tool like Maven or Gradle and add this to your JAVA_ARGS variable (via something like MAVEN_OPTS) you'll need to wrap the whole thing in double quotes.
The second parameter appears to be necessary to tell DMEnhancer what to instrument (mine was relative to the top level of my classpath; because my compiled POJOs were in the META-INF directory).
Lastly, you may notice that you sometimes get an error talking about a class being implemented in two places in the classpath internal to the VM:
Class JavaLaunchHelper is implemented in both <Two full classspaths shown here> One of the two will be used. Which one is undefined.
This seems to happen because of a bug in the JVM and is fixed (on MacOS X) in 1.8u152 (at the time of writing, this is considered an Early Access Release available here). See this other answer for more information on this JVM bug.
Run your cmd as an Admin. When you try to startup your server and you are not starting it up as an admin you get this error.
Rebuild your project or try mvn clean install
Export jar with manifest file in eclipse as follows:
OR
Merge manifest file with created jar.
CMD: jar ufm /Users/inzamam/Desktop/inzaa.jar META-INF/MANIFEST.MF

What's a good way to set up Closure Compiler on Linux? Or, where should Java .jar's live on a Linux?

I'd like to set up a process where I can generate minified and optimized JS for my webapps as part of the process of pushing updated code to the webserver with git.
It's quite straightforward to run it: java -jar ./compiler.jar script.js
Of course if I have ten projects I don't want ten compiler.jars.
If I stick it here: /usr/local/lib/compiler.jar my call just looks stupid:
java -jar /usr/local/lib/compiler.jar script.js
It would make more sense to dump it in ~ like I do with everything else that doesn't have a place to go. It just feels sloppy.
Is there some directory that I can stick my jars into so that I can run them more easily, rather than my having to set up (symlinks to) shell scripts (or possibly better, shell command aliases) for each jar I want to use?
For example, shouldn't there be a system where I put my jar in a global designated java lib directory, after which point I may call java closure script.js?
Edit: I tried putting it in jre/lib/ext which I found here, but it did not work:
$ find /usr/lib | grep jre/lib/ext
/usr/lib/jvm/java-1.7.0-openjdk-1.7.0.25.x86_64/jre/lib/ext
.... bunch of other jar files here
$ cp ~/compiler.jar /usr/lib/jvm/java-1.7.0-openjdk-1.7.0.25.x86_64/jre/lib/ext
$ java -jar compiler.jar script.js
Error: Unable to access jarfile compiler.jar
My answer is more a suggestion that you do not reinvent the wheel, and that hopefully will save you from problems, you did not run in - yet, since you were already suggesting in your own comment that it might be good to include the jar in every project. :-)
I would suggest putting the jar in every project and make it self contained or better: run a setup script in every project, which fetches the jar from a remote location.
You could script the setup script by hand or go one step further and use a task runner, to create your own build-toolchain, which you can reuse on multiple projects.
We transitioned our project structure to Grunt tasks (http://gruntjs.com) Grunt contains a closure-compiler plugin (and many more plugins, e.g. sass). Each project contains a Grunt config file, which specifies all tasks, e.g. test, build, which you can invoke on the given project. So you have to install Grunt once on your machine and Grunt will pick up all your tasks for a given project and will take care of downloading the closure-compiler.jar and invoking the closure-compiler.
So even, if you might think right now: "I only need the closure-compiler" eventually you might need another tool B and start bash-scripting for tool B. I suggest you invest more time in learning, for example Grunt, and use the work of the community.
A side note: Before we used Grunt I set up the build-toolchain with another taskrunner, Gradle (http://www.gradle.org), which is popular for Java projects, motivated by the fact that the closure-compiler.jar is itself a Java project. This worked quite nice but I finally noticed that there is more Web-Project-Based support for Grunt than Gradle. As I believe in the right tool for the right job, my conclusion is: use Grunt for Javascript-Projects, Gradle for Java/JVM.
I would also put it in each and every project. This is to make them self-contained. Here is my code to do so:
cd /path/to/your/project
sudo apt-get install -y default-jre
wget "https://dl.google.com/closure-compiler/compiler-latest.tar.gz"
tar -xf compiler-latest.tar.gz
rm compiler-latest.tar.gz README.md COPYING
mv closure-compiler* closure-compiler.jar # rename for easier use
What's a good way to set up Closure Compiler on Linux?
It depends on you Linux distribution. Typically, it is already available in package repositories.
E.g. for CentOS 7, you would run:
yum install https://extras.getpagespeed.com/release-el7-latest.rpm
yum install closure-compiler
Then simply invoke it via closure-compiler <arguments>
If you don't use a distro that packaged it, see next answer.
Or, where should Java .jar's live on a Linux?
The system packages for .jar files typically go into /usr/share/java/ (at least so in RedHat based systems). Additionally, manually installed or downloaded software should go into /usr/local according to FHS standards.
From the above, you can decipher that /usr/local/share/java/ should be a proper place to put your manually downloaded .jar files if you want to have them accessible to multiple users / projects.
If you using the java command directly, then you'll have to provide a path to the jar in question. It's probably easier to place the jar in one place and create a shell script that handles the invocation and jar path.
I use an alias which I think is much more efficient than having a shell script sitting somewhere achieving roughly the same thing.
alias closure='java -jar /opt/closure-compiler/compiler.jar'
In use:
closure --js i.js --js_output_file i.min.js

Could not find the main class (on other computers)

I finished writing a java program and am ready to export it. I made a runnable jar from Eclipse. Running the jar works just fine on my computer, but throws the "Could not find main class" error on any other computer (including my other computer that I write Java on).
Whenever I search around for other people having the problem, it's always the same answer: Check the manifest file. I'm not seeing any problem with mine (Plus, can't imagine why it'd work on my computer but not someone else's)
Manifest:
Manifest-Version: 1.0
Main-Class: my.quick.monster.QuickMonster
And I've also tried:
Manifest-Version: 1.0
Class-Path: .
Main-Class: my.quick.monster.QuickMonster
Both work for me, but not other computers.
Thinking about the things that might be going wrong, here are a few other things to check:
make sure that there are no spurious characters (tabs, spaces) at the end of the lines.
check that the main class is actually in the JAR file with the right name.
on the machine that works, try changing your current directory and seeing if it still works.
check that you are using the same version of Java on each machine. Run java -version to check.
make sure that you are running it as an executable JAR; i.e. as java -jar foo.jar not as java -cp foo.jar.
(One theory is that the JAR is working on the one machine in spite of the manifest; e.g. that it is finding the class via the classpath in your CLASSPATH environment variable or something.)
To summarize for other folks, the OP's problem turned out to be that he had compiled his code with / for Java 7, and was trying to run the JAR on older Java installations. That wasn't working because of the classfile version numbers.
You can compile your code so that it will run on an older version of Java, but you need to use the -target option when compiling, and you ought to use the -bootclasspath option to compile against an rt.jar from the oldest Java version. A typical IDE will simplify this by allowing you to specify the target build platform, but it is worthwhile understanding the technical details, for cases where you are not using an IDE.
(I'm surprised that the java command didn't mention the classfile version number in the error message ...)
Make sure the MANIFEST.MF file contains a blank line at the end. If the Main-Class definition is on the very last line of the file, some class loaders ignore it.
Do not ever use 'eclipse-jar-worked-fine-on-my-computer'. I use maven shade jar plugin which excellently build a ready to run jar with all the dependencies, specified main class, etc.
EDIT:
What is the wrong with eclipse-builded-jar is that you won't been able to build it w/o elcipse. Maven is the common tool widely used to build packages of any kind. It's automated, and means that it can be used in CI environmet, etc. And the goal of a good developer is to write code so that it can be easily moved to CI.
However, if it's not a regular task, assuming to make just once/twice, theen, maybe, 'eclipse' solutio has also some benefits. But, I answered keeping in mind some cases of my past when people build packages in GUI just because they didn't manage to do it in maven.
So, I hope there is enough arguments for maven vs eclipse, so please stop downvote :D

Deploying a Java application. How?

I am new to Java (and Eclipse) but I have used .NET (and Visual Studio) a fair amount. I also know about compiling C/C++ code and things like that. I know that at the end I get either an EXE or a nice binary file that can be run from the command line.
I have been making a Java utility that uses some external libraries. I need to compile this into an executable that I can run from the command line on a unix machine, but I cannot find any way to do this.
I can build and run/debug in Eclipse, but that is no use to me as this code will be run on a webserver. I just need all the dependancies compiled in to one file but after hours of searching on Google, the best thing I could find was the Fat-JAR plugin for Eclipse and after using that I just get the following error when I try to run the file:
Exception in thread "main" java.lang.NoClassDefFoundError: Network/jar
This is really confusing me and as it is such an essential thing to be able to do I am sure I must be missing something blindingly obvious, but as I said, after hours of searching I have gotten nowhere.
I really appreciate any help you can give me. Thanks.
If you build your java app using Maven (which can be done with every major IDE), then you can use the maven Shade Plugin to build a shaded jar file; this is a jar file with all of its dependencies included.
A shaded jar can be run from the command line like this:
java -jar myjar.jar command line options
You're doing something standard and you're using eclipse. This means, in your case, Maven is your friend. Download and install the M2Eclipse plug-in. Maven is best at managing dependencies. So, creating a jar with dependencies included will be very, very straight forward. There are thousands of examples on the web and in StackOverflow. If you have problems setting it up, comment on this and I can point you in the right direction.
Sounds like your class path on the server needs to be modified to pick up the jar file containing the Network class. How are you executing your program? What path(s) are you putting in the -cp option?
If you are not sure how to find out the contents inside a jar file, run jar tf , this will list the packaged classes. Validate that one of the jars in your CLASSPATH has that class it says missing.
Give us more details and we can help solve it.
I think I should first explain some basics. A Java class can be run as an application if it has a public static void main(String[] args) method. If it has this method, you can run it from command line as:
java my.package.MyClass <attributes>
Before launching your app, you need to make sure that all required .jar files (and the root of your own class folders, if you did not make a jar from your classes) are in the CLASSPATH environment variable.
These are the absolute basics. When you are building a more complex app, or an app for distribution, you'll probably use maven or ant or some other tool that makes your life easier.

Categories

Resources