Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java import static fails when imported class extends 3rd party lib

The problem setup consists of three java libs (I stripped all package names for readability, full qualified names are used everywhere):

  1. external-lib: provides the abstract class

    public abstract class AbstractExternal {}
    
  2. my-lib-A: provides the class

    public class ClassA extends AbstractExternal {
        public static final String FOO = "foo";
    }
    

    external-lib is in my-lib-A's classpath.

  3. my-lib-B statically imports FOO from ClassA:

    import static ClassA.FOO;
    public class ClassB {
        private String foo = FOO;
    }
    

    my-lib-A is in my-lib-B's classpath but external-lib is not.

Problem: The import static line produces the following error:

The type AbstractExternal cannot be resolved. It is indirectly referenced from required .class files.

However (1), when modifying ClassB to

import ClassA;
public class ClassB {
    private String foo = ClassA.FOO;
}

the compiler is happy.

However (2), when adding a second abstraction two my-lib-A like

public class AbstractClassA extends AbstractExternal {}

and

public class ClassA extends AbstractClassA {
    public static final String FOO = "foo";
}

the static import of ClassA.FOO in the example above works.

Question 1: Why does import static ClassA.FOO fails while import ClassA with ClassA.FOO works?

Question 2: Why does import static ClassA.FOO works when it extends another class from my-lib-A which then extends AbstractExternal?

Edit: a significant information: the compiler in question is the Eclipse Compiler for Java (ECJ).

Edit 2: javac is in sync with ECJ and is able to compile the normal import and class access in ClassB while the static import fails.

like image 213
Henning Treu Avatar asked Apr 16 '18 14:04

Henning Treu


People also ask

Are static imports bad Java?

by Joshua Bloch.) This is considered bad Java programming practice because when a class implements an interface, it becomes part of the class's public API. Implementation details, such as using the static members of another class, should not leak into public APIs.

Can we import static method in Java?

Static import is a feature introduced in the Java programming language that allows members (fields and methods) which have been scoped within their container class as public static , to be used in Java code without specifying the class in which the field has been defined.

Is it good to use static import in Java?

So when should you use static import? Very sparingly! Only use it when you'd otherwise be tempted to declare local copies of constants, or to abuse inheritance (the Constant Interface Antipattern). In other words, use it when you require frequent access to static members from one or two classes.

What is difference between import and static import in Java?

What is the difference between import and static import? The import allows the java programmer to access classes of a package without package qualification whereas the static import feature allows to access the static members of a class without the class qualification.


1 Answers

Ecj ideally "shouldn't" report this error. I filed Bug 533890 to track this.

The common theme behind all errors of this message ("... cannot be resolved. It is indirectly referenced ...") is a conflict between:

  1. wanting full semantic analysis which is aware of all relevant classes and
  2. wanting resilience if the build path does not contain all classes upon which the current class (indirectly) depends.

Obviously, JLS doesn't specify how compilers should handle incomplete build paths, but as a convenience for users, no errors should be reported if semantic analysis can avoid looking into certain indirect dependencies.

Where and when this can indeed be avoided needs to be checked (and implemented) on a case-by-case basis, but the given example likely qualifies as a case that can be avoided.

Until this issue is resolved, the problem can be avoided by making external-lib visible also to my-lib-B (e.g., using a project dependency). In module systems like OSGi or JPMS, it might actually be a good idea to let my-lib-A "re-export" its dependency external-lib, since its API class ClassA is "incomplete" for clients that are unable to see AbstractExternal.

like image 93
Stephan Herrmann Avatar answered Oct 04 '22 08:10

Stephan Herrmann