Out of desperation of lack of ideas I'm currently working on a way to compile a single file from inside an eclipse plugin.
So far, I've successfully made code that compiles a single .java file that has no external .class (without being inside .jar) dependencies.
For the compilation process, I know where all the dependency .class files are and I give that information to the compiler using -classpath option.
Currently, I'm calling the compiler like this:
String[] params = new String[]{
"-properties", propertiesFile,
"-g", "-preserveAllLocals",
"-classpath", classPath,
fileToCompile,
"-d", outputPath,
"-proc:none",
"-proceedOnError",
};
boolean result = BatchCompiler.compile(
params, new PrintWriter(outWriter), new PrintWriter(errWriter), null);
The variables:
propertiesFile: exists and it contains the merge of the workspace + project's settings without repetition (in that order).
classPath: contains multiple paths separated by ";" (this one has problems, see below)
fileToCompile contains the absolute path of the file I want to compile. Do note that this file is not in the sources directory.
outputPath: The directory where the "bin" of the project is. It gets it from the IProject object itself.
You may find the meaning of the other options here.
classPath is giving me an error. Two classes exist in this test project:
This is its content (after reducing the size by removing most .jar includes from native java:
"C:/Program Files (x86)/java/jre1.8.0_66/lib/resources.jar";"C:/Program Files (x86)/Java/jre1.8.0_66/lib/rt.jar";D:/Users/user/runtime-EclipseApplication/Tests/bin"
I've tried using these as the last "include" in the classpath:
"D:/Users/user/runtime-EclipseApplication/Tests/bin"
"D\:\Users\user\runtime-EclipseApplication\Tests\bin"
"D\\:/Users/user/runtime-EclipseApplication/Tests/bin"
"D\\:\\Users\\user\\runtime-EclipseApplication\\Tests\\bin"
Here's the output it gives in stderr:
incorrect classpath: "D:/Users/user/runtime-EclipseApplication/Tests/bin"
----------
1. ERROR in D:\Users\user\runtime-EclipseApplication\.metadata\.plugins\myplugin\tmp\sources\Test2.java (at line 3)
public class Test2 extends Test{
^^^^^^^^
Test cannot be resolved to a type
I can assert in my own code that, just before the compiler is called:
That classpath directory exists
That Test.class is in that directory
I'm using the default package at the time that code executes
What am I doing wrong here? Why is it classifying it at an incorrect classpath?
I'm using org.eclipse.jdt.core(v.3.10.2) dependency and I'm compiling in eclipse Luna (4.4) which is the minimum version I want my plugin to support.
After days around this, somehow...
"C:/Program Files (x86)/java/jre1.8.0_66/lib/resources.jar";"C:/Program Files (x86)/Java/jre1.8.0_66/lib/rt.jar";D:/Users/user/runtime-EclipseApplication/Tests/bin <- No ending quote
That worked. I don't remember anymore if I did anything else but it works like that regardless if it has spaces or not.
I'm still wondering what is causing the inconsistency between the first elements using quotes but my element mustn't use any quotes.
Related
I have a problem with System.getProperty("user.dir") giving different directory when run by IDE and when I manually compile & run it in cmd. My thing is this, I have project structure like this:
project
- exports
- src
- main
- java
- Main
- file1
- file2
One of the args in main method is the name of one of those 2 files, that I then access.
When I configure my run in IDE it works like a charm - the directory I get is C:\Users\**\**\**\project and it is able to read and write to the file.
But when I compile it in cmd javac Main.java and then run it, I get C:\Users\**\**\**\project\src\main\java and because of that, I am unable to access the file without having to modify the path.
My question is, is there like a golden way, that would work for both these cases, without me having to alter the returned path?
EDIT:
For clear understanding, I know what System.getProperty("user.dir") returns, but my question was, if it is possible to get the same result somehow with using Path or if I have to get the path and edit it, so that it will end in project directory?
in IDE I get: C:\Users\petri\Desktop\CZM\bicycle-statistics
in cmd: C:\Users\petri\Desktop\CZM\bicycle-statistics\src\main\java
I want to get the same path in cmd, that I got in IDE.
I tried using Paths.get("").toAbsolutePath(), but it is the same thing.
So, what I did is this:
Path path = Paths.get("").toAbsolutePath();
while (!path.endsWith("project")) {
path = path.getParent();
}
And it works, but I am trying to ask, if there is some more elegant way, because I will have to defend my solution in front of my supervisor.
Normally your IDE will build source files in src/main/java and write the class files out to some other directory, like target/classes.
If your IDE built the project that way, then you can run it from the command line by switching to your project directory (cd C:\Users\**\**\**\project using your example) and then running:
java -classpath target/classes Main
assuming that target/classes is where your IDE put the files. If you really do have the class files in the source directory, then use -classpath src/main/java.
If you always run the program from the project directory, then you can assume within the program that the current directory is the project directory. You don't even have to use user.dir then, just use relative path names for everything, e.g., path/to/whatever.dat will automatically resolve to C:\Users\**\**\**\project\path\to\whatever.dat.
One of the args in main method is the name of one of those 2 files
Then make sure you enter the name correctly.
E.g. if the current working directory is the project folder, then name file1 will refer to the file1 file. If the current working directory is the java folder, then the argument to the program needs to be ..\..\..\file1.
That is because you give relative file names, which means they are relative to the current working directory.
Alternatively, give a fully qualified name, then the argument will be the same, regardless of what the current working directory is:
C:\Users\**\**\**\project\file1
In a tomcat server, at run time, I am reading java class files and compiling them dynamically using the InMemoryJavaCompiler library which internally uses JavaCompiler .
Code Sample -
InMemoryJavaCompiler.newInstance()
.useOptions("-parameters",
"-classpath", sb.toString(),
"-Xlint:unchecked")
.compile(sourceCodeClassName,
sourceCode.toString());
Here sb (Stringbuilder) indicates the jars read from WEB-INF/lib directory separated by a colon.
The code works in the following scenarios :
If the above compilation code is kept in a standalone class file & the relevant libraries are set in the classpath. The compilation was successful.
I printed the jar files i.e. I printed sb value separately & took a copy of it. I manually ran javac -classpath <sourceCode.java> in the terminal. The compilation was successful.
The code is not working in the following scenarios :
a. When the above code snippet is added as a stand alone program in eclipse, I faced NoClassDefFound error for the interface which the sourceCode was implementing.
b. In Tomcat, the relevant jar is present in contextName/WEB-INF/lib/ and in addition to that the jar is added in -useOptions classpath. Even then, I am facing NoClassDefFound error for the the interface the sourceCode was implementing.
Note : There are no duplicate copies of the jar or multiple versions of the jar present in the lib directory or the classpath value. The interface is ContractInterface present in hyperledger-fabric-shim
The issue was that System classloader was being used. Once I set the classloader using the -useParentClassLoader option with the current thread's classloader, the compilation was successful.
This is the first time I am compiling a program, and it doesn't seem to be working out. Looks like some packages are not being located - so for this question, I'll just focus on one:
Steps I've take so far:
1) setting up the System Variable Path to include java
2) in CMD.exe: jar tf log4j.jar I did this to make sure it includes log4j.Logger and it does.
3) I Shift+rightclick and open command prompt from this folder:
4) Then I enter javac TNT.java and i get the following error (along with others):
Any thoughts?
I set the classpath to the same folders with set classpath = "name of folder" no change...
edit
5) have also tried
javac -cp jdkbindirectory;jrebindirectory;theabovefolder TNT.java
I get this:
blahblahblah
You shouldn't set the classpath using an environment variable as it is bad practice. What if you accidentally change it later for a different project and your current project breaks?
When including classes in the classpath, you can include the path of the root of the package of the class, as in the folder that contains the folders in the package structure. However, when you're including a jar in your classpath, you need to put the entire path of the jar file (relative to the current working directory) all the way up to the jarname.jar.
Also, remember that by default, java looks in the current working directory and uses that as its default classpath. However, as soon as you specify a classpath it no longer does that automatically for you. Be sure that you're including your current directory in your classpath as well.
Finally, be sure to surround the classpath in quotes otherwise java might think its a part of another argument.
I would try this:
javac -cp "./;log4j.jar" TNT.java
And then to execute the class file:
java -cp "./;log4j.jar" TNT
Hope this works, good luck!
I have a Spring/MVC/Tomcat website project that I am attempting to run with IntelliJ IDEA. Because I am running on Windows, there is a command-line size limit, which is exceeded by the large classpath. I use IntelliJ's dynamic classpath feature which puts the classpath in a jar file to shorten the command line. Java runs with -classpath <classpath.jar>.
When I try to view a page, the JSP compilation fails with an error to this effect:
org.apache.jasper.JasperException: Unable to compile class for JSP:
An error occurred at line: [-1] in the generated java file: [<removed>.java]
[javac] <removed>.java:11: error: package javax.servlet does not exist
[javac] import javax.servlet.*;
[javac] ^
I ran it in debug and stepped into where the java compilation was being done and found the javac command line used. It was put together in org.apache.tools.ant.taskdefs.compilers.JavacExternal. I ran the javac command myself, with -verbose, and noticed that the dependency path from the search path for class files: log line shows up like:
C:\Users\<removed>\AppData\Local\Temp\file:\C:\Users\<removed>\lib\servlet-api-3.0.jar
Note that it seems like the absolute URI path is being treated as a relative path, resulting in an invalid path. I believe this is why it's not compiling properly.
Intellij's generated pathing jar's MANIFEST.MF lists the classpath with entries that are absolute paths that look like:
file:/C:/Program%20Files/Java/jdk1.8.0_121/jre/lib/charsets.jar file:/C:/Program%20Files/Java/jdk1.8.0_121/jre/lib/deploy.jar [...]
This problem doesn't happen on Mac, using dynamic classpath jar (even though it's not necessary because the command line too long error does not happen) so I believe something about the Windows path or the way that IntelliJ generates the classpath jar on Windows is messing up the JSP compilation.
Also, using an Ant build task that generates a pathing jar with relative paths works too, but I am interested in avoiding the use of Ant here.
How can I get this working, or what else do I need to investigate to get to the root cause?
This is a known bug in JDK.
Javac incorrectly handles absolute paths in manifest classpath headers. It has been fixed in JDK9.
When I investigated this problem, assuming Java8, I found a different root cause in my case.
In short:
The "/org/apache/jasper/servlet/TldScanner.java" on Line 102, attempts to scan locations for potential JARs.
It uses the "/org/apache/tomcat/util/scan/StandardJarScanner.java" to actually search.
Put a breakpoint on Line 221 URL[] urls = ((URLClassLoader) classLoader).getURLs();
You will see this ClassLoader has the "classpath.jar" as a potential JAR to scan (i.e. process).
But it cannot further find JARs referenced by a (classpath.jar) JAR's manifest file. Meaning, the real JAR(s) you need are not going to be checked.
A short fix, a for this is to:
Add "standard-1.1.2.jar" to your web/WEB-INF/lib/ dir.
If you look inside this jar, you will see *.tld files.
Test:
You can put a breakpoint on TldScanner.java Line 311 found = true;.
When it is not working, you will never hit this line.
When it works, with this (or any) fix, it will hit this line.
I'll try to illustrate the problem as simple as I can.
I have a JAR file, which I extracted using Winrar. (The jar file contains an open source android library).
I want to modify this JAR file by adding a new class to the library.
So here are my steps:
First, I created a class using Eclipse and set the package name same as the android's library package name.
Second, I copied this java File to the folder of the other java files in the library.
Third, I tried to compile the JAVA file via the CMD using javac.
The path of the new java file and the other .JAVA and .CLASS files of the library is: C:\com\example\core\
The name of the new java file would be: "MyNewClass.java"
The command I run via the CMD is: javac C:\com\example\core\MyNewClass.java
But, during the compilation I get many errors saying: Cannot find symbols.
I've been looking up for a solution of this problem but couldn't figure how to solve it and make the new JAR File having another class that I created seperately.
What am I missing?
As per earlier comments:
Rather than trying to modify the JAR, you can get access to the full source code of the Universal Image Loader library by cloning the repository using git or hitting "Download ZIP" on the righthand side of the page you linked.
Once you have the source, import the library in your IDE. From there on you'll be able to build the whole thing from scratch, make any adjustments/modifications you like, etc.
Your classpath might be wrong or there might be some mistake in package name.
When a Java program is being compiled the compiler it creates a list of all the identifiers in use. If it can't find what an identifier refers to it cannot complete the compilation. This is what the cannot find symbol error message is saying, it doesn't have enough information to piece together what the Java code wants to execute.
Try:
javac -cp com/* C:\com\example\core\MyNewClass.java
That should make the compiler aware of all the other classes under com/...