jdk/test/com/sun/jdi/InterfaceMethodsTest.java
changeset 24125 b85eeaae56c7
child 24973 8c4bc3fa4c4e
equal deleted inserted replaced
24124:5f5f7f7a4328 24125:b85eeaae56c7
       
     1 /*
       
     2  * Copyright (c) 2014, 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 8031195
       
    27  *  @summary  JDI: Add support for static and default methods in interfaces
       
    28  *
       
    29  *  @run build TestScaffold VMConnection TargetListener TargetAdapter
       
    30  *  @run build InterfaceMethodsTest
       
    31  *  @run main InterfaceMethodsTest
       
    32  */
       
    33 import com.sun.jdi.*;
       
    34 import com.sun.jdi.event.*;
       
    35 import java.util.Collections;
       
    36 
       
    37 public class InterfaceMethodsTest extends TestScaffold {
       
    38     private static final int RESULT_A = 1;
       
    39     private static final int RESULT_B = 1;
       
    40     private static final int RESULT_TARGET = 1;
       
    41     static interface InterfaceA {
       
    42         static int staticMethodA() {
       
    43             System.out.println("-InterfaceA: static interface method A-");
       
    44             return RESULT_A;
       
    45         }
       
    46         static int staticMethodB() {
       
    47             System.out.println("-InterfaceA: static interface method B-");
       
    48             return RESULT_A;
       
    49         }
       
    50         default int defaultMethodA() {
       
    51             System.out.println("-InterfaceA: default interface method A-");
       
    52             return RESULT_A;
       
    53         }
       
    54         default int defaultMethodB() {
       
    55             System.out.println("-InterfaceA: default interface method B-");
       
    56             return RESULT_A;
       
    57         }
       
    58         default int defaultMethodC() {
       
    59             System.out.println("-InterfaceA: default interface method C-");
       
    60             return RESULT_A;
       
    61         }
       
    62 
       
    63         int implementedMethod();
       
    64     }
       
    65 
       
    66     static interface InterfaceB extends InterfaceA {
       
    67         @Override
       
    68         default int defaultMethodC() {
       
    69             System.out.println("-InterfaceB: overridden default interface method C-");
       
    70             return RESULT_B;
       
    71         }
       
    72         default int defaultMethodD() {
       
    73             System.out.println("-InterfaceB: default interface method D-");
       
    74             return RESULT_B;
       
    75         }
       
    76 
       
    77         static int staticMethodB() {
       
    78             System.out.println("-InterfaceB: overridden static interface method B-");
       
    79             return RESULT_B;
       
    80         }
       
    81 
       
    82         static int staticMethodC() {
       
    83             System.out.println("-InterfaceB: static interface method C-");
       
    84             return RESULT_B;
       
    85         }
       
    86     }
       
    87 
       
    88     final static class TargetClass implements InterfaceB {
       
    89         public int classMethod() {
       
    90             System.out.println("-TargetClass: class only method-");
       
    91             return RESULT_TARGET;
       
    92         }
       
    93 
       
    94         @Override
       
    95         public int implementedMethod() {
       
    96             System.out.println("-TargetClass: implemented non-default interface method-");
       
    97             return RESULT_TARGET;
       
    98         }
       
    99 
       
   100         @Override
       
   101         public int defaultMethodB() {
       
   102             System.out.println("-TargetClass: overridden default interface method D");
       
   103 
       
   104             return RESULT_TARGET;
       
   105         }
       
   106 
       
   107         public static void main(String[] args) {
       
   108             TargetClass tc = new TargetClass();
       
   109             tc.doTests(tc);
       
   110         }
       
   111 
       
   112         private void doTests(TargetClass ref) {
       
   113             // break
       
   114         }
       
   115     }
       
   116 
       
   117     public InterfaceMethodsTest(String[] args) {
       
   118         super(args);
       
   119     }
       
   120 
       
   121     public static void main(String[] args) throws Exception {
       
   122         new InterfaceMethodsTest(args).startTests();
       
   123     }
       
   124 
       
   125     private static final String TEST_CLASS_NAME = InterfaceMethodsTest.class.getName().replace('.', '/');
       
   126     private static final String TARGET_CLASS_NAME = TargetClass.class.getName().replace('.', '/');
       
   127     private static final String INTERFACEA_NAME = InterfaceA.class.getName().replace('.', '/');
       
   128     private static final String INTERFACEB_NAME = InterfaceB.class.getName().replace('.', '/');
       
   129 
       
   130     protected void runTests() throws Exception {
       
   131         /*
       
   132          * Get to the top of main()
       
   133          * to determine targetClass and mainThread
       
   134          */
       
   135         BreakpointEvent bpe = startToMain(TARGET_CLASS_NAME);
       
   136 
       
   137         bpe = resumeTo(TARGET_CLASS_NAME, "doTests", "(L" + TARGET_CLASS_NAME +";)V");
       
   138 
       
   139         mainThread = bpe.thread();
       
   140 
       
   141         StackFrame frame = mainThread.frame(0);
       
   142         ObjectReference thisObject = frame.thisObject();
       
   143         ObjectReference ref = (ObjectReference)frame.getArgumentValues().get(0);
       
   144 
       
   145         ReferenceType targetClass = bpe.location().declaringType();
       
   146         testImplementationClass(targetClass, thisObject);
       
   147 
       
   148         testInterfaceA(ref);
       
   149 
       
   150         testInterfaceB(ref);
       
   151 
       
   152         /*
       
   153          * resume the target listening for events
       
   154          */
       
   155         listenUntilVMDisconnect();
       
   156 
       
   157         /*
       
   158          * deal with results of test
       
   159          * if anything has called failure("foo") testFailed will be true
       
   160          */
       
   161         if (!testFailed) {
       
   162             println("InterfaceMethodsTest: passed");
       
   163         } else {
       
   164             throw new Exception("InterfaceMethodsTest: failed");
       
   165         }
       
   166     }
       
   167 
       
   168     private void testInterfaceA(ObjectReference ref) {
       
   169         // Test non-virtual calls on InterfaceA
       
   170 
       
   171         ReferenceType ifaceClass = (ReferenceType)vm().classesByName(INTERFACEA_NAME).get(0);
       
   172         /* Default method calls */
       
   173 
       
   174         // invoke the InterfaceA's "defaultMethodA"
       
   175         testInvokePos(ifaceClass, ref, "defaultMethodA", "()I", vm().mirrorOf(RESULT_A));
       
   176 
       
   177         // invoke the InterfaceA's "defaultMethodB"
       
   178         testInvokePos(ifaceClass, ref, "defaultMethodB", "()I", vm().mirrorOf(RESULT_A));
       
   179 
       
   180         // invoke the InterfaceA's "defaultMethodC"
       
   181         testInvokePos(ifaceClass, ref, "defaultMethodC", "()I", vm().mirrorOf(RESULT_A));
       
   182 
       
   183         // "defaultMethodD" from InterfaceB is not accessible from here
       
   184         testInvokeNeg(ifaceClass, ref, "defaultMethodD", "()I", vm().mirrorOf(RESULT_B),
       
   185                 "Attempted to invoke non-existing method");
       
   186 
       
   187         // trying to invoke the asbtract method "implementedMethod"
       
   188         testInvokeNeg(ifaceClass, ref, "implementedMethod", "()I", vm().mirrorOf(TARGET_CLASS_NAME),
       
   189                 "Invocation of non-default methods is not supported");
       
   190 
       
   191 
       
   192         /* Static method calls */
       
   193 
       
   194         // invoke interface static method A
       
   195         testInvokePos(ifaceClass, null, "staticMethodA", "()I", vm().mirrorOf(RESULT_A));
       
   196 
       
   197         // try to invoke static method A on the instance
       
   198         testInvokePos(ifaceClass, ref, "staticMethodA", "()I", vm().mirrorOf(RESULT_A));
       
   199 
       
   200         // invoke interface static method B
       
   201         testInvokePos(ifaceClass, null, "staticMethodB", "()I", vm().mirrorOf(RESULT_A));
       
   202 
       
   203         // try to invoke static method B on the instance
       
   204         testInvokePos(ifaceClass, ref, "staticMethodB", "()I", vm().mirrorOf(RESULT_A));
       
   205     }
       
   206 
       
   207     private void testInterfaceB(ObjectReference ref) {
       
   208         // Test non-virtual calls on InterfaceB
       
   209         ReferenceType ifaceClass = (ReferenceType)vm().classesByName(INTERFACEB_NAME).get(0);
       
   210 
       
   211         /* Default method calls */
       
   212 
       
   213         // invoke the inherited "defaultMethodA"
       
   214         testInvokePos(ifaceClass, ref, "defaultMethodA", "()I", vm().mirrorOf(RESULT_A));
       
   215 
       
   216         // invoke the inherited "defaultMethodB"
       
   217         testInvokePos(ifaceClass, ref, "defaultMethodB", "()I", vm().mirrorOf(RESULT_A));
       
   218 
       
   219         // invoke the inherited and overridden "defaultMethodC"
       
   220         testInvokePos(ifaceClass, ref, "defaultMethodC", "()I", vm().mirrorOf(RESULT_B));
       
   221 
       
   222         // invoke InterfaceB only "defaultMethodD"
       
   223         testInvokePos(ifaceClass, ref, "defaultMethodD", "()I", vm().mirrorOf(RESULT_B));
       
   224 
       
   225         // "implementedMethod" is not present in InterfaceB
       
   226         testInvokeNeg(ifaceClass, ref, "implementedMethod", "()I", vm().mirrorOf(RESULT_TARGET),
       
   227                 "Invocation of non-default methods is not supported");
       
   228 
       
   229 
       
   230         /* Static method calls*/
       
   231 
       
   232         // "staticMethodA" must not be inherited by InterfaceB
       
   233         testInvokeNeg(ifaceClass, null, "staticMethodA", "()I", vm().mirrorOf(RESULT_A),
       
   234                 "Static interface methods are not inheritable");
       
   235 
       
   236         // however it is possible to call "staticMethodA" on the actual instance
       
   237         testInvokeNeg(ifaceClass, ref, "staticMethodA", "()I", vm().mirrorOf(RESULT_A),
       
   238                 "Static interface methods are not inheritable");
       
   239 
       
   240         // "staticMethodB" is overridden in InterfaceB
       
   241         testInvokePos(ifaceClass, null, "staticMethodB", "()I", vm().mirrorOf(RESULT_B));
       
   242 
       
   243         // the instance invokes the overriden form of "staticMethodB" from InterfaceB
       
   244         testInvokePos(ifaceClass, ref, "staticMethodB", "()I", vm().mirrorOf(RESULT_B));
       
   245 
       
   246         // "staticMethodC" is present only in InterfaceB
       
   247         testInvokePos(ifaceClass, null, "staticMethodC", "()I", vm().mirrorOf(RESULT_B));
       
   248 
       
   249         // "staticMethodC" should be reachable from the instance too
       
   250         testInvokePos(ifaceClass, ref, "staticMethodC", "()I", vm().mirrorOf(RESULT_B));
       
   251     }
       
   252 
       
   253     private void testImplementationClass(ReferenceType targetClass, ObjectReference thisObject) {
       
   254         // Test invocations on the implementation object
       
   255 
       
   256         /* Default method calls */
       
   257 
       
   258         // "defaultMethodA" is accessible and not overridden
       
   259         testInvokePos(targetClass, thisObject, "defaultMethodA", "()I", vm().mirrorOf(RESULT_TARGET));
       
   260 
       
   261         // "defaultMethodB" is accessible and overridden in TargetClass
       
   262         testInvokePos(targetClass, thisObject, "defaultMethodB", "()I", vm().mirrorOf(RESULT_TARGET));
       
   263 
       
   264         // "defaultMethodC" is accessible and overridden in InterfaceB
       
   265         testInvokePos(targetClass, thisObject, "defaultMethodC", "()I", vm().mirrorOf(RESULT_TARGET));
       
   266 
       
   267         // "defaultMethodD" is accessible
       
   268         testInvokePos(targetClass, thisObject, "defaultMethodD", "()I", vm().mirrorOf(RESULT_TARGET));
       
   269 
       
   270 
       
   271         /* Non-default instance method calls */
       
   272 
       
   273         // "classMethod" declared in TargetClass is accessible
       
   274         testInvokePos(targetClass, thisObject, "classMethod", "()I", vm().mirrorOf(RESULT_TARGET));
       
   275 
       
   276         // the abstract "implementedMethod" has been implemented in TargetClass
       
   277         testInvokePos(targetClass, thisObject, "implementedMethod", "()I", vm().mirrorOf(RESULT_TARGET));
       
   278 
       
   279 
       
   280         /* Static method calls */
       
   281 
       
   282         // All the static methods declared by the interfaces are not reachable from the instance of the implementor class
       
   283         testInvokeNeg(targetClass, thisObject, "staticMethodA", "()I", vm().mirrorOf(RESULT_A),
       
   284                 "Static interface methods are not inheritable");
       
   285 
       
   286         testInvokeNeg(targetClass, thisObject, "staticMethodB", "()I", vm().mirrorOf(RESULT_B),
       
   287                 "Static interface methods are not inheritable");
       
   288 
       
   289         testInvokeNeg(targetClass, thisObject, "staticMethodC", "()I", vm().mirrorOf(RESULT_B),
       
   290                 "Static interface methods are not inheritable");
       
   291 
       
   292         // All the static methods declared by the interfaces are not reachable through the implementor class
       
   293         testInvokeNeg(targetClass, null, "staticMethodA", "()I", vm().mirrorOf(RESULT_A),
       
   294                 "Static interface methods are not inheritable");
       
   295 
       
   296         testInvokeNeg(targetClass, null, "staticMethodB", "()I", vm().mirrorOf(RESULT_B),
       
   297                 "Static interface methods are not inheritable");
       
   298 
       
   299         testInvokeNeg(targetClass, null, "staticMethodC", "()I", vm().mirrorOf(RESULT_B),
       
   300                 "Static interface methods are not inheritable");
       
   301     }
       
   302 
       
   303     private void testInvokePos(ReferenceType targetClass, ObjectReference ref, String methodName,
       
   304                                String methodSig, Value value) {
       
   305         logInvocation(ref, methodName, methodSig, targetClass);
       
   306         try {
       
   307             invoke(targetClass, ref, methodName, methodSig, value);
       
   308             System.err.println("--- PASSED");
       
   309         } catch (Exception e) {
       
   310             System.err.println("--- FAILED");
       
   311             failure("FAILED: Invocation failed with error message " + e.getLocalizedMessage());
       
   312         }
       
   313     }
       
   314 
       
   315     private void testInvokeNeg(ReferenceType targetClass, ObjectReference ref, String methodName,
       
   316                                String methodSig, Value value, String msg) {
       
   317         logInvocation(ref, methodName, methodSig, targetClass);
       
   318         try {
       
   319             invoke(targetClass, ref, methodName, methodSig, value);
       
   320             System.err.println("--- FAILED");
       
   321             failure("FAILED: " + msg);
       
   322         } catch (Exception e) {
       
   323             System.err.println("--- PASSED");
       
   324 
       
   325         }
       
   326     }
       
   327 
       
   328     private void invoke(ReferenceType targetClass, ObjectReference ref, String methodName,
       
   329                         String methodSig, Value value)
       
   330     throws Exception {
       
   331         Method method = getMethod(targetClass, methodName, methodSig);
       
   332         if (method == null) {
       
   333             throw new Exception("Can't find method: " + methodName  + " for class = " + targetClass);
       
   334         }
       
   335 
       
   336         println("Invoking " + (method.isAbstract() ? "abstract " : " ") + "method: " + method);
       
   337 
       
   338         Value returnValue = null;
       
   339         if (ref != null) {
       
   340             returnValue = invokeInstance(ref, method);
       
   341         } else {
       
   342             returnValue = invokeStatic(targetClass, method);
       
   343         }
       
   344 
       
   345         println("        return val = " + returnValue);
       
   346         // It has to be the same value as what we passed in!
       
   347         if (returnValue.equals(value)) {
       
   348             println("         " + method.name() + " return value matches: "
       
   349                     + value);
       
   350         } else {
       
   351             if (value != null) {
       
   352                 throw new Exception(method.name() + " returned: " + returnValue +
       
   353                                     " expected: " + value );
       
   354             } else {
       
   355                 println("         " + method.name() + " return value : " + returnValue);
       
   356             }
       
   357 
       
   358         }
       
   359     }
       
   360 
       
   361     private Value invokeInstance(ObjectReference ref, Method method) throws Exception {
       
   362         return ref.invokeMethod(mainThread, method, Collections.emptyList(), ObjectReference.INVOKE_NONVIRTUAL);
       
   363     }
       
   364 
       
   365     private Value invokeStatic(ReferenceType refType, Method method) throws Exception {
       
   366         if (refType instanceof ClassType) {
       
   367             return ((ClassType)refType).invokeMethod(mainThread, method, Collections.emptyList(), ObjectReference.INVOKE_NONVIRTUAL);
       
   368         } else {
       
   369             return ((InterfaceType)refType).invokeMethod(mainThread, method, Collections.emptyList(), ObjectReference.INVOKE_NONVIRTUAL);
       
   370         }
       
   371     }
       
   372 
       
   373     private Method getMethod(ReferenceType rt, String name, String signature) {
       
   374         if (rt == null) return null;
       
   375         Method m = findMethod(rt, name, signature);
       
   376         if (m == null) {
       
   377             if (rt instanceof ClassType) {
       
   378                 for (Object ifc : ((ClassType)rt).interfaces()) {
       
   379                     m = getMethod((ReferenceType)ifc, name, signature);
       
   380                     if (m != null) {
       
   381                         break;
       
   382                     }
       
   383                 }
       
   384                 if (m == null) {
       
   385                     m = getMethod(((ClassType)rt).superclass(), name, signature);
       
   386                 } else {
       
   387                     if (m.isStatic()) {
       
   388                         // interface static methods are not inherited
       
   389                         m = null;
       
   390                     }
       
   391                 }
       
   392             } else if (rt instanceof InterfaceType) {
       
   393                 for(Object ifc : ((InterfaceType)rt).superinterfaces()) {
       
   394                     m = getMethod((ReferenceType)ifc, name, signature);
       
   395                     if (m != null) {
       
   396                         if (m.isStatic()) {
       
   397                             // interface static methods are not inherited
       
   398                             m = null;
       
   399                         }
       
   400                         break;
       
   401                     }
       
   402                 }
       
   403             }
       
   404         }
       
   405 
       
   406         return m;
       
   407     }
       
   408 
       
   409     private void logInvocation(ObjectReference ref, String methodName, String methodSig, ReferenceType targetClass) {
       
   410         if (ref != null) {
       
   411             System.err.println("Invoking: " + ref.referenceType().name() + "." +
       
   412                     methodName + methodSig + " with target of type " +
       
   413                     targetClass.name());
       
   414         } else {
       
   415             System.err.println("Invoking static : " + targetClass.name() + "." +
       
   416                     methodName + methodSig);
       
   417         }
       
   418     }
       
   419 }
       
   420 
       
   421 
       
   422