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