Can't start main class when classpath order changes - java

I am trying to start rascal with clair from the command line, however I do not understand why this happens:
java -cp "rascal-0.18.0.jar;clair_0.1.0.202005281059.jar;org.eclipse.cdt.core_6.11.0.202003081657.jar" org.rascalmpl.shell.RascalShell
Version: 0.18.0
INFO: detected |lib://rascal| at |jar+file:///C:/ws/rascal-0.18.0.jar!/|
INFO: detected |lib://clair| at |jar+file:///C:/ws/clair_0.1.0.202005281059.jar!/|
rascal>
But when the order of the jars changes, it fails:
java -cp "clair_0.1.0.202005281059.jar;rascal-0.18.0.jar;org.eclipse.cdt.core_6.11.0.202003081657.jar" org.rascalmpl.shell.RascalShell
Version: 0.18.0
INFO: detected |lib://clair| at |jar+file:///C:/ws/clair_0.1.0.202005281059.jar!/|
INFO: detected |lib://rascal| at |jar+file:///C:/ws/rascal-0.18.0.jar!/|
main function should either have one argument of type list[str], or keyword parameters
Usage: java -jar ...
Is this normal behavior with classpaths?
Note: The clair jar does not contain a org.rascalmpl.shell.RascalShell class.
Update: Removing from META-INF/RASCAL.MF the line:
Main-Function: main
Main-Module: lang::cpp::IDE
resolves the problem, so it seems to be an issue with Rascal (and a rascal function) and not with Java (and a Java function).

RascalShell's main function behaves differently if there are commandline parameters and differently depending on the first RASCAL.MF file it finds in the classpath.
If there is a parameter, then it loads that parameter as a module name and invokes the main function in that module, passing it the other commandline parameters
Otherwise it starts the REPL
But: if the first RASCAL.MF file it finds in the classpath has a Main-Module and a Main-Function, then it loads this module always and starts its main function.
I suspect the latter is at work: the order of the classpath changes which RASCAL.MF file is found and therefore the REPL does not start but some module is being loaded and not found. I'm not sure though, since I can't set a breakpoint from here ;-)

I think you have found two bugs in the REPL:
The second behavior is the bug that we try to run the Main-Function definition which is intended for the IDE plugin, also in the terminal. I think the issue/bug is that we use the same configuration for command line as ide integration point, we might need to add a seperate tag for this.
We should provide a way to say which RASCAL.MF we want to run, since now it just picks the first one it sees (rascal also has a RASCAL.MF file).

Related

Same class is in multiple jar

I have several jars containing the exact same class.
Lets say for example, A.jar and B.jar have the same class Hello.class. What will happen if I run the following:
java -classpath A.jar;B.jar com.testing.testcode
My question is whether it will run or not? As from my understanding class loader will scan the classpath and it will return whatever Hello.class it finds first.
I know I can avoid this problem if I use OSGi for loading a particular class.
But what my question is – whether this will run or not? Or the java -classpath A.jar;B.jar com.testing.testcode will break down for having two version of the same class.
This will work and the first Hello class in the classpath will be used, so in this case, the one from the A.jar
The class path is a "path". The first match is taken.
There is a boot class path which is examined first and this included the JARs in the JRE. BTW You can prepend these and override system classes but you are not supposed to and it might not be allowed in your license agreement.
Whenever you include the jar in your classpath, on startup/ on application class gets loaded into the container.
Now whether your code will work or not will depend on which jar gets loaded first in your container and accordingly if you are lucky then in your current setup it will work else you might get some error saying that method1 doesn't accept Type1 it should accept Type2.

How can I run a Groovy class from the command-line within a Grails environment?

