1 /*
   2  * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25  * @test
  26  * @bug 8046171
  27  * @summary Test access to private methods between nestmates where there
  28  *          is an inheritance hierarchy and we invoke private methods that
  29  *          exist in specific classes in the hierarchy.
  30  * @run main TestMethodHandlesHierarchy
  31  */
  32 
  33 import java.lang.invoke.*;
  34 import static java.lang.invoke.MethodHandles.*;
  35 import static java.lang.invoke.MethodType.*;
  36 
  37 public class TestMethodHandlesHierarchy {
  38 
  39    static final MethodType M_T = MethodType.methodType(String.class);
  40 
  41     static class NestedA extends ExternalSuper {
  42         static final String ID =  "NestedA::priv_invoke";
  43         private String priv_invoke() {
  44             return ID;
  45         }
  46         static void checkA(NestedA a) throws Throwable {
  47             MethodHandle mh =
  48                 lookup().findSpecial(NestedA.class, "priv_invoke",
  49                                      M_T,  NestedA.class);
  50             verifyEquals((String)mh.invoke(a), NestedA.ID);
  51             verifyEquals((String)mh.invokeExact(a), NestedA.ID);
  52 
  53             mh = lookup().findVirtual(NestedA.class, "priv_invoke", M_T);
  54             verifyEquals((String)mh.invoke(a), NestedA.ID);
  55             verifyEquals((String)mh.invokeExact(a), NestedA.ID);
  56         }
  57     }
  58 
  59     static class NestedB extends NestedA {
  60         static final String ID =  "NestedB::priv_invoke";
  61         private String priv_invoke() {
  62             return ID;
  63         }
  64         static void checkA(NestedA a) throws Throwable {
  65             MethodHandle mh =
  66                 lookup().findVirtual(NestedA.class, "priv_invoke", M_T);
  67             verifyEquals((String)mh.invoke(a), NestedA.ID);
  68             verifyEquals((String)mh.invokeExact(a), NestedA.ID);
  69         }
  70     }
  71 
  72     static class NestedC extends NestedB {
  73         static final String ID =  "NestedC::priv_invoke";
  74         private String priv_invoke() {
  75             return ID;
  76         }
  77         static void checkA(NestedA a) throws Throwable {
  78             MethodHandle mh =
  79                 lookup().findVirtual(NestedA.class, "priv_invoke", M_T);
  80             verifyEquals((String)mh.invoke(a), NestedA.ID);
  81             verifyEquals((String)mh.invokeExact(a), NestedA.ID);
  82         }
  83     }
  84 
  85     static void checkA(NestedA a) throws Throwable {
  86             MethodHandle mh =
  87                 lookup().findVirtual(NestedA.class, "priv_invoke", M_T);
  88             verifyEquals((String)mh.invoke(a), NestedA.ID);
  89             verifyEquals((String)mh.invokeExact(a), NestedA.ID);
  90     }
  91 
  92     static void checkB(NestedB b) throws Throwable {
  93             MethodHandle mh =
  94                 lookup().findVirtual(NestedB.class, "priv_invoke", M_T);
  95             verifyEquals((String)mh.invoke(b), NestedB.ID);
  96             verifyEquals((String)mh.invokeExact(b), NestedB.ID);
  97     }
  98 
  99     static void checkC(NestedC c) throws Throwable {
 100             MethodHandle mh =
 101                 lookup().findVirtual(NestedC.class, "priv_invoke", M_T);
 102             verifyEquals((String)mh.invoke(c), NestedC.ID);
 103             verifyEquals((String)mh.invokeExact(c), NestedC.ID);
 104     }
 105 
 106 
 107     // Access to private members of classes outside the nest is
 108     // not permitted. These tests should throw IllegalAccessException
 109     // at runtime.
 110 
 111     static void checkExternalSuper(ExternalSuper s) throws Throwable {
 112         try {
 113             lookup().findVirtual(ExternalSuper.class, "priv_invoke", M_T);
 114             throw new Error("Unexpected access to ExternalSuper.priv_invoke");
 115         }
 116         catch (IllegalAccessException iae) {
 117             System.out.println("Got expected exception accessing ExternalSuper.priv_invoke:" + iae);
 118         }
 119     }
 120 
 121     static void checkExternalSub(ExternalSub s) throws Throwable {
 122         try {
 123             lookup().findVirtual(ExternalSub.class, "priv_invoke", M_T);
 124             throw new Error("Unexpected access to ExternalSub.priv_invoke");
 125         }
 126         catch (IllegalAccessException iae) {
 127             System.out.println("Got expected exception accessing ExternalSub.priv_invoke:" + iae);
 128         }
 129     }
 130 
 131     static void verifyEquals(String actual, String expected) {
 132         if (!actual.equals(expected)) {
 133             throw new Error("Expected " + expected + " but got " + actual);
 134         }
 135         System.out.println("Check passed for " + expected);
 136     }
 137 
 138     public static void main(String[] args) throws Throwable {
 139         NestedA a = new NestedA();
 140         NestedB b = new NestedB();
 141         NestedC c = new NestedC();
 142         ExternalSub sub = new ExternalSub();
 143         ExternalSuper sup = new ExternalSuper();
 144 
 145         checkExternalSuper(sup);
 146         checkExternalSuper(a);
 147         checkExternalSuper(b);
 148         checkExternalSuper(c);
 149         checkExternalSuper(sub);
 150 
 151         checkA(a);
 152         checkA(b);
 153         checkA(c);
 154         checkA(sub);
 155 
 156         NestedA.checkA(a);
 157         NestedA.checkA(b);
 158         NestedA.checkA(c);
 159         NestedA.checkA(sub);
 160 
 161         NestedB.checkA(a);
 162         NestedB.checkA(b);
 163         NestedB.checkA(c);
 164         NestedB.checkA(sub);
 165 
 166         NestedC.checkA(a);
 167         NestedC.checkA(b);
 168         NestedC.checkA(c);
 169         NestedC.checkA(sub);
 170 
 171         checkB(b);
 172         checkB(c);
 173         checkB(sub);
 174 
 175         checkC(c);
 176         checkC(sub);
 177 
 178         checkExternalSub(sub);
 179     }
 180 }
 181 
 182 // Classes that are not part of the nest.
 183 // Being non-public allows us to declare them in this file.
 184 
 185 class ExternalSuper {
 186     static final String ID =  "ExternalSuper::priv_invoke";
 187     private String priv_invoke() {
 188         return ID;
 189     }
 190 }
 191 
 192 
 193 class ExternalSub extends TestMethodHandlesHierarchy.NestedC {
 194     static final String ID =  "ExternalSub::priv_invoke";
 195     private String priv_invoke() {
 196         return ID;
 197     }
 198 }