1 /*
   2  * Copyright (c) 2009, 2019, 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 package invokeinterface;
  26 
  27 import java.lang.reflect.Method;
  28 import java.lang.reflect.Modifier;
  29 
  30 public class Checker extends shared.Checker {
  31     private Class interfaceClass;
  32 
  33     public Checker(Class interfaceClass, Class dynamicTargetClass) {
  34         super(interfaceClass, dynamicTargetClass);
  35 
  36         if (staticTargetClass.isInterface()) {
  37             this.interfaceClass = staticTargetClass;
  38         } else {
  39             throw new RuntimeException("Static target class should be an interface.");
  40         }
  41     }
  42 
  43     public String check (Class callerClass) {
  44         // Check access rights to interface for caller
  45         if (!checkAccess(interfaceClass, callerClass)) {
  46             return "java.lang.IllegalAccessError";
  47         }
  48 
  49         // NSME is thrown when interface doesn't declare the method
  50         if (getDeclaredMethod(interfaceClass) == null) {
  51             return "java.lang.NoSuchMethodError";
  52         }
  53 
  54         // 9.1.5 Access to Interface Member Names
  55         // "All interface members are implicitly public. They are
  56         // accessible outside the package where the interface is
  57         // declared if the interface is also declared public or
  58         // protected, in accordance with the rules of 6.6."
  59 
  60         // Search for method declaration in the hierarchy
  61         Class klass = dynamicTargetClass;
  62 
  63         while (klass != Object.class) {
  64             Method method = getDeclaredMethod(klass);
  65 
  66             if (method != null) {
  67                 int modifiers = method.getModifiers();
  68 
  69                 // Check whether obtained method is public and isn't abstract
  70                 if ( Modifier.isPublic(modifiers))
  71                 {
  72                     if (Modifier.isAbstract(modifiers)) {
  73                         return "java.lang.AbstractMethodError";
  74                     } else {
  75                         return String.format("%s.%s"
  76                             , method.getDeclaringClass().getSimpleName()
  77                             , methodName
  78                             );
  79                     }
  80                 } else {
  81                     // IAE is thrown when located method isn't PUBLIC
  82                     // or private.  Private methods are skipped when
  83                     // looking for an interface method.
  84                     if (!Modifier.isPrivate(modifiers)) {
  85                         return "java.lang.IllegalAccessError";
  86                     }
  87                 }
  88             }
  89 
  90             klass = klass.getSuperclass();
  91         }
  92 
  93         // No method declaration is found
  94         return "java.lang.AbstractMethodError";
  95     }
  96 }