I'm using Grails 2.1.0, and I have a Groovy class that I've written that's not dependent on services, controllers, or any of the other Grails goodness. It uses some .jar libraries and other classes that are already in the Grails classpath.
I want to:
Run the Groovy class (or a Java class, it shouldn't mattter) use the other libraries/classes that Grails already has on its classpath (not services, not controllers, none of that).
Be able to access the command line arguments [this is required]
Does not require bootstrapping the entire Grails environment (I need the classpath obviously, but nothing else)
Ideally, I'd like to be able to do something like this:
java -classpath (I_HAVE_NO_IDEA_HOW_TO_DETERMINE_THIS) com.something.MyClass param1 param2 param3
Things I've already looked into:
Using "grails create-script" which results in a Gant script.
Using "grails run-script"
The first one (using a Gant script) seems horribly wrong to me. Using an Gant script as some sort of intermediary wrapper seems to require bootstrapping the whole Grails environment, plus I have to figure out how to get a reference to the actual class I want to call which seems to be difficult (but I Am Not A Gant Expert, so enlighten me). =)
The second one (using run-script) sort of works... I've used this approach to call service methods before, but it has two problems: first, it bootstraps the entire Grails environment; second, there does not appear to be any way to pass the command-line arguments easily.
Really, I just want the stuff in the classpath (and my command-line parameters) and to be able to call the main() method of my class with minimial frustration. That being said, if you can come up with a working example of any sort that solves the issue (even if it involves some intermediary Gant or other class) I'll be happy to use that approach.
Thanks.
Update: A solution that works with a Gant task, still open to better ideas if anyone has any...
In scripts/FooBar.groovy
includeTargets << grailsScript("_GrailsInit")
target(main: "Runs a generic script and passes parameters") {
def myclass = classLoader.loadClass('com.whatever.scripting.GenericRunScript')
myclass.execute(args);
}
setDefaultTarget(main)
In src/groovy/com/whatever/scripting/GenericRunScript.groovy
package com.whatever.scripting
class GenericRunScript {
public static execute(def args) {
println "args=" + args.inspect()
}
}
Then from the command line, at while in the root directory of the Grails project:
$ grails compile
| Environment set to development.....
| Compiling 2 source files.
$ grails foo-bar test one two
| Environment set to development....
args='test\none\ntwo'
Note 1: When I first did this, I kept forgetting the compile statement, so I added that in.
Note 2: Yes, the args are separated by carriage returns; fixing that is left as an exercise to the reader.
The way described above would work but all grails facility will be gone including domains and dependencies.
If you require everything that you have defined in your grails project, the run-script command will do the trick
grails run-script [path to your groovy file]
http://grails.org/doc/latest/ref/Command%20Line/run-script.html
As described in http://grails.org/doc/latest/guide/commandLine.html, you can include targets _GrailsClasspath and _GrailsArgParsing, and whatever else you need. For example, if you want to parse command-line arguments without creating a second script:
$ grails create-script ArgsScript
| Created file scripts/ArgsScript.groovy
Now edit the script scripts/ArgsScript.groovy as follows:
includeTargets << grailsScript("_GrailsArgParsing") // grailsScript("_GrailsInit")
target(main: "The description of the script goes here!") {
println argsMap
for (p in argsMap['params'])
println p
}
setDefaultTarget(main)
See the result:
$ grails args-script one two three=four
| Environment set to development....
[params:[one, two, three=four]]
one
two
three=four
Update: well, it is not as easy as I thought. Basically, you can either run a script as a Gant task, e.g. by doing grails myscript, or as a script, e.g. by doing grails run-script src/groovy/MyScript.groovy. In the first case you have access to parameters, as I already explained, but you still miss some of the Grails environment, which is, perhaps, a bug. For example, you can't really access scripts or classes defined in src/groovy/ from a Gant task. On the other hand, as was already discussed, if you use run-script, you can't get the arguments.
However, you can use System.getProperty to pass command-line arguments with the -Dproperty=value syntax. Also see Java system properties and environment variables

How to run Tests when developing javaagents?

