18

The following code written in Java-9 being run gives me a very weird and funny exception in runtime:

Exception in thread "main" java.lang.NoSuchFieldError: super
    at A$C.test(A.java:15)
    at A.main(A.java:5)

The code:

public class A {
    public static void main(String[] args) {
        new C().test();
    }

    interface B {
        private void test() {
        }
    }

    static class C implements B {
        void test() {
            B.super.test();
        }
    }
}

I am wondering: is it designed so, or ideally this code shouldn't be compiled, and therefore this is a compiler bug? (I personally believe that this is a bug).

UPD: Submitted a bug, ID : 9052188

UPD-2: It looks like B.super.test() is generally a valid construction, because if test() method is default than it works fine. This fact just makes things more complicated.

Andremoniy
  • 34,031
  • 20
  • 135
  • 241
  • 5
    Guessing here: A) this code is invalid (the B super interface is an interface, thus there is no point in deferring to an **implementation** of a method within that) and B) yeah, compiler bug. So the reasonable thing to do: go write a bug tracker issue ;-) – GhostCat Jan 09 '18 at 19:41
  • 6
    Of course, it is a compiler bug. A program that compiles without errors and is not manipulated afterwards should never get a `NoSuchFieldError` at runtime (unless creating and throwing it itself explicitly), regardless of whether the source code is valid or invalid. – Holger Jan 09 '18 at 19:42
  • 1
    @Holger theoretically it could be also JVM bug if such a code is allowed according to JLS 9. But I am to reluctant to delve into it :) – Andremoniy Jan 09 '18 at 19:47
  • @DwB I have no explicit module definitions – Andremoniy Jan 09 '18 at 19:56
  • 4
    @GhostCat: not exactly. `B` has a `private` method, which is accessible because it’s a nested class and we’re within the same top level class. But I suppose, `B.super.test()` is not the right syntax for it (but it is the right syntax for invoking `default` methods). In contrast, `((B)this).test()` is definitely valid syntax and also works correctly. – Holger Jan 09 '18 at 19:57
  • 5
    @Andremoniy well, yes, without going deeper, we could assume that this could be a JVM bug, but well, I went deeper. `super` access is never implementing using a field called `super`, further, when calling the method via `((B)this).test()`, it works smoothly. The only remaining question is whether `B.super.test()` is valid and should get compiled like `((B)this).test()` or whether it is not valid and should be rejected by the compiler. I tend to the latter. – Holger Jan 09 '18 at 20:00
  • @Holger, a funny thing is that `B.super.test()` is valid construction if `test()` is a `default` method :) – Andremoniy Jan 09 '18 at 20:04
  • Now I tend to consider this as a JVM bug, because it generally should be possible access `test()` method even it is private within the scope of this inner class. – Andremoniy Jan 09 '18 at 20:13
  • 1
    @Andremoniy I tend to agree with you here, a very interesting finding – Eugene Jan 09 '18 at 20:38
  • 5
    I [already mentioned](https://stackoverflow.com/questions/48175532/java-lang-nosuchfielderror-super-exception-bug-in-compiler?noredirect=1#comment83331209_48175532) that `Interface.super.method()` is the right way to invoke `default` methods, but as far as I can see in the JLS, it is *only* for invoking `default` methods. Regarding the accessibility, the JVM never allows accessing `private` methods by other (ordinary) classes. That's why the compiler generates these synthetic `access$n` methods for nested classes. A `NoSuchFieldError` is not an indicator that the JVM denied method access. – Holger Jan 09 '18 at 23:36

1 Answers1

10

In the end this issue was admitted as a bug by the Java Developer Support team, here is a link: https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8194847

Andremoniy
  • 34,031
  • 20
  • 135
  • 241