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 and nest-host
  28  *          using different flavours of named nested types using MethodHandles
  29  * @run main TestMethodHandles
  30  */
  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 TestMethodHandles {
  38 
  39     static final MethodType M_T = MethodType.methodType(void.class);
  40 
  41     // Private method of nest-host for nestmates to access
  42     private void priv_invoke() {
  43         System.out.println("TestMethodHandles::priv_invoke");
  44     }
  45 
  46     // public constructor so we aren't relying on private access
  47     public TestMethodHandles() {}
  48 
  49     // Methods that will access private methods of nestmates
  50 
  51     void access_priv(TestMethodHandles o) throws Throwable {
  52         MethodHandle mh = lookup().findVirtual(o.getClass(), "priv_invoke", M_T);
  53         mh.invoke(o);
  54         mh.invokeExact(o);
  55         checkBadInvoke(mh, new StaticNested()); // wrong nestmate
  56         checkBadInvoke(mh, mh); // completely wrong type
  57         // findSpecial also works when this and o are the same class
  58         mh = lookup().findSpecial(o.getClass(), "priv_invoke", M_T, this.getClass());
  59         mh.invoke(o);
  60         mh.invokeExact(o);
  61         checkBadInvoke(mh, new StaticNested()); // wrong nestmate
  62         checkBadInvoke(mh, mh); // completely wrong type
  63     }
  64     void access_priv(InnerNested o) throws Throwable {
  65         MethodHandle mh = lookup().findVirtual(o.getClass(), "priv_invoke", M_T);
  66         mh.invoke(o);
  67         mh.invokeExact(o);
  68         checkBadInvoke(mh, this); // wrong nestmate
  69         checkBadInvoke(mh, mh); // completely wrong type
  70         try {
  71             mh = lookup().findSpecial(o.getClass(), "priv_invoke", M_T, this.getClass());
  72             throw new Error("findSpecial() succeeded unexpectedly");
  73         }
  74         catch (IllegalAccessException expected) {}
  75     }
  76     void access_priv(StaticNested o) throws Throwable {
  77         MethodHandle mh = lookup().findVirtual(o.getClass(), "priv_invoke", M_T);
  78         mh.invoke(o);
  79         mh.invokeExact(o);
  80         checkBadInvoke(mh, this); // wrong nestmate
  81         checkBadInvoke(mh, mh); // completely wrong type
  82         try {
  83             mh = lookup().findSpecial(o.getClass(), "priv_invoke", M_T, this.getClass());
  84             throw new Error("findSpecial() succeeded unexpectedly");
  85         }
  86         catch (IllegalAccessException expected) {}
  87     }
  88     void access_priv(StaticIface o) throws Throwable {
  89         MethodHandle mh = lookup().findVirtual(StaticIface.class, "priv_invoke", M_T);
  90         mh.invoke(o);
  91         mh.invokeExact(o);
  92         checkBadInvoke(mh, this); // wrong nestmate
  93         checkBadInvoke(mh, mh); // completely wrong type
  94         try {
  95             mh = lookup().findSpecial(StaticIface.class, "priv_invoke", M_T, this.getClass());
  96             throw new Error("findSpecial() succeeded unexpectedly");
  97         }
  98         catch (IllegalAccessException expected) {}
  99     }
 100 
 101     // The various nestmates
 102 
 103     static interface StaticIface {
 104 
 105         private void priv_invoke() {
 106             System.out.println("StaticIface::priv_invoke");
 107         }
 108 
 109         // Methods that will access private methods of nestmates
 110 
 111         default void access_priv(TestMethodHandles o) throws Throwable {
 112             MethodHandle mh =
 113               lookup().findVirtual(o.getClass(), "priv_invoke", M_T);
 114             mh.invoke(o);
 115             mh.invokeExact(o);
 116             checkBadInvoke(mh, this); // wrong nestmate
 117             checkBadInvoke(mh, mh); // completely wrong type
 118             try {
 119                 mh = lookup().findSpecial(o.getClass(), "priv_invoke", M_T, this.getClass());
 120                 throw new Error("findSpecial() succeeded unexpectedly");
 121             }
 122             catch (IllegalAccessException expected) {}
 123         }
 124         default void access_priv(InnerNested o) throws Throwable {
 125             MethodHandle mh = lookup().findVirtual(o.getClass(), "priv_invoke", M_T);
 126             mh.invoke(o);
 127             mh.invokeExact(o);
 128             checkBadInvoke(mh, this); // wrong nestmate
 129             checkBadInvoke(mh, mh); // completely wrong type
 130             try {
 131                 mh = lookup().findSpecial(o.getClass(), "priv_invoke", M_T, this.getClass());
 132                 throw new Error("findSpecial() succeeded unexpectedly");
 133             }
 134             catch (IllegalAccessException expected) {}
 135         }
 136         default void access_priv(StaticNested o) throws Throwable {
 137             MethodHandle mh = lookup().findVirtual(o.getClass(), "priv_invoke", M_T);
 138             mh.invoke(o);
 139             mh.invokeExact(o);
 140             checkBadInvoke(mh, this); // wrong nestmate
 141             checkBadInvoke(mh, mh); // completely wrong type
 142             try {
 143                 mh = lookup().findSpecial(o.getClass(), "priv_invoke", M_T, this.getClass());
 144                 throw new Error("findSpecial() succeeded unexpectedly");
 145             }
 146             catch (IllegalAccessException expected) {}
 147         }
 148         default void access_priv(StaticIface o) throws Throwable {
 149             MethodHandle mh = lookup().findVirtual(StaticIface.class, "priv_invoke", M_T);
 150             mh.invoke(o);
 151             mh.invokeExact(o);
 152             checkBadInvoke(mh, new StaticNested()); // wrong nestmate
 153             checkBadInvoke(mh, mh); // completely wrong type
 154             // findSpecial also works when this and o are the same interface
 155             mh = lookup().findSpecial(StaticIface.class, "priv_invoke", M_T, StaticIface.class);
 156             mh.invoke(o);
 157             mh.invokeExact(o);
 158             checkBadInvoke(mh, new StaticNested()); // wrong nestmate
 159             checkBadInvoke(mh, mh); // completely wrong type
 160         }
 161     }
 162 
 163     static class StaticNested {
 164 
 165         private void priv_invoke() {
 166             System.out.println("StaticNested::priv_invoke");
 167         }
 168 
 169         // public constructor so we aren't relying on private access
 170         public StaticNested() {}
 171 
 172         // Methods that will access private methods of nestmates
 173 
 174         void access_priv(TestMethodHandles o) throws Throwable {
 175             MethodHandle mh = lookup().findVirtual(o.getClass(), "priv_invoke", M_T);
 176             mh.invoke(o);
 177             mh.invokeExact(o);
 178             checkBadInvoke(mh, this); // wrong nestmate
 179             checkBadInvoke(mh, mh); // completely wrong type
 180             try {
 181                 mh = lookup().findSpecial(o.getClass(), "priv_invoke", M_T, this.getClass());
 182                 throw new Error("findSpecial() succeeded unexpectedly");
 183             }
 184             catch (IllegalAccessException expected) {}
 185         }
 186         void access_priv(InnerNested o) throws Throwable {
 187             MethodHandle mh = lookup().findVirtual(o.getClass(), "priv_invoke", M_T);
 188             mh.invoke(o);
 189             mh.invokeExact(o);
 190             checkBadInvoke(mh, this); // wrong nestmate
 191             checkBadInvoke(mh, mh); // completely wrong type
 192             try {
 193                 mh = lookup().findSpecial(o.getClass(), "priv_invoke", M_T, this.getClass());
 194                 throw new Error("findSpecial() succeeded unexpectedly");
 195             }
 196             catch (IllegalAccessException expected) {}
 197         }
 198         void access_priv(StaticNested o) throws Throwable {
 199             MethodHandle mh = lookup().findVirtual(o.getClass(), "priv_invoke", M_T);
 200             mh.invoke(o);
 201             mh.invokeExact(o);
 202             checkBadInvoke(mh, new TestMethodHandles()); // wrong nestmate
 203             checkBadInvoke(mh, mh); // completely wrong type
 204             // findSpecial also works when this and o are the same class
 205             mh = lookup().findSpecial(o.getClass(), "priv_invoke", M_T, this.getClass());
 206             mh.invoke(o);
 207             mh.invokeExact(o);
 208             checkBadInvoke(mh, new TestMethodHandles()); // wrong nestmate
 209             checkBadInvoke(mh, mh); // completely wrong type
 210         }
 211         void access_priv(StaticIface o) throws Throwable {
 212             MethodHandle mh = lookup().findVirtual(StaticIface.class, "priv_invoke", M_T);
 213             mh.invoke(o);
 214             mh.invokeExact(o);
 215             checkBadInvoke(mh, this); // wrong nestmate
 216             checkBadInvoke(mh, mh); // completely wrong type
 217             try {
 218                 mh = lookup().findSpecial(StaticIface.class, "priv_invoke", M_T, this.getClass());
 219                 throw new Error("findSpecial() succeeded unexpectedly");
 220             }
 221             catch (IllegalAccessException expected) {}
 222         }
 223     }
 224 
 225     class InnerNested {
 226 
 227         private void priv_invoke() {
 228             System.out.println("InnerNested::priv_invoke");
 229         }
 230 
 231         // public constructor so we aren't relying on private access
 232         public InnerNested() {}
 233 
 234         void access_priv(TestMethodHandles o) throws Throwable {
 235             MethodHandle mh = lookup().findVirtual(o.getClass(), "priv_invoke", M_T);
 236             mh.invoke(o);
 237             mh.invokeExact(o);
 238             checkBadInvoke(mh, this); // wrong nestmate
 239             checkBadInvoke(mh, mh); // completely wrong type
 240             try {
 241                 mh = lookup().findSpecial(o.getClass(), "priv_invoke", M_T, this.getClass());
 242                 throw new Error("findSpecial() succeeded unexpectedly");
 243             }
 244             catch (IllegalAccessException expected) {}
 245         }
 246         void access_priv(InnerNested o) throws Throwable {
 247             MethodHandle mh = lookup().findVirtual(o.getClass(), "priv_invoke", M_T);
 248             mh.invoke(o);
 249             mh.invokeExact(o);
 250             checkBadInvoke(mh, new StaticNested()); // wrong nestmate
 251             checkBadInvoke(mh, mh); // completely wrong type
 252             // findSpecial also works when this and o are the same class
 253             mh = lookup().findSpecial(o.getClass(), "priv_invoke", M_T, this.getClass());
 254             mh.invoke(o);
 255             mh.invokeExact(o);
 256             checkBadInvoke(mh, new StaticNested()); // wrong nestmate
 257             checkBadInvoke(mh, mh); // completely wrong type
 258         }
 259         void access_priv(StaticNested o) throws Throwable {
 260             MethodHandle mh = lookup().findVirtual(o.getClass(), "priv_invoke", M_T);
 261             mh.invoke(o);
 262             mh.invokeExact(o);
 263             checkBadInvoke(mh, this); // wrong nestmate
 264             checkBadInvoke(mh, mh); // completely wrong type
 265             try {
 266                 mh = lookup().findSpecial(o.getClass(), "priv_invoke", M_T, this.getClass());
 267                 throw new Error("findSpecial() succeeded unexpectedly");
 268             }
 269             catch (IllegalAccessException expected) {}
 270         }
 271         void access_priv(StaticIface o) throws Throwable {
 272             MethodHandle mh = lookup().findVirtual(StaticIface.class, "priv_invoke", M_T);
 273             mh.invoke(o);
 274             mh.invokeExact(o);
 275             checkBadInvoke(mh, this); // wrong nestmate
 276             checkBadInvoke(mh, mh); // completely wrong type
 277             try {
 278                 mh = lookup().findSpecial(StaticIface.class, "priv_invoke", M_T, this.getClass());
 279                 throw new Error("findSpecial() succeeded unexpectedly");
 280             }
 281             catch (IllegalAccessException expected) {}
 282         }
 283     }
 284 
 285     static void checkBadInvoke(MethodHandle mh, Object o) throws Throwable {
 286         try {
 287             mh.invoke(o);
 288             throw new Error("Invoke on MethodHandle " + mh + " with receiver "
 289                             + o + "should have failed with ClassCastException!");
 290          }
 291          catch (ClassCastException expected) {
 292              System.out.println("invoke got expected exception: " + expected);
 293          }
 294     }
 295 
 296     public static void main(String[] args) throws Throwable {
 297         TestMethodHandles o = new TestMethodHandles();
 298         StaticNested s = new StaticNested();
 299         InnerNested i = o.new InnerNested();
 300         StaticIface intf = new StaticIface() {};
 301 
 302         o.access_priv(new TestMethodHandles());
 303         o.access_priv(i);
 304         o.access_priv(s);
 305         o.access_priv(intf);
 306 
 307         s.access_priv(o);
 308         s.access_priv(i);
 309         s.access_priv(new StaticNested());
 310         s.access_priv(intf);
 311 
 312         i.access_priv(o);
 313         i.access_priv(o.new InnerNested());
 314         i.access_priv(s);
 315         i.access_priv(intf);
 316 
 317         intf.access_priv(o);
 318         intf.access_priv(i);
 319         intf.access_priv(s);
 320         intf.access_priv(new StaticIface(){});
 321     }
 322 }