Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Maven compilation fails with "cannot find symbol" while with Eclipse, it compiles

I have a compilation error in Maven but in Eclipse everything goes well.

Is there something I am doing wrong or is it a Maven bug?

I have created a code snippet, so you can try to reproduce it.

Here are the Java source files and a pom.xml.

package p1;

import p1.A.D.C;
import p1.p2.E;

public class A {
    interface B<T> {
        T methodB();
    }

    class D implements B<E> {
        C c = new C();

        public C getC() {
            return c;
        }

        class C {
            public void methodC() {
                System.out.println(this);
            }
        }

        @Override
        public E methodB() {
            return new E();
        }
    }

    public void methodA() {
        D d = new D();
        d.methodB();
        C c = d.getC();
        c.methodC();
    }

    public static void main(String[] args) {
        A a = new A();
        a.methodA();
    }
}


package p1.p2;

public class E {
}


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>mvntst</groupId>
  <artifactId>test</artifactId>
  <version>0</version>
  <packaging>jar</packaging>
  <name>mvntst</name>
</project>

When I run mvn clean compile, I get this output:

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:compile (default-compile) on project test: Compilation failure
[ERROR] /C:/dev/test/CompilerTest/MavenTest/src/main/java/p1/A.java:[6,30] cannot find symbol
[ERROR] symbol:   class E                                                                                                                       
[ERROR] location: class p1.A
[ERROR] -> [Help 1]                                                                                                                             
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.                                                             
[ERROR] Re-run Maven using the -X switch to enable full debug logging.                                                                          
[ERROR]                                                                                                                                         
[ERROR] For more information about the errors and possible solutions, please read the following articles:                                       
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException

Here is the result of mvn --version:

Apache Maven 3.3.1 (cab6659f9874fa96462afef40fcf6bc033d58c1c; 2015-03-13T23:10:27+03:00)
Maven home: C:\dev\apache-maven-3.3.1\bin\..
Java version: 1.8.0_40, vendor: Oracle Corporation
Java home: C:\Program Files\Java\jdk1.8.0_40\jre
Default locale: en_US, platform encoding: Cp1252
OS name: "windows 7", version: "6.1", arch: "amd64", family: "dos"
like image 624
shapkin Avatar asked Dec 14 '15 17:12

shapkin


3 Answers

If you reverse the order of your imports...

import p1.p2.E;
import p1.A.D.C;

...it will compile just fine. This is likely due to the compiler presuming that folders A, D and C exist beneath p1, which isn't the case.

But instead of doing that (which just feels wrong), you should change how you bring in C in methodA.

public void methodA() {
    D d = new D();
    d.methodB();
    D.C c = d.getC();
    c.methodC();
}

You can also get rid of the import of the inner class as well, since that's no longer necessary with the above.

like image 140
Makoto Avatar answered Nov 14 '22 23:11

Makoto


I agree with the other answer that "import p1.A.D.C;" feels wrong and will confuse readers, but technically this may well be OK after all:

First, note that from seeing "import p1.A.D.C" it would be wrong for a compiler to jump to the conclusion that p1.A.D must be a package (as suggested in the other answer). It's perfectly OK to import nested types by their qualified name.

Whether or not the example is legal Java depends on how we interpret this sentence from JLS 7.5.1:

If the type imported by the single-type-import declaration is declared in the compilation unit that contains the import declaration, the import declaration is ignored.

Taking this sentence literally would imply that compilers simply ignore the import for C, resulting in a compile error against the unqualified reference "C" within methodA().

That's not what any of the compiler reports.

Eclipse seems to interpret the JLS sentence as requesting to ignore any redundant imports of toplevel types from the same compilation unit. An import of a nested type is not redundant in this interpretation and can be used to successfully resolve C by its unqualified name.

Javac seems to discard the subsequent import, i.e., the import for C is used but the unrelated import for E is discarded. This appears to be the most plausible explanation why changing the order of imports changes the compiler result, which is not backed by anything in JLS. Moreover, when flipping the order of imports javac seems to agree with Eclipse's interpretation, in that an import of a nested type even from the same compilation unit is useful and should not be ignored.

Ergo: javac seems confused (aka has a bug).

like image 37
Stephan Herrmann Avatar answered Nov 14 '22 22:11

Stephan Herrmann


First try mvn clean if that runs successfully then try mvn install. If this works fine then you can try mvn compile. This process worked for me.

like image 36
Pritom Avatar answered Nov 14 '22 22:11

Pritom