In memory I build this string:
package consume;
public class Consumer {
public void consume(String message){
System.out.println(new produce.Producer().produce(message));
}
}
On my filesystem I have C:\Users\hooch\Desktop\produce\Producer.class built from this source:
package produce;
public class Producer {
public String produce(String message){
return "THIS IS THE MESSAGE: " + message;
}
}
I use org.eclipse.jdt.internal.compiler.tool.EclipseCompiler and pass these options:
Arrays.asList(new String[] {"-cp", "C:\\Users\\hooch\\Desktop"});
I try to compile it but get this error
1. ERROR in \Consumer.java (at line 4)
System.out.println(new produce.Producer().produce(message));
^^^^^^^
produce cannot be resolved to a type
If I have the class produce.Producer inside the project which calls the EclipseCompiler, it works. (I do not need to specify the classpath in the options then) Now the question is: how do I correctly specify the classpath so that the in-memory code can access external classes?
If I add -verbose to options, I get
[parsing \Consumer.java - #1/1]
[reading java/lang/Object.class]
[reading java/lang/String.class]
[analyzing \Consumer.java - #1/1]
[reading java/lang/System.class]
[reading java/io/PrintStream.class]
[reading java/io/FilterOutputStream.class]
[reading java/io/OutputStream.class]
[reading java/io/Flushable.class]
[reading java/io/Closeable.class]
[reading java/lang/AutoCloseable.class]
----------
1. ERROR in \Consumer.java (at line 4)
System.out.println(new produce.Producer().produce(message));
^^^^^^^
produce cannot be resolved to a type
----------
[completed \Consumer.java - #1/1]
[1 unit compiled]
1 problem (1 error)Exception in thread "main" java.lang.NullPointerException
at impl.SimpleTestCompiler.executeCode(SimpleTestCompiler.java:137)
at impl.SimpleTestCompiler.main(SimpleTestCompiler.java:155)
Ok, now I'm sure it must have to do with the classpath option because I swapped EclipseCompiler for javax.tools.ToolProvider.getSystemJavaCompiler() and I get the same error about the package not being resolved.
This should work (if you double the backslashes in the String which I assume you did because you would get compile errors in the code which invokes the compiler).
Try to add -verbose to the compiler options to see which files it tries to access.
[EDIT] As the next steps:
Try to run the compiler from the command line.
If that doesn't work, get the sources and try to debug it. There is probably something wrong with passing the classpath to the compiler.
I'm a little bit worried by the path of the source file (\Consumer.java). Try to create a correct package path when passing this virtual file to the compiler.
Related
I wrote a Java program whose filename was (intentionally) different from the class I wrote inside the file. The javac command failed as expected on both CMD and WSL. The java command however worked and ran my print statement. I wrote the code intentionally this way so there is no way it was a previously compiled version of the code. The following code was written in a file called "explainJava.java" (notice the filename is different from the class name).
public class explain{
public static void main(String[] args) {
System.out.println("Java is weird");
}
}
I've had to google this myself, but I think I've found an explanation in this article.
According to that source as of Java 11 java is capable of compiling a single source file into memory.
What I conclude from that: When the file is compiled into memory and not written to disk it obviously cannot have a file name. If there is no filename there is no such thing as a wrong filename, therefore the code executes.
Please also note that the restriction of having to name a file like the public class within that file is more of a design decision to make work for the compiler easier/ faster. It is not a physical restriction so to speak. Have a look at the following thread for more details.
If you put this code:
public class explain {
public static void main(String[] args) {
System.out.println("Java is weird");
}
}
into a file named explainJava.java, and then compile it with this:
javac explainJava.java
you will get an error that correctly informs you that your filename ("explainJava") and the class defined inside that file ("explain") do not match:
explainJava.java:1: error: class explain is public, should be declared in a file named explain.java
public class explain{
^
1 error
If you run this command:
$ java explainJava.java
Java is weird
you see expected output, because you're skipping the explicit compilation step (that is, you aren't running javac first) and instead relying on behavior introduced in Java 11 that allows you to compile+run in a single step. Here's an explanation: Does the 'java' command compile Java programs?
So the answer is to either:
rename your file to match the class, so change the filename to "explain.java", or
rename the class to match the file, change public class explain to be public class explainJava
I am using JDK11. Below is my sample class -
public class SayHi {
public static void main(String[] args) {
System.out.println("Hi There");
}
}
I executed the above class with command "java filename.java" for below scenarios
ColumnA -> Class declared as public?
ColumnB -> File name same as class name?
ColumnA ColumnB Result
Yes Yes Yes
No Yes Yes
*Yes No Yes
No No Yes
For all the scenarios, the command executed successfully and I got the result. I get compile-time error for the "Yes-No" case, if I run the "javac" command on the file name.
Why I am not getting the compile-time error when I am executing "java" command on the file name?
I have multiple public classes in a single code file. I am able to execute the file using "java filename.java" command. What I am missing with the compile-time issues when running the file with "java" command. Please help me on this.
The answers to all your questions can be found in JEP 330. I believe the following excerpts provide answers to your questions.
the first class found in the source file is executed
The source file should contain one or more top-level classes, the first of which is taken as the class to be executed
The compiler does not enforce the optional restriction defined at the end of JLS ยง7.6, that a type in a named package should exist in a file whose name is composed from the type name followed by the .java extension
In other words, when you compile a java source code file with javac, the source code file must contain a single, "public" class whose name matches the name of the file. But when you run a java source code file using the java command, the above restriction does not apply.
The class to be executed is the first top-level class found in the source file. It must contain a declaration of the standard public static void main(String[]) method.
I would like to determine whether the javadoc command that we issue from a makefile encounters any errors or warnings. Currently, I can see that we're encountering errors due to import statements that are not on the classpath that we specify to javadoc (but should be). I ultimately want to fix our javadoc invocation and content and then lock it down so that any error or warning will be caught by the makefile and stop the build. However, as far as I can tell, the documentation does not mention any return code values from the javadoc command. Note that we're using Java 7 and running javadoc from a command in a GNU makefile, not from Ant or Maven. What do you recommend that I do?
UPDATE: My command looks like this:
<path1>/javadoc -overview <path2>/overview.html -sourcepath <path3> <file1> <file2> <dir1> <dir2> -d <output_dir>
There's nothing I can see in that call that would cause errors to be treated as warnings.
Here's a fragment from the output that shows the error/warning messages I'm seeing:
....
Constructing Javadoc information...
../../../<path>/<filename>.java:5: error: package javax.servlet.http does not exist
import javax.servlet.http.HttpSessionBindingEvent;
....
The word "error" appears in them, but at the end, the output says only "50 warnings". If I add another issue (such as the #invalid tag suggested in one of the answers), I get 51 warnings.
I just tried from the commandline, when no errors are present, a value of zero is returned:
> javadoc my.package.name
> ....
> echo $?
> 0
After editing a javadoc command with:
/**
* #invalid
*/
and running the same javadoc command again, I get an error message and a return code of 1:
> javadoc my.package.name
> ....
> ./my/package/name/Coordinate.java:21: error: unknown tag: invalid
> * #invalid
> ^
> ....
> echo $?
> 1
So you just should check if the return value of javadoc is 0 or not. If you do not know how to check that return, read this SO question and answer
Even though javadoc 1.7 reports errors, it returns with a zero return value, so the build doesn't catch it. However, javadoc 1.8 returns with a nonzero return value, which the build does catch.
I have a simple class with just a main method that prints something and a package statement as follows
package default;
public class Main
{
public static void main(String[] args)
{
System.out.printf("something\n");
}
}
I have put the file Main.java into a folder default and I have attempted to compile it using the following command.
javac default/Main.java
The problem is that when I try to compile the class I get the following error message verbatim
default/Main.java:1: error: <identifier> expected
package default;
^
1 error
I'm really confused by this. If I take the package statement out or put the code into an IDE such as eclipse, the error goes away and it works fine. I have tried scouring the internet for answers to this question and all sources say that what I'm doing should work.
I have also tried to modify the compile statement as recommended by several Stack Overflow threads by including a classpath as follows
javac -cp default default/Main.java
but the error message remains the same.
Some of my colleagues at my university have suggested that using packages outside of an IDE is impossible and that the only way for my code to compile by command line is to remove the package statement, but that answer doesn't seem right to me.
If anyone knows why I am having this issue, I would really appreciate a response. I just really want to know what I am doing wrong.
"default", Is a keyword in java, you can't use keywords as package name or for example as a variable name. The default keyword belongs to a switch statement:
switch(x){
case 1:
//do stuff if x is 1...
break;
default:
//do stuff if x is not any of the other cases
break;
}
I'm trying to link my Android app with a JAR that was compiled with Free Pascal. I'm getting the following build error:
[2012-09-14 16:08:38 - MyApp] Dx
EXCEPTION FROM SIMULATION:
[2012-09-14 16:08:38 - MyApp] Dx local 0009: invalid
[2012-09-14 16:08:38 - Yarxi] Dx ...at bytecode offset 00015f2c
locals[0000]: Lcom/mypackage/$Core$$_fpc_nestedvars$70;
locals[0001]: I
locals[0002]: I
locals[0003]: I
locals[0004]: I
locals[0005]: I
locals[0006]: I
locals[0007]: I
locals[0008]: I
locals[0009]: <invalid>
locals[000a]: <invalid>
(..more locals... much more)
locals[06db]: <invalid>
stack[0003]: I
stack[0002]: I
stack[0001]: [I
stack[top0]: int{0x00000000 / 0}
...while working on block 5f23
...while working on method $MyMethod$944$FPR1:(Lcom/mypackage/$Core$$_fpc_nestedvars$70;)V
...while processing $MyMethod$944$FPR1 (Lcom/mypackage/$Core$$_fpc_nestedvars$70;)V
...while processing com/mypackage/Core.class
[2012-09-14 16:08:40 - MyApp] Dx 1 error; aborting
[2012-09-14 16:08:40 - MyApp] Conversion to Dalvik format failed with error 1
The error seems to be that at some point, the code tries to read local 0009, which is not initialized.
Now, Pascal does not enforce initialization of local variables. Chances are, initialization was omitted in the first place. I've retained the JVM assembly file that Free Pascal generated for me. Those are assembled with Jasmin into class files. The file is huge - I'm not pasting it here.
Can someone please help me trace back the point of error to the source? The error is at bytecode offset 00015f2c. Is there a way to translate that back into assembly file line number?
Resolved. 00015f2c (89900 decimal) is, indeed, a bytecode offset within a method. I did the following.
First, I called Jasmin directly, passing the generated .j file and the -g option (generate line numbers):
java -jar %JASM% -g Core.j
Free Pascal does not emit -g by itself. This gave me an alternative Core.class file with line numbers in it, line numbers being relative to the FPC-generated .j file. Then I used javap to disassemble the class back into another .j file:
"%JDKROOT%\javap" -l -c Core.class >Core_WithLines.j
But this new .j file contained line numbers and offsets of each individual command. I then searched for offset 89900 in the offending method (note: offsets, as generated by javap, wrap at 65536). Then I looked at the LineNumberTable below that method's body (both offsets and line numbers wrap), found the line number in the source Core.j file that corresponded to this offset. Looked back at Core.j, and there was a comment that contained the line number of the Pascal source.
There was, indeed, a function call that passed an uninitialized variable - but as a var parameter.
The issue is something of a Pascal/JVM borderline issue. The variable was uninitialized, but it was passed by ref into a function to be returned from the latter. The compiler should've abstracted that away somehow, IMHO, but FPC did not.