I'm trying to fiddle with Foursquare's HeapAudit, and am attempting to set it up using IntelliJ IDEA. I have managed to get it to build just fine, using the dependencies from the pom.xml.
However, when I actually try to run the JUnit tests, basically all of them fail. I'm guessing this is because using HeapAudit requires the JVM to be started with it as a -javaagent, according to the github:
$ java -javaagent:heapaudit.jar MyTest
Presumably the tests would pass if I put this line in, and referenced the heapaudit.jar i downloaded/built earlier. However, it seems to me that if I make changes the the source, I'm gonna need to re-package this silly .jar file in order to see if it works.
Is there any way of running the tests with a -javaagent without going through the whole rigmarole of compile -> package-into-jar every testing cycle? Perhaps getting IntelliJ to attached the newly-compiled .class files as a -javaagent before running the tests?
1) Have a jar just with a META-INF/MANIFEST.MF
The manifest must be properly configured with Premain-Class and other attributes. The jar doesn't need any other files. Use this jar with the -javaagent. Provided that the agent classes are in the classpath, the agent will start normally.
This might fail when using maven-surefire-plugin with forkMode=never because by default the application classes are loaded in a child ClassLoader.
Works fine with Eclipse and Intellij.
If doing this, double check the manifest syntax (once I spent a long time to figure out that a package name was wrong).
2) Use ea-agent-loader
It will allow you to load the agent (any agent) in runtime (it uses VM.attach()). However the VM.attach() sometimes disrupts debugging and breakpoints might fail to trigger.
It will have the same issues with the surefire in forkMode=never
3) Load the agent in runtime.
Write your on code to load the agent in runtime. And call it from your #BeforeClass You will still need a jar (which you can generate in runtime if you want).
Just you need to call this (only once):
AgentLoader.loadAgentClass(YourAgentClass.class.getName());

How to set a long Java classpath in Windows?

