1 /* 2 * Copyright (c) 2018, 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 import java.lang.invoke.MethodHandle; 25 import java.lang.invoke.MethodHandleInfo; 26 import java.lang.invoke.MethodHandles; 27 import java.lang.invoke.MethodType; 28 import java.lang.invoke.WrongMethodTypeException; 29 import java.lang.constant.ClassDesc; 30 import java.lang.constant.ConstantDescs; 31 import java.lang.constant.DirectMethodHandleDesc; 32 import java.lang.constant.MethodHandleDesc; 33 import java.lang.reflect.Field; 34 import java.lang.reflect.Modifier; 35 import java.lang.constant.MethodTypeDesc; 36 import java.util.ArrayList; 37 import java.util.List; 38 import java.util.function.Supplier; 39 40 import org.testng.annotations.Test; 41 42 import static java.lang.constant.ConstantDescs.CD_Void; 43 import static java.lang.constant.ConstantDescs.CD_boolean; 44 import static java.lang.constant.DirectMethodHandleDesc.*; 45 import static java.lang.constant.DirectMethodHandleDesc.Kind.GETTER; 46 import static java.lang.constant.DirectMethodHandleDesc.Kind.SETTER; 47 import static java.lang.constant.DirectMethodHandleDesc.Kind.STATIC_GETTER; 48 import static java.lang.constant.DirectMethodHandleDesc.Kind.STATIC_SETTER; 49 import static java.lang.constant.DirectMethodHandleDesc.Kind.VIRTUAL; 50 import static java.lang.constant.ConstantDescs.CD_Integer; 51 import static java.lang.constant.ConstantDescs.CD_List; 52 import static java.lang.constant.ConstantDescs.CD_Object; 53 import static java.lang.constant.ConstantDescs.CD_String; 54 import static java.lang.constant.ConstantDescs.CD_int; 55 import static java.lang.constant.ConstantDescs.CD_void; 56 import static org.testng.Assert.assertEquals; 57 import static org.testng.Assert.assertNotSame; 58 import static org.testng.Assert.assertSame; 59 import static org.testng.Assert.assertTrue; 60 import static org.testng.Assert.fail; 61 62 /** 63 * @test 64 * @compile MethodHandleDescTest.java 65 * @run testng MethodHandleDescTest 66 * @summary unit tests for java.lang.constant.MethodHandleDesc 67 */ 68 @Test 69 public class MethodHandleDescTest extends SymbolicDescTest { 70 private static ClassDesc helperHolderClass = ClassDesc.of("TestHelpers"); 71 private static ClassDesc testClass = helperHolderClass.nested("TestClass"); 72 private static ClassDesc testInterface = helperHolderClass.nested("TestInterface"); 73 private static ClassDesc testSuperclass = helperHolderClass.nested("TestSuperclass"); 74 75 assertMHEquals(MethodHandle a, MethodHandle b)76 private static void assertMHEquals(MethodHandle a, MethodHandle b) { 77 MethodHandleInfo ia = LOOKUP.revealDirect(a); 78 MethodHandleInfo ib = LOOKUP.revealDirect(b); 79 assertEquals(ia.getDeclaringClass(), ib.getDeclaringClass()); 80 assertEquals(ia.getName(), ib.getName()); 81 assertEquals(ia.getMethodType(), ib.getMethodType()); 82 assertEquals(ia.getReferenceKind(), ib.getReferenceKind()); 83 } 84 testMethodHandleDesc(MethodHandleDesc r)85 private void testMethodHandleDesc(MethodHandleDesc r) throws ReflectiveOperationException { 86 if (r instanceof DirectMethodHandleDesc) { 87 testSymbolicDesc(r); 88 89 DirectMethodHandleDesc rr = (DirectMethodHandleDesc) r; 90 assertEquals(r, MethodHandleDesc.of(rr.kind(), rr.owner(), rr.methodName(), rr.lookupDescriptor())); 91 assertEquals(r.invocationType().resolveConstantDesc(LOOKUP), ((MethodHandle) r.resolveConstantDesc(LOOKUP)).type()); 92 } 93 else { 94 testSymbolicDescForwardOnly(r); 95 } 96 } 97 lookupDescriptor(DirectMethodHandleDesc rr)98 private String lookupDescriptor(DirectMethodHandleDesc rr) { 99 switch (rr.kind()) { 100 case VIRTUAL: 101 case SPECIAL: 102 case INTERFACE_VIRTUAL: 103 case INTERFACE_SPECIAL: 104 return rr.invocationType().dropParameterTypes(0, 1).descriptorString(); 105 case CONSTRUCTOR: 106 return rr.invocationType().changeReturnType(CD_void).descriptorString(); 107 default: 108 return rr.invocationType().descriptorString(); 109 } 110 } 111 testMethodHandleDesc(MethodHandleDesc r, MethodHandle mh)112 private void testMethodHandleDesc(MethodHandleDesc r, MethodHandle mh) throws ReflectiveOperationException { 113 testMethodHandleDesc(r); 114 115 assertMHEquals(((MethodHandle) r.resolveConstantDesc(LOOKUP)), mh); 116 assertEquals(mh.describeConstable().orElseThrow(), r); 117 118 // compare extractable properties: refKind, owner, name, type 119 MethodHandleInfo mhi = LOOKUP.revealDirect(mh); 120 DirectMethodHandleDesc rr = (DirectMethodHandleDesc) r; 121 assertEquals(mhi.getDeclaringClass().descriptorString(), rr.owner().descriptorString()); 122 assertEquals(mhi.getName(), rr.methodName()); 123 assertEquals(mhi.getReferenceKind(), rr.kind().refKind); 124 MethodType type = mhi.getMethodType(); 125 assertEquals(type.toMethodDescriptorString(), lookupDescriptor(rr)); 126 } 127 testSimpleMHs()128 public void testSimpleMHs() throws ReflectiveOperationException { 129 MethodHandle MH_String_isEmpty = LOOKUP.findVirtual(String.class, "isEmpty", MethodType.fromMethodDescriptorString("()Z", null)); 130 testMethodHandleDesc(MethodHandleDesc.of(Kind.VIRTUAL, CD_String, "isEmpty", "()Z"), MH_String_isEmpty); 131 testMethodHandleDesc(MethodHandleDesc.ofMethod(Kind.VIRTUAL, CD_String, "isEmpty", MethodTypeDesc.of(CD_boolean)), MH_String_isEmpty); 132 133 MethodHandle MH_List_isEmpty = LOOKUP.findVirtual(List.class, "isEmpty", MethodType.fromMethodDescriptorString("()Z", null)); 134 testMethodHandleDesc(MethodHandleDesc.of(Kind.INTERFACE_VIRTUAL, CD_List, "isEmpty", "()Z"), MH_List_isEmpty); 135 testMethodHandleDesc(MethodHandleDesc.ofMethod(Kind.INTERFACE_VIRTUAL, CD_List, "isEmpty", MethodTypeDesc.of(CD_boolean)), MH_List_isEmpty); 136 137 MethodHandle MH_String_format = LOOKUP.findStatic(String.class, "format", MethodType.methodType(String.class, String.class, Object[].class)); 138 testMethodHandleDesc(MethodHandleDesc.of(Kind.STATIC, CD_String, "format", MethodType.methodType(String.class, String.class, Object[].class).descriptorString()), 139 MH_String_format); 140 testMethodHandleDesc(MethodHandleDesc.ofMethod(Kind.STATIC, CD_String, "format", MethodTypeDesc.of(CD_String, CD_String, CD_Object.arrayType())), 141 MH_String_format); 142 143 MethodHandle MH_ArrayList_new = LOOKUP.findConstructor(ArrayList.class, MethodType.methodType(void.class)); 144 testMethodHandleDesc(MethodHandleDesc.ofMethod(Kind.CONSTRUCTOR, ClassDesc.of("java.util.ArrayList"), "<init>", MethodTypeDesc.of(CD_void)), 145 MH_ArrayList_new); 146 testMethodHandleDesc(MethodHandleDesc.ofConstructor(ClassDesc.of("java.util.ArrayList")), MH_ArrayList_new); 147 148 // bad constructor non void return type 149 try { 150 MethodHandleDesc.of(Kind.CONSTRUCTOR, ClassDesc.of("java.util.ArrayList"), "<init>", "()I"); 151 fail("should have failed: non void return type for constructor"); 152 } catch (IllegalArgumentException ex) { 153 // good 154 } 155 156 // null list of parameters 157 try { 158 MethodHandleDesc.ofConstructor(ClassDesc.of("java.util.ArrayList", null)); 159 fail("should have failed: null list of parameters"); 160 } catch (NullPointerException ex) { 161 // good 162 } 163 164 // null elements in list of parameters 165 try { 166 ClassDesc[] paramList = new ClassDesc[1]; 167 paramList[0] = null; 168 MethodHandleDesc.ofConstructor(ClassDesc.of("java.util.ArrayList"), paramList); 169 fail("should have failed: null content in list of parameters"); 170 } catch (NullPointerException ex) { 171 // good 172 } 173 } 174 testAsType()175 public void testAsType() throws Throwable { 176 MethodHandleDesc mhr = MethodHandleDesc.ofMethod(Kind.STATIC, ClassDesc.of("java.lang.Integer"), "valueOf", 177 MethodTypeDesc.of(CD_Integer, CD_int)); 178 MethodHandleDesc takesInteger = mhr.asType(MethodTypeDesc.of(CD_Integer, CD_Integer)); 179 testMethodHandleDesc(takesInteger); 180 MethodHandle mh1 = (MethodHandle) takesInteger.resolveConstantDesc(LOOKUP); 181 assertEquals((Integer) 3, (Integer) mh1.invokeExact((Integer) 3)); 182 assertEquals(takesInteger.toString(), "MethodHandleDesc[STATIC/Integer::valueOf(int)Integer].asType(Integer)Integer"); 183 184 try { 185 Integer i = (Integer) mh1.invokeExact(3); 186 fail("Expected WMTE"); 187 } 188 catch (WrongMethodTypeException ignored) { } 189 190 MethodHandleDesc takesInt = takesInteger.asType(MethodTypeDesc.of(CD_Integer, CD_int)); 191 testMethodHandleDesc(takesInt); 192 MethodHandle mh2 = (MethodHandle) takesInt.resolveConstantDesc(LOOKUP); 193 assertEquals((Integer) 3, (Integer) mh2.invokeExact(3)); 194 195 try { 196 Integer i = (Integer) mh2.invokeExact((Integer) 3); 197 fail("Expected WMTE"); 198 } 199 catch (WrongMethodTypeException ignored) { } 200 201 // Short circuit optimization 202 MethodHandleDesc same = mhr.asType(mhr.invocationType()); 203 assertSame(mhr, same); 204 205 try { 206 mhr.asType(null); 207 fail("Expected NPE"); 208 } catch (NullPointerException ex) { 209 // good 210 } 211 212 // @@@ Test varargs adaptation 213 // @@@ Test bad adaptations and assert runtime error on resolution 214 // @@@ Test intrinsification of adapted MH 215 } 216 testMethodHandleDesc()217 public void testMethodHandleDesc() throws Throwable { 218 MethodHandleDesc ctorDesc = MethodHandleDesc.of(Kind.CONSTRUCTOR, testClass, "<ignored!>", "()V"); 219 MethodHandleDesc staticMethodDesc = MethodHandleDesc.of(Kind.STATIC, testClass, "sm", "(I)I"); 220 MethodHandleDesc staticIMethodDesc = MethodHandleDesc.of(Kind.INTERFACE_STATIC, testInterface, "sm", "(I)I"); 221 MethodHandleDesc instanceMethodDesc = MethodHandleDesc.of(Kind.VIRTUAL, testClass, "m", "(I)I"); 222 MethodHandleDesc instanceIMethodDesc = MethodHandleDesc.of(Kind.INTERFACE_VIRTUAL, testInterface, "m", "(I)I"); 223 MethodHandleDesc superMethodDesc = MethodHandleDesc.of(Kind.SPECIAL, testSuperclass, "m", "(I)I"); 224 MethodHandleDesc superIMethodDesc = MethodHandleDesc.of(Kind.INTERFACE_SPECIAL, testInterface, "m", "(I)I"); 225 MethodHandleDesc privateMethodDesc = MethodHandleDesc.of(Kind.SPECIAL, testClass, "pm", "(I)I"); 226 MethodHandleDesc privateIMethodDesc = MethodHandleDesc.of(Kind.INTERFACE_SPECIAL, testInterface, "pm", "(I)I"); 227 MethodHandleDesc privateStaticMethodDesc = MethodHandleDesc.of(Kind.STATIC, testClass, "psm", "(I)I"); 228 MethodHandleDesc privateStaticIMethodDesc = MethodHandleDesc.of(Kind.INTERFACE_STATIC, testInterface, "psm", "(I)I"); 229 230 assertEquals(ctorDesc.invocationType(), MethodTypeDesc.of(testClass)); 231 assertEquals(((DirectMethodHandleDesc) ctorDesc).lookupDescriptor(), "()V"); 232 233 assertEquals(staticMethodDesc.invocationType().descriptorString(), "(I)I"); 234 assertEquals(((DirectMethodHandleDesc) staticMethodDesc).lookupDescriptor(), "(I)I"); 235 236 assertEquals(instanceMethodDesc.invocationType().descriptorString(), "(" + testClass.descriptorString() + "I)I"); 237 assertEquals(((DirectMethodHandleDesc) instanceMethodDesc).lookupDescriptor(), "(I)I"); 238 239 for (MethodHandleDesc r : List.of(ctorDesc, staticMethodDesc, staticIMethodDesc, instanceMethodDesc, instanceIMethodDesc)) 240 testMethodHandleDesc(r); 241 242 TestHelpers.TestClass instance = (TestHelpers.TestClass) ((MethodHandle)ctorDesc.resolveConstantDesc(LOOKUP)).invokeExact(); 243 TestHelpers.TestClass instance2 = (TestHelpers.TestClass) ((MethodHandle)ctorDesc.resolveConstantDesc(TestHelpers.TestClass.LOOKUP)).invokeExact(); 244 TestHelpers.TestInterface instanceI = instance; 245 246 assertNotSame(instance, instance2); 247 248 assertEquals(5, (int) ((MethodHandle)staticMethodDesc.resolveConstantDesc(LOOKUP)).invokeExact(5)); 249 assertEquals(5, (int) ((MethodHandle)staticMethodDesc.resolveConstantDesc(TestHelpers.TestClass.LOOKUP)).invokeExact(5)); 250 assertEquals(0, (int) ((MethodHandle)staticIMethodDesc.resolveConstantDesc(LOOKUP)).invokeExact(5)); 251 assertEquals(0, (int) ((MethodHandle)staticIMethodDesc.resolveConstantDesc(TestHelpers.TestClass.LOOKUP)).invokeExact(5)); 252 253 assertEquals(5, (int) ((MethodHandle)instanceMethodDesc.resolveConstantDesc(LOOKUP)).invokeExact(instance, 5)); 254 assertEquals(5, (int) ((MethodHandle)instanceMethodDesc.resolveConstantDesc(TestHelpers.TestClass.LOOKUP)).invokeExact(instance, 5)); 255 assertEquals(5, (int) ((MethodHandle)instanceIMethodDesc.resolveConstantDesc(LOOKUP)).invokeExact(instanceI, 5)); 256 assertEquals(5, (int) ((MethodHandle)instanceIMethodDesc.resolveConstantDesc(TestHelpers.TestClass.LOOKUP)).invokeExact(instanceI, 5)); 257 258 try { superMethodDesc.resolveConstantDesc(LOOKUP); fail(); } 259 catch (IllegalAccessException e) { /* expected */ } 260 assertEquals(-1, (int) ((MethodHandle)superMethodDesc.resolveConstantDesc(TestHelpers.TestClass.LOOKUP)).invokeExact(instance, 5)); 261 262 try { superIMethodDesc.resolveConstantDesc(LOOKUP); fail(); } 263 catch (IllegalAccessException e) { /* expected */ } 264 assertEquals(0, (int) ((MethodHandle)superIMethodDesc.resolveConstantDesc(TestHelpers.TestClass.LOOKUP)).invokeExact(instance, 5)); 265 266 try { privateMethodDesc.resolveConstantDesc(LOOKUP); fail(); } 267 catch (IllegalAccessException e) { /* expected */ } 268 assertEquals(5, (int) ((MethodHandle)privateMethodDesc.resolveConstantDesc(TestHelpers.TestClass.LOOKUP)).invokeExact(instance, 5)); 269 270 try { privateIMethodDesc.resolveConstantDesc(LOOKUP); fail(); } 271 catch (IllegalAccessException e) { /* expected */ } 272 assertEquals(0, (int) ((MethodHandle)privateIMethodDesc.resolveConstantDesc(TestHelpers.TestInterface.LOOKUP)).invokeExact(instanceI, 5)); 273 assertEquals(0, (int) ((MethodHandle)privateIMethodDesc.resolveConstantDesc(TestHelpers.TestClass.LOOKUP)).invoke(instanceI, 5)); 274 275 try { privateStaticMethodDesc.resolveConstantDesc(LOOKUP); fail(); } 276 catch (IllegalAccessException e) { /* expected */ } 277 assertEquals(5, (int) ((MethodHandle)privateStaticMethodDesc.resolveConstantDesc(TestHelpers.TestClass.LOOKUP)).invokeExact(5)); 278 279 try { privateStaticIMethodDesc.resolveConstantDesc(LOOKUP); fail(); } 280 catch (IllegalAccessException e) { /* expected */ } 281 assertEquals(0, (int) ((MethodHandle)privateStaticIMethodDesc.resolveConstantDesc(TestHelpers.TestInterface.LOOKUP)).invokeExact(5)); 282 assertEquals(0, (int) ((MethodHandle)privateStaticIMethodDesc.resolveConstantDesc(TestHelpers.TestClass.LOOKUP)).invokeExact(5)); 283 284 MethodHandleDesc staticSetterDesc = MethodHandleDesc.ofField(STATIC_SETTER, testClass, "sf", CD_int); 285 MethodHandleDesc staticGetterDesc = MethodHandleDesc.ofField(STATIC_GETTER, testClass, "sf", CD_int); 286 MethodHandleDesc staticGetterIDesc = MethodHandleDesc.ofField(STATIC_GETTER, testInterface, "sf", CD_int); 287 MethodHandleDesc setterDesc = MethodHandleDesc.ofField(SETTER, testClass, "f", CD_int); 288 MethodHandleDesc getterDesc = MethodHandleDesc.ofField(GETTER, testClass, "f", CD_int); 289 290 for (MethodHandleDesc r : List.of(staticSetterDesc, staticGetterDesc, staticGetterIDesc, setterDesc, getterDesc)) 291 testMethodHandleDesc(r); 292 293 ((MethodHandle)staticSetterDesc.resolveConstantDesc(LOOKUP)).invokeExact(6); assertEquals(TestHelpers.TestClass.sf, 6); 294 assertEquals(6, (int) ((MethodHandle)staticGetterDesc.resolveConstantDesc(LOOKUP)).invokeExact()); 295 assertEquals(6, (int) ((MethodHandle)staticGetterDesc.resolveConstantDesc(TestHelpers.TestClass.LOOKUP)).invokeExact()); 296 ((MethodHandle)staticSetterDesc.resolveConstantDesc(TestHelpers.TestClass.LOOKUP)).invokeExact(7); assertEquals(TestHelpers.TestClass.sf, 7); 297 assertEquals(7, (int) ((MethodHandle)staticGetterDesc.resolveConstantDesc(LOOKUP)).invokeExact()); 298 assertEquals(7, (int) ((MethodHandle)staticGetterDesc.resolveConstantDesc(TestHelpers.TestClass.LOOKUP)).invokeExact()); 299 300 assertEquals(3, (int) ((MethodHandle)staticGetterIDesc.resolveConstantDesc(LOOKUP)).invokeExact()); 301 assertEquals(3, (int) ((MethodHandle)staticGetterIDesc.resolveConstantDesc(TestHelpers.TestClass.LOOKUP)).invokeExact()); 302 303 ((MethodHandle)setterDesc.resolveConstantDesc(LOOKUP)).invokeExact(instance, 6); assertEquals(instance.f, 6); 304 assertEquals(6, (int) ((MethodHandle)getterDesc.resolveConstantDesc(LOOKUP)).invokeExact(instance)); 305 assertEquals(6, (int) ((MethodHandle)getterDesc.resolveConstantDesc(TestHelpers.TestClass.LOOKUP)).invokeExact(instance)); 306 ((MethodHandle)setterDesc.resolveConstantDesc(TestHelpers.TestClass.LOOKUP)).invokeExact(instance, 7); assertEquals(instance.f, 7); 307 assertEquals(7, (int) ((MethodHandle)getterDesc.resolveConstantDesc(LOOKUP)).invokeExact(instance)); 308 assertEquals(7, (int) ((MethodHandle)getterDesc.resolveConstantDesc(TestHelpers.TestClass.LOOKUP)).invokeExact(instance)); 309 } 310 assertBadArgs(Supplier<MethodHandleDesc> supplier, String s)311 private void assertBadArgs(Supplier<MethodHandleDesc> supplier, String s) { 312 try { 313 MethodHandleDesc r = supplier.get(); 314 fail("Expected failure for " + s); 315 } 316 catch (IllegalArgumentException e) { 317 // succeed 318 } 319 } 320 testBadFieldMHs()321 public void testBadFieldMHs() { 322 List<String> badGetterDescs = List.of("()V", "(Ljava/lang/Object;)V", "(I)I", "(Ljava/lang/Object;I)I"); 323 List<String> badStaticGetterDescs = List.of("()V", "(Ljava/lang/Object;)I", "(I)I", "(Ljava/lang/Object;I)I"); 324 List<String> badSetterDescs = List.of("()V", "(I)V", "(Ljava/lang/Object;)V", "(Ljava/lang/Object;I)I", "(Ljava/lang/Object;II)V"); 325 List<String> badStaticSetterDescs = List.of("()V", "(II)V", "()I"); 326 327 badGetterDescs.forEach(s -> assertBadArgs(() -> MethodHandleDesc.of(GETTER, helperHolderClass, "x", s), s)); 328 badSetterDescs.forEach(s -> assertBadArgs(() -> MethodHandleDesc.of(SETTER, helperHolderClass, "x", s), s)); 329 badStaticGetterDescs.forEach(s -> assertBadArgs(() -> MethodHandleDesc.of(STATIC_GETTER, helperHolderClass, "x", s), s)); 330 badStaticSetterDescs.forEach(s -> assertBadArgs(() -> MethodHandleDesc.of(STATIC_SETTER, helperHolderClass, "x", s), s)); 331 } 332 333 @Test(expectedExceptions = IllegalArgumentException.class) testBadOwners()334 public void testBadOwners() { 335 MethodHandleDesc.ofMethod(VIRTUAL, ClassDesc.ofDescriptor("I"), "x", MethodTypeDesc.ofDescriptor("()I")); 336 } 337 testSymbolicDescsConstants()338 public void testSymbolicDescsConstants() throws ReflectiveOperationException { 339 int tested = 0; 340 Field[] fields = ConstantDescs.class.getDeclaredFields(); 341 for (Field f : fields) { 342 try { 343 if (f.getType().equals(DirectMethodHandleDesc.class) 344 && ((f.getModifiers() & Modifier.STATIC) != 0) 345 && ((f.getModifiers() & Modifier.PUBLIC) != 0)) { 346 MethodHandleDesc r = (MethodHandleDesc) f.get(null); 347 MethodHandle m = (MethodHandle)r.resolveConstantDesc(MethodHandles.lookup()); 348 testMethodHandleDesc(r, m); 349 ++tested; 350 } 351 } 352 catch (Throwable e) { 353 fail("Error testing field " + f.getName(), e); 354 } 355 } 356 357 assertTrue(tested > 0); 358 } 359 testKind()360 public void testKind() { 361 for (Kind k : Kind.values()) { 362 assertEquals(Kind.valueOf(k.refKind, k.isInterface), k); 363 } 364 } 365 } 366