StaticInterfaceMethodInWayOfDefault.java revision 9783:3b50efed107a
1/* 2 * Copyright (c) 2013, 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 8009411 27 * @summary Test that a static method on an interface doesn't hide a default 28 * method with the same name and signature in a separate compilation 29 * scenario. 30 * @library /lib/testlibrary 31 * @build jdk.testlibrary.IOUtils 32 * @run main StaticInterfaceMethodInWayOfDefault 33 */ 34 35import java.io.IOException; 36import java.io.InputStream; 37import java.lang.reflect.InvocationTargetException; 38import java.lang.reflect.Method; 39import java.util.concurrent.Callable; 40 41import jdk.testlibrary.IOUtils; 42 43public class StaticInterfaceMethodInWayOfDefault { 44 public interface A_v1 { 45 } 46 47 public interface A_v2 { 48 default void m() { 49 System.err.println("A.m() called"); 50 } 51 } 52 53 public interface B extends A_v1 { 54 static void m() { 55 System.err.println("B.m() called"); 56 } 57 } 58 59 public interface C_v1 extends B { 60 default void m() { 61 System.err.println("C.m() called"); 62 } 63 } 64 65 public interface C_v2 extends B { 66 } 67 68 public static class TestTask implements Callable<String> { 69 @Override 70 public String call() { 71 try { 72 Method m = C_v1.class.getMethod("m", (Class<?>[])null); 73 return m.getDeclaringClass().getSimpleName(); 74 } catch (NoSuchMethodException e) { 75 System.err.println("Couldn't find method"); 76 return "ERROR"; 77 } 78 } 79 } 80 81 public static void main(String[] args) throws Exception { 82 int errors = 0; 83 Callable<String> v1Task = new TestTask(); 84 85 ClassLoader v2Loader = new V2ClassLoader( 86 StaticInterfaceMethodInWayOfDefault.class.getClassLoader()); 87 Callable<String> v2Task = (Callable<String>) Class.forName( 88 TestTask.class.getName(), 89 true, 90 v2Loader).newInstance(); 91 92 System.err.println("Running using _v1 classes:"); 93 String res = v1Task.call(); 94 if(!res.equals("C_v1")) { 95 System.err.println("Got wrong method, expecting C_v1, got: " + res); 96 errors++; 97 } 98 99 System.err.println("Running using _v2 classes:"); 100 res = v2Task.call(); 101 if(!res.equals("A_v1")) { 102 System.err.println("Got wrong method, expecting A_v1, got: " + res); 103 errors++; 104 } 105 106 if (errors != 0) 107 throw new RuntimeException("Errors found, check log for details"); 108 } 109 110 /** 111 * A ClassLoader implementation that loads alternative implementations of 112 * classes. If class name ends with "_v1" it locates instead a class with 113 * name ending with "_v2" and loads that class instead. 114 */ 115 static class V2ClassLoader extends ClassLoader { 116 V2ClassLoader(ClassLoader parent) { 117 super(parent); 118 } 119 120 @Override 121 protected Class<?> loadClass(String name, boolean resolve) 122 throws ClassNotFoundException { 123 if (name.indexOf('.') < 0) { // root package is our class 124 synchronized (getClassLoadingLock(name)) { 125 // First, check if the class has already been loaded 126 Class<?> c = findLoadedClass(name); 127 if (c == null) { 128 c = findClass(name); 129 } 130 if (resolve) { 131 resolveClass(c); 132 } 133 return c; 134 } 135 } 136 else { // not our class 137 return super.loadClass(name, resolve); 138 } 139 } 140 141 @Override 142 protected Class<?> findClass(String name) 143 throws ClassNotFoundException { 144 // special class name -> replace it with alternative name 145 if (name.endsWith("_v1")) { 146 String altName = name.substring(0, name.length() - 3) + "_v2"; 147 String altPath = altName.replace('.', '/').concat(".class"); 148 try (InputStream is = getResourceAsStream(altPath)) { 149 if (is != null) { 150 byte[] bytes = IOUtils.readFully(is); 151 // patch class bytes to contain original name 152 for (int i = 0; i < bytes.length - 2; i++) { 153 if (bytes[i] == '_' && 154 bytes[i + 1] == 'v' && 155 bytes[i + 2] == '2') { 156 bytes[i + 2] = '1'; 157 } 158 } 159 return defineClass(name, bytes, 0, bytes.length); 160 } 161 else { 162 throw new ClassNotFoundException(name); 163 } 164 } 165 catch (IOException e) { 166 throw new ClassNotFoundException(name, e); 167 } 168 } 169 else { // not special class name -> just load the class 170 String path = name.replace('.', '/').concat(".class"); 171 try (InputStream is = getResourceAsStream(path)) { 172 if (is != null) { 173 byte[] bytes = IOUtils.readFully(is); 174 return defineClass(name, bytes, 0, bytes.length); 175 } 176 else { 177 throw new ClassNotFoundException(name); 178 } 179 } 180 catch (IOException e) { 181 throw new ClassNotFoundException(name, e); 182 } 183 } 184 } 185 } 186} 187