I'm trying to run a particular JUnit test by hand on a Windows XP command line, which has an unusually high number of elements in the class path. I've tried several variations, such as:
set CLASS_PATH=C:\path\a\b\c;C:\path\e\f\g;....
set CLASS_PATH=%CLASS_PATH%;C:\path2\a\b\c;C:\path2\e\f\g;....
...
C:\apps\jdk1.6.0_07\bin\java.exe -client oracle.jdevimpl.junit.runner.TestRunner com.myco.myClass.MyTest testMethod
(Other variations are setting the classpath all on one line, setting the classpath via -classpath as an argument to java"). It always comes down to the console throwing up it's hands with this error:
The input line is too long.
The syntax of the command is incorrect.
This is a JUnit test testing a rather large existing legacy project, so no suggestions about rearranging my directory structure to something more reasonable, those types of solutions are out for now. I was just trying to gen up a quick test against this project and run it on the command line, and the console is stonewalling me. Help!
The Windows command line is very limiting in this regard. A workaround is to create a "pathing jar". This is a jar containing only a Manifest.mf file, whose Class-Path specifies the disk paths of your long list of jars, etc. Now just add this pathing jar to your command line classpath. This is usually more convenient than packaging the actual resources together.
As I recall, the disk paths can be relative to the pathing jar itself. So the Manifest.mf might look something like this:
Class-Path: this.jar that.jar ../lib/other.jar
If your pathing jar contains mainly foundational resources, then it won't change too frequently, but you will probably still want to generate it somewhere in your build. For example:
<jar destfile="pathing.jar">
<manifest>
<attribute name="Class-Path" value="this.jar that.jar ../lib/other.jar"/>
</manifest>
</jar>
Since Java 6 you can use classpath wildcards.
Example: foo/*, refers to all .jar files in the directory foo
this will not match class files (only jar files). To match both use: foo;foo/* or foo/*;foo. The order determines what is loaded first.
The search is NOT recursive
Use An "Argument File" on Java 9+
In Java 9+, the java executable supports providing arguments via a file. See
https://docs.oracle.com/javase/9/tools/java.htm#JSWOR-GUID-4856361B-8BFD-4964-AE84-121F5F6CF111.
This mechanism is explicitly intended to solve the problem of OS limitations on command lengths:
You can shorten or simplify the java command by using #argument files
to specify a text file that contains arguments, such as options and
class names, passed to the java command. This let’s you to create java
commands of any length on any operating system.
In the command line, use the at sign (#) prefix to identify an
argument file that contains java options and class names. When the
java command encounters a file beginning with the at sign (#) , it
expands the contents of that file into an argument list just as they
would be specified on the command line.
This is the "right" solution, if you are running version 9 or above. This mechanism simply modifies how the argument is provided to the JVM, and is therefore 100% compatible with any framework or application, regardless of how they do classloading i.e. it is completely equivalent to simply providing the argument on the command line as usual. This is not true for manifest-based workarounds to this OS limitation.
An example of this is:
Original command:
java -cp c:\foo\bar.jar;c:\foo\baz.jar
can be rewritten as:
java #c:\path\to\cparg
where c:\path\to\cparg is a file which contains:
-cp c:\foo\bar.jar;c:\foo\baz.jar
This "argument file" also supports line continuation characters and quoting for properly handling spaces in paths e.g.
-cp "\
c:\foo\bar.jar;\
c:\foo\baz.jar"
Gradle
If you are encountering this issue in Gradle, see this plugin, which converts your classpath automatically into an "argument file" and provides that to the JVM when doing exec or test tasks on Windows. On Linux or other operating systems it does nothing by default, though an optional configuration value can be used to apply the transformation regardless of OS.
https://github.com/redocksoft/classpath-to-file-gradle-plugin
(disclaimer: I am the author)
See also this related Gradle issue -- hopefully this capability will eventually be integrated into Gradle core: https://github.com/gradle/gradle/issues/1989.
(I suppose you do not really mean DOS, but refer to cmd.exe.)
I think it is less a CLASSPATH limitation than an environment size/environment variable size limit. On XP, individual environment variables can be 8k in size, the entire environment is limited to 64k. I can't see you would hit that limit.
There is a limit on windows that restricts the length of a command line, on WindowsNT+ it is 8k for cmd.exe. A set command is subject to that restriction. Can it be you have more than 8k worth of directories in your set command? You may be out of luck, then - even if you split them up like Nick Berardi suggested.
Thanks to Raman for introducing a new solution to a pathing problem for Java 9+. I made a hack to bootRun task that allows using everything already evaluated by gradle to run java with argument files. Not very elegant but working.
// Fix long path problem on Windows by utilizing java Command-Line Argument Files
// https://docs.oracle.com/javase/9/tools/java.htm#JSWOR-GUID-4856361B-8BFD-4964-AE84-121F5F6CF111
// The task creates the command-line argument file with classpath
// Then we specify the args parameter with path to command-line argument file and main class
// Then we clear classpath and main parameters
// As arguments are applied after applying classpath and main class last step
// is done to cheat gradle plugin: we will skip classpath and main and manually
// apply them through args
// Hopefully at some point gradle will do this automatically
// https://github.com/gradle/gradle/issues/1989
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
bootRun {
doFirst {
def argumentFilePath = "build/javaArguments.txt"
def argumentFile = project.file(argumentFilePath)
def writer = argumentFile.newPrintWriter()
writer.print('-cp ')
writer.println(classpath.join(';'))
writer.close()
args = ["#${argumentFile.absolutePath}", main]
classpath = project.files()
main = ''
}
}
}
If I were in your shoes, I would download the junction utility from MS : http://technet.microsoft.com/en-us/sysinternals/bb896768.aspx and then map your
"C:\path" to say, "z:\" and "c:\path2" to say, "y:\". This way, you will be reducing 4 characters per item in your classpath.
set CLASS_PATH=C:\path\a\b\c;C:\path\e\f\g;
set CLASS_PATH=%CLASS_PATH%;C:\path2\a\b\c;C:\path2\e\f\g;
Now, your classpath will be :
set CLASS_PATH=z\a\b\c;z\e\f\g;
set CLASS_PATH=%CLASS_PATH%;y:\a\b\c;y:\e\f\g;
It might do more depending on your actual classpath.
I think you are up the creek without a paddle here.
The commandline has a limit for arguments to call a programm.
I have 2 sugestion you could try.
First, prior to running the junit tests, you can let a script/ant_task create JARs of the various classes on the classpath.
Then you can put the JARs on the classpath, which should be shorter.
Another way you could try is to create an antscript to run JUNIT,
in ANT there should not be such a limit for classpath entries.
As HuibertGill mentions, I would wrap this in an Ant build script just so that you don't have to manage all of this yourself.
You could try this
#echo off
set A=D:\jdk1.6.0_23\bin
set B=C:\Documents and Settings\674205\Desktop\JavaProj
set PATH="%PATH%;%A%;"
set CLASSPATH="%CLASSPATH%;%B%;"
go to a command prompt and run it twice(no idea why....i have to do so on a windows XP machine)
also the paths r set only for the current command prompt session
There was no solution to the issue other than somehow making the classpath shorter by moving the jar files into a folder like "C:\jars".
Fix for windows gradle long classpath issue. Fixes JavaExec tasks that error out with message "CreateProcess error=206, The filename or extension is too long"
Using the plugins DSL:
plugins {
id "com.github.ManifestClasspath" version "0.1.0-RELEASE"
}
Using legacy plugin application:
buildscript {
repositories {
maven {
url "https://plugins.gradle.org/m2/"
}
}
dependencies {
classpath "gradle.plugin.com.github.viswaramamoorthy:gradle-util-plugins:0.1.0-RELEASE"
}
}
apply plugin: "com.github.ManifestClasspath"
I had a similar issue here with a giant classpath definition inside a .bat file.
The problem was that this class path was also including the execution path into the giant path, its ok, its make sense.
In this context, the software was not able to run and the message "The input line is too long" appeared everytime.
Solution:
I just moved the all files to a shorter position.
For instance, I was trying to execute the software in a directory tree like:
c:\softwares\testing\testing_solution\one
and I moved the whole structure to a point like this
c:\test
The software worked very well.
It is not the best option, I know, but might help some one who is looking to a fast solution.
Tks
Have you tried stacking them?
set CLASS_PATH = c:\path
set ALT_A = %CLASS_PATH%\a\b\c;
set ALT_B = %CLASS_PATH%\e\f\g;
...
set ALL_PATHS = %CLASS_PATH%;%ALT_A%;%ALT_B%

NoClassDefFoundError on command-line with new NetBeans project

I've created a new J2SE project in NetBeans, and I can run it from the IDE, but when I try to run it using Ant on the command line, I get the following problem:
<snip>
run:
[java] Exception in thread "main" java.lang.NoClassDefFoundError: IndexBuilder
[java] Java Result: 1
<snip>
Based on the snippet from project.properties below, the class should be found.
run.classpath=\
${javac.classpath}:\
${build.classes.dir}
How do I go about fixing this?
The error you're getting means that one of the following is true:
The class IndexBuilder cannot be found on the classpath
A necessary (for class loading) dependency of IndexBuilder cannot be found on the classpath
That is, when loading the class, it's possible (even likely) that the class can be found but that some critical dependency of the class cannot be found. For example, if IndexBuilder extends another class and that base class cannot be found on the classpath, you'll get this error. Another example is if IndexBuilder uses a class in a static initializer and that class cannot be found.
Check your classpath not just for IndexBuilder but also for anything that IndexBuilder depends on.
See, for example, this discussion of NoClassDefFoundError.
When you are running it from the command line, you are actually invoking Apache Ant. The reason you are getting the ClassNotFound Exception is because ${javac.classpath} and all the other properties are not being properly populated. That is why your code runs from within the Netbeans context. Netbeans is setting those properties for you.
To answer your original question of how do you go about getting it to run from the command line, you need to either set up a properties file that defines those parameters via a property declaration:
<property file="myproject.properties"/>
Another solution is to set the properties as environment variables via a sh script. Or you can use real paths in the build script instead of properties.
See here for more details on how to invoke Ant from the command line.
Did you try setting the working directory to "build\classes" in the Project Properties -> Run tab?
At least one of the JARs/Libs referenced by your project may not be being copied to the class path of your program. Copy all of the jars/libs that your project uses to the /dist folder of your project (or wherever YourApplication.jar is), then try to run your program. If this fixes it it means your Netbeans project isn't configured quite correctly.
Are you running this on Windows or Unix. If Windows, try changing your property file to:
run.classpath=${javac.classpath};${build.classes.dir}
Please note the semicolon instead of a colon.

Categories