/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; // // Two classes A and B with method foo(). // class A { A() { System.out.println("new A"); } public void foo() { System.out.println("I am A's foo"); } // We previously used to invoke this method with a Y instance, due // to invoke-super underspecified behavior. public void bar() { System.out.println("I am A's bar"); } } class B { B() { System.out.println("new B"); } public void foo() { System.out.println("I am B's foo"); } } // // Two subclasses X and Y that call foo() on super. // class X extends A { public void foo() { super.foo(); } } class Y extends B { public void foo() { super.foo(); } } // // Driver class. // public class Main { public static void main(String[] args) throws Exception { // The normal stuff, X's super goes to A, Y's super goes to B. new X().foo(); new Y().foo(); // And now it gets interesting. // In bytecode, we define a class Z that is a subclass of A, and we call // invoke-super on an instance of Y. Class<?> z = Class.forName("Z"); Method m = z.getMethod("foo"); try { m.invoke(z.newInstance()); throw new Error("Expected InvocationTargetException"); } catch (InvocationTargetException e) { if (!(e.getCause() instanceof NoSuchMethodError)) { throw new Error("Expected NoSuchMethodError"); } } System.out.println("passed"); } }