interface A
{
public void f();
public void g();
}
class B implements A
{
public void f()
{
System.out.println("B.f()");
}
}
public class Main
{
public static void main(String[] args)
{
B tmp = new B();
tmp.f();
System.out.println("B.f()");
}
}
I don't implement all the method in the interface A in B
and it has a error that
The type B must implement the inherited abstract method A.g()
but why it can get the output that
B.f()
B.f()
Eclipse allows you to run code with compile-time errors - after giving you a warning and offering you the option to back out (which you should normally take).
If you try to call tmp.g() you'll get an exception indicating a compile-time failure.
Occasionally it can be useful to run code which doesn't fully compile - particularly if the compile-time failure is unrelated to the code you actually wish to run, e.g. when unit testing - but I would be very careful about how you use this feature.
Eclipse can "patch" around certain classes of compile errors, and run a program even if errors exist. Normally, you get a dialog box that says the following:
Errors exist in required project(s):
(project name)
Proceed with launch?
[X] Always launch without asking
If you select Proceed, or if you have disabled the dialog, Eclipse will proceed to fix the compile errors if possible. If you try to run code impacted by the compile error, you'll get a runtime exception.
In this case, Eclipse adds a dummy B.g() method containing just the following:
throw new java.lang.Error("Unresolved compilation problem: \n"
"The type B must implement the inherited abstract method A.g()");
By inserting this dummy method, the code will compile properly and it will run. If you never call B.g, then you'll never see this error.
Related
I would need help trying to understand why this is happening to me:
Using Java 1.8.0_131, I have a class such as this:
public class DynamicClassLoadingAppKO {
/*
* THIS VERSION DOES NOT WORK, A ClassNotFoundException IS THROWN BEFORE EVEN EXECUTING main()
*/
// If this method received ChildClassFromLibTwo, everything would work OK!
private static void showMessage(final ParentClassFromLibOne obj) {
System.out.println(obj.message());
}
public static void main(final String[] args) throws Throwable {
try {
final ChildClassFromLibTwo obj = new ChildClassFromLibTwo();
showMessage(obj);
} catch (final Throwable ignored) {
// ignored, we just wanted to use it if it was present
}
System.out.println("This should be displayed, but no :(");
}
}
Two other classes are being used up there: ParentClassFromLibOne and ChildClassFromLibTwo. The latter extends from the former.
There are two external libraries involved:
One library is called libone and contains the ParentClassFromLibOne class. The application includes this library in the classpath both for compiling and executing.
A second library is called libtwo and contains the ChildClassFromLibTwo class. The application includes this library in the classpath for compiling, but not for executing.
As far as I understand, the Java runtime should try to load the ChildClassFromLibTwo (which is not in the classpath at runtime) at this line:
final ChildClassFromLibTwo obj = new ChildClassFromLibTwo();
Given this class is not in the classpath, a ClassNotFoundException should be thrown, and given this line is inside a try...catch (Throwable), the System.out.println line at the end should be executed anyway.
However, what I get is the ClassNotFoundException thrown when the DynamicClassLoadingAppKO itself is loaded, apparently before the main() method is executed at all, and therefore not caught by the try...catch.
What seems more strange to me is that this behaviour disappears and everything works as I would expect if I change the signature of the showMessage() method so that instead of receiving an argument of the parent class, it is directly of the child class:
/*
* THIS VERSION WORKS OK, BECAUSE showMessage RECEIVES THE CHILD CLASS AS A PARAMETER
*/
private static void showMessage(final ChildClassFromLibTwo obj) {
System.out.println(obj.message());
}
How is this possible? What am I missing in the way class loading works?
For testing convenience, I have created a GitHub repository replicating this behaviour [1].
[1] https://github.com/danielfernandez/test-dynamic-class-loading/tree/20170504
OK, the details of why this happens are explained in this Spring Boot ticket [1] which I've been very lucky to be promptly pointed to by Andy Wilkinson. That was definitely a difficult one IMO.
Apparently, what happens in this case is that when the calling class itself is loaded, the verifier kicks in and sees that the showMessage() method receives an argument of type ParentClassFromLibOne. So far so good, and this would not provoke a ClassNotFoundException at this phase even if ParentClassFromLibOne was not in the classpath at runtime.
BUT apparently the verifier also scans method code and notes that there is a call in main() to that showMessage() method. A call that does not pass as an argument a ParentClassFromLibOne, but instead an object of a different class: ChildClassFromLibTwo.
So it is in this case that the verifier does try to load ChildClassFromLibTwo in order to be able to check if it really extends from ParentClassFromLibOne.
Interestingly this wouldn't happen if ParentClassFromLibOne was an interface, because interfaces are treated as Object for assignment.
Also, this does not happen if showMessage(...) directly asks for a ChildClassFromLibTwo as an argument because in such case the verifier does not need to load the child class to check it is compatible... with itself.
Daniel, I'm voting up your answer but I will not mark it as accepted because I consider it fails at explaining the real reason why this is happening at verify time (it's not the class in the signature of the method that's causing the ClassNotFoundException).
[1] https://github.com/spring-projects/spring-boot/issues/8181
This is a bit more complicated than you think. When a class is loaded, all functions are verified. During the verify phase also all referenced classes are loaded, because they are needed to calculated the exact types that are on the stack at any given location in the bytecode.
If you want that lazy behaviour, you have to pass the -noverify option to Java, which will delay the loading of classes until the functions that reference them are executed the first time. But don't use -noverify for security reasons when you don't have full control over the classes that will be loaded into the JVM.
I understand that it is illegal to declare local variables of the same name in the same scope. I wrote this very simple class, and yes, the IDE does display an error next to int i = 10;. But when I run the code, everything seem to be fine.
public class VariableWithSameName {
static void myMethod(int i){
int i = 10; //error: variable i already defined in method
}
public static void main(String[] args){
}
}
It is only when I called myMethod did a run time error occurred.
public class VariableWithSameName {
static void myMethod(int i){
int i = 10; //error: variable i already defined in method
}
public static void main(String[] args){
myMethod(1);
}
}
Exception in thread "main" java.lang.RuntimeException: Uncompilable
source code - variable i is already defined in method myMethod(int)
So why runnning the first version does not results in a run time error?
Because in run time. You never called your method "VariableWithSameName" and that's why. run time error will only occur if a system run onto an error . but compile time error will determine all possible errors that in can found during compilation
Just adding my 2 cents, If you are wondering how a class with compile error is getting compiled , take a look here https://stackoverflow.com/a/7590454/6785908
The IDE's internal compiler is - at least in some cases - able to keep going with the build, even when some classes don't compile fully. It will even produce class files for the broken classes if possible, generating methods which throw an exception as soon as they're called.
This is a compile-time error. Presumably you successfully compiled before introducing the error and are still executing that .class file.
I've just started learning about TDD and am trying to write a simple project that way.
I'm using Eclipse and JUnit, and every time I make a change I run all the tests in the relevant package.
But then I'm very surprised to see in the package explorer that one of my test cases has a big red cross indicating a compiler problem... Annoyed I figured that I got my eclipse shortcuts mixed up and haven't been running all the tests, as they are all passing.
But when I start fiddling about, I realise that it seems Eclipse + JUnit will run and pass tests even if there are compiler errors...
The JUnit test case:
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
public class ATestCase {
private Command command;
private Invoker invoker;
#Before
public void setUp() throws Exception {
command = new Command() {
public void methodA(){};
//haven't implemented methodB()
};
invoker = new Invoker(command);
}
#Test
public void test(){
invoker.invoke();
}
}
interface Command{
void methodA();
void methodB();
}
The Invoker class:
class Invoker{
private Command command;
public Invoker(Command command) {
this.command = command;
//if I invoke methodB() I get UnresolvedCompilationError
}
public void invoke(){
command.methodA();
//only if I call methodB here
//do I get Unresolved compilation problem
// command.methodB();
}
}
The command object I create in setUp in the test case only implements one of the interface's methods. This of course causes a compilation error warning in Eclipse.
However unless I actually call that method in the test case, the test passes.
If I do call the method, then the test fails with 'unresolved compilation error'.
Can anyone explain to me what exactly is going on?
******EDIT******
I'm not sure why this was closed as a duplicate.
Apparently I'm supposed to edit this question to make the difference clear:
Well the question I'm supposed to be duplicating asks in the first line:
What are the possible causes of a "java.lang.Error: Unresolved
compilation problem"?
The title of my question states I'm asking:
Why/how does JUnit pass tests with compiler errors?
As in how can code which shouldn't compile be run by JUnit without causing errors?
I fully understand the causes of the Unresolved Compilation Error, it's the obvious unresolved compilation error in my code. What I don't understand is how the error doesn't always occur (it only occurs when I specifically call an unimplemented method) and how the tests pass?!
It may be that these issues are related, but unless there is a specific answer explaining how they are related I fail to see how they are in any way duplicate questions...
When a class fails to implement an interface method, the Java compiler does not reject the code but instead emits bytecode for the method that will raise the runtime error seen. This explains why JUnit is able to run the tests and why the test passes if you don't call methodB - the runtime error does not get raised.
Per this page, this does not occur by default but requires that you have the Java -> Debug 'Suspend execution on compilation errors' setting enabled.
I'm assuming that is by design: to allow for testing specific methods without having to worry about whether other dependencies which the compiler would pick up on anyway are resolved or not. i.e. we shouldn't be using JUnit to tell us whether our entire project can compile or not.
I have a class
public Class Foobar{
public void methodA();
}
Now I have a method in another class
public static final void callFooBar(){
Foobar foobar = new Foobar();
foobar.methodA(); <-- error here
}
Error: Exception in thread "main" java.lang.IllegalAccessError: tried to access method package.FooBar.methodA([Ljava/lang/String;)V from class package.mainclass
Any suggestions
(Sorry a newbie here)
First, case sensitive. Your error states FooBar() when your class is named Foobar()
Perhaps you are using a different version of the class at runtime to the one you expect. In particular, the runtime class would be different to the one you've compiled against (else this would have caused a compile-time error) - has that method ever been private? Do you have old versions of the classes/jars on your system anywhere?
As the javadocs for IllegalAccessError state,
Normally, this error is caught by the compiler; this error can only occur at run time if the definition of a class has incompatibly changed.
I'd definitely look at your classpath and check whether it holds any surprises.
Foobar had previously a void methodA(String s). At that time the Foobar using class was compiled.
This using class should have been recompiled after changing the signature of methodA to void methodA().
This did not happen, and hence the error.
The clue: tried to access method package.FooBar.methodA([Ljava/lang/String;)V
This is void methodA(java.lang.String)
I have the following code in Eclipse(Helios)/STS which runs and prints console output when doing a Run As> Java Application, in spite of obvious compilation issues
public interface ITest{
String func();
}
public static class Test implements ITest{
void printFunc(){
System.out.println("Inside Test Function");
}
}
public static void main(String[] args) {
Test test = new Test();
test.printFunc();
}
Can anyone pinpoint the reasoning behind this Eclipse functioning.
Note: Doing a javac externally obviously fails to compile.
Eclipse's Java compiler is designed to cope with flaky, non-compiling code. It will add whatever stuff is necessary to the code to get it to compile.
See this question What is the difference between javac and the Eclipse compiler?
It might have been that you have coded the class successfully before the errors. Eclipse auto-compiles your file while you are coding. Just then, you happen to have errors.. then you decide to run as Java Application, Eclipse will run the most recent compiled class.
I tried your code, implemented the necessary methods to remove the errors, then removed it again to put back the errors.. sure enough, it printed out "Inside Test Function". I also tried commenting out System.out.println("Inside Test Function"); and it still printed out.
In another try, I created another class, added your code, then run (without implementing the errors to avoid auto-compiling), then it printed out an error..
java.lang.NoSuchMethodError: main
Exception in thread "main"