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  * @compile TestInvokeHierarchy.java
  31  * @compile ExternalSuper.jcod ExternalSub.jcod
  32  * @run main TestInvokeHierarchy
  33  */
  34 
  35 public class TestInvokeHierarchy {
  36 
  37     static class NestedA extends ExternalSuper {
  38         static final String ID =  "NestedA::priv_invoke";
  39         private String priv_invoke() {
  40             return ID;
  41         }
  42         static void checkA(NestedA a) throws Throwable {
  43             verifyEquals(a.priv_invoke(), NestedA.ID);
  44         }
  45     }
  46 
  47     static class NestedB extends NestedA {
  48         static final String ID =  "NestedB::priv_invoke";
  49         private String priv_invoke() {
  50             return ID;
  51         }
  52         static void checkA(NestedA a) throws Throwable {
  53             verifyEquals(a.priv_invoke(), NestedA.ID);
  54         }
  55     }
  56 
  57     static class NestedC extends NestedB {
  58         static final String ID =  "NestedC::priv_invoke";
  59         private String priv_invoke() {
  60             return ID;
  61         }
  62         static void checkA(NestedA a) throws Throwable {
  63             verifyEquals(a.priv_invoke(), NestedA.ID);
  64         }
  65     }
  66 
  67     static void checkA(NestedA a) throws Throwable {
  68         verifyEquals(a.priv_invoke(), NestedA.ID);
  69     }
  70 
  71     static void checkB(NestedB b) throws Throwable {
  72         verifyEquals(b.priv_invoke(), NestedB.ID);
  73     }
  74 
  75     static void checkC(NestedC c) throws Throwable {
  76         verifyEquals(c.priv_invoke(), NestedC.ID);
  77     }
  78 
  79 
  80     // Access to private members of classes outside the nest is
  81     // not permitted. These tests should throw IllegalAccessError
  82     // at runtime. To allow them to compile the classes below are
  83     // defined with public members. We then replace those class files
  84     // with jcod variants that make the member private again.
  85 
  86     static void checkExternalSuper(ExternalSuper s) throws Throwable {
  87         try {
  88             String str = s.priv_invoke_s();
  89             throw new Error("Unexpected access to ExternalSuper.priv_invoke_s");
  90         }
  91         catch (IllegalAccessError iae) {
  92             System.out.println("Got expected exception accessing ExternalSuper.priv_invoke_s:" + iae);
  93         }
  94     }
  95 
  96     static void checkExternalSub(ExternalSub s) throws Throwable {
  97         try {
  98             String str = s.priv_invoke();
  99             throw new Error("Unexpected access to ExternalSub.priv_invoke");
 100         }
 101         catch (IllegalAccessError iae) {
 102             System.out.println("Got expected exception accessing ExternalSub.priv_invoke:" + iae);
 103         }
 104     }
 105 
 106     static void verifyEquals(String actual, String expected) {
 107         if (!actual.equals(expected)) {
 108             throw new Error("Expected " + expected + " but got " + actual);
 109         }
 110         System.out.println("Check passed for " + expected);
 111     }
 112 
 113     public static void main(String[] args) throws Throwable {
 114         NestedA a = new NestedA();
 115         NestedB b = new NestedB();
 116         NestedC c = new NestedC();
 117         ExternalSub sub = new ExternalSub();
 118         ExternalSuper sup = new ExternalSuper();
 119 
 120         checkExternalSuper(sup);
 121         checkExternalSuper(a);
 122         checkExternalSuper(b);
 123         checkExternalSuper(c);
 124         checkExternalSuper(sub);
 125 
 126         checkA(a);
 127         checkA(b);
 128         checkA(c);
 129         checkA(sub);
 130 
 131         NestedA.checkA(a);
 132         NestedA.checkA(b);
 133         NestedA.checkA(c);
 134         NestedA.checkA(sub);
 135 
 136         NestedB.checkA(a);
 137         NestedB.checkA(b);
 138         NestedB.checkA(c);
 139         NestedB.checkA(sub);
 140 
 141         NestedC.checkA(a);
 142         NestedC.checkA(b);
 143         NestedC.checkA(c);
 144         NestedC.checkA(sub);
 145 
 146         checkB(b);
 147         checkB(c);
 148         checkB(sub);
 149 
 150         checkC(c);
 151         checkC(sub);
 152 
 153         checkExternalSub(sub);
 154     }
 155 }
 156 
 157 // Classes that are not part of the nest.
 158 // Being non-public allows us to declare them in this file.
 159 // The priv_invoke* member is public to allow this file to compile, but
 160 // the jcod files change it back to private.
 161 
 162 class ExternalSuper {
 163     static final String ID =  "ExternalSuper::priv_invoke_s";
 164     // Can't call this priv_invoke as subclasses make it less accessible
 165     // which is not allowed.
 166     public String priv_invoke_s() {
 167         return ID;
 168     }
 169 }
 170 
 171 
 172 class ExternalSub extends TestInvokeHierarchy.NestedC {
 173     static final String ID =  "ExternalSub::priv_invoke";
 174     public String priv_invoke() {
 175         return ID;
 176     }
 177 }