150 // private constructors, or interfaces with multiple but related |
150 // private constructors, or interfaces with multiple but related |
151 // entry points, must be covered by hand-written or automatically |
151 // entry points, must be covered by hand-written or automatically |
152 // generated adapter classes. |
152 // generated adapter classes. |
153 // |
153 // |
154 @CallerSensitive |
154 @CallerSensitive |
155 public static |
155 public static <T> T asInterfaceInstance(final Class<T> intfc, final MethodHandle target) { |
156 <T> T asInterfaceInstance(final Class<T> intfc, final MethodHandle target) { |
|
157 if (!intfc.isInterface() || !Modifier.isPublic(intfc.getModifiers())) |
156 if (!intfc.isInterface() || !Modifier.isPublic(intfc.getModifiers())) |
158 throw newIllegalArgumentException("not a public interface", intfc.getName()); |
157 throw newIllegalArgumentException("not a public interface", intfc.getName()); |
159 final MethodHandle mh; |
158 final MethodHandle mh; |
160 if (System.getSecurityManager() != null) { |
159 if (System.getSecurityManager() != null) { |
161 final Class<?> caller = Reflection.getCallerClass(); |
160 final Class<?> caller = Reflection.getCallerClass(); |
233 /** |
232 /** |
234 * Determines if the given object was produced by a call to {@link #asInterfaceInstance asInterfaceInstance}. |
233 * Determines if the given object was produced by a call to {@link #asInterfaceInstance asInterfaceInstance}. |
235 * @param x any reference |
234 * @param x any reference |
236 * @return true if the reference is not null and points to an object produced by {@code asInterfaceInstance} |
235 * @return true if the reference is not null and points to an object produced by {@code asInterfaceInstance} |
237 */ |
236 */ |
238 public static |
237 public static boolean isWrapperInstance(Object x) { |
239 boolean isWrapperInstance(Object x) { |
|
240 return x instanceof WrapperInstance; |
238 return x instanceof WrapperInstance; |
241 } |
239 } |
242 |
240 |
243 private static WrapperInstance asWrapperInstance(Object x) { |
241 private static WrapperInstance asWrapperInstance(Object x) { |
244 try { |
242 try { |
256 * This requirement may be tested via {@link #isWrapperInstance isWrapperInstance}. |
254 * This requirement may be tested via {@link #isWrapperInstance isWrapperInstance}. |
257 * @param x any reference |
255 * @param x any reference |
258 * @return a method handle implementing the unique method |
256 * @return a method handle implementing the unique method |
259 * @throws IllegalArgumentException if the reference x is not to a wrapper instance |
257 * @throws IllegalArgumentException if the reference x is not to a wrapper instance |
260 */ |
258 */ |
261 public static |
259 public static MethodHandle wrapperInstanceTarget(Object x) { |
262 MethodHandle wrapperInstanceTarget(Object x) { |
|
263 return asWrapperInstance(x).getWrapperInstanceTarget(); |
260 return asWrapperInstance(x).getWrapperInstanceTarget(); |
264 } |
261 } |
265 |
262 |
266 /** |
263 /** |
267 * Recovers the unique single-method interface type for which this wrapper instance was created. |
264 * Recovers the unique single-method interface type for which this wrapper instance was created. |
269 * This requirement may be tested via {@link #isWrapperInstance isWrapperInstance}. |
266 * This requirement may be tested via {@link #isWrapperInstance isWrapperInstance}. |
270 * @param x any reference |
267 * @param x any reference |
271 * @return the single-method interface type for which the wrapper was created |
268 * @return the single-method interface type for which the wrapper was created |
272 * @throws IllegalArgumentException if the reference x is not to a wrapper instance |
269 * @throws IllegalArgumentException if the reference x is not to a wrapper instance |
273 */ |
270 */ |
274 public static |
271 public static Class<?> wrapperInstanceType(Object x) { |
275 Class<?> wrapperInstanceType(Object x) { |
|
276 return asWrapperInstance(x).getWrapperInstanceType(); |
272 return asWrapperInstance(x).getWrapperInstanceType(); |
277 } |
273 } |
278 |
274 |
279 private static |
275 private static boolean isObjectMethod(Method m) { |
280 boolean isObjectMethod(Method m) { |
|
281 switch (m.getName()) { |
276 switch (m.getName()) { |
282 case "toString": |
277 case "toString": |
283 return (m.getReturnType() == String.class |
278 return (m.getReturnType() == String.class |
284 && m.getParameterTypes().length == 0); |
279 && m.getParameterTypes().length == 0); |
285 case "hashCode": |
280 case "hashCode": |
291 && m.getParameterTypes()[0] == Object.class); |
286 && m.getParameterTypes()[0] == Object.class); |
292 } |
287 } |
293 return false; |
288 return false; |
294 } |
289 } |
295 |
290 |
296 private static |
291 private static Object callObjectMethod(Object self, Method m, Object[] args) { |
297 Object callObjectMethod(Object self, Method m, Object[] args) { |
|
298 assert(isObjectMethod(m)) : m; |
292 assert(isObjectMethod(m)) : m; |
299 switch (m.getName()) { |
293 switch (m.getName()) { |
300 case "toString": |
294 case "toString": |
301 return self.getClass().getName() + "@" + Integer.toHexString(self.hashCode()); |
295 return self.getClass().getName() + "@" + Integer.toHexString(self.hashCode()); |
302 case "hashCode": |
296 case "hashCode": |
305 return (self == args[0]); |
299 return (self == args[0]); |
306 } |
300 } |
307 return null; |
301 return null; |
308 } |
302 } |
309 |
303 |
310 private static |
304 private static Method[] getSingleNameMethods(Class<?> intfc) { |
311 Method[] getSingleNameMethods(Class<?> intfc) { |
|
312 ArrayList<Method> methods = new ArrayList<>(); |
305 ArrayList<Method> methods = new ArrayList<>(); |
313 String uniqueName = null; |
306 String uniqueName = null; |
314 for (Method m : intfc.getMethods()) { |
307 for (Method m : intfc.getMethods()) { |
315 if (isObjectMethod(m)) continue; |
308 if (isObjectMethod(m)) continue; |
316 if (!Modifier.isAbstract(m.getModifiers())) continue; |
309 if (!Modifier.isAbstract(m.getModifiers())) continue; |
323 } |
316 } |
324 if (uniqueName == null) return null; |
317 if (uniqueName == null) return null; |
325 return methods.toArray(new Method[methods.size()]); |
318 return methods.toArray(new Method[methods.size()]); |
326 } |
319 } |
327 |
320 |
328 private static |
321 private static boolean isDefaultMethod(Method m) { |
329 boolean isDefaultMethod(Method m) { |
|
330 return !Modifier.isAbstract(m.getModifiers()); |
322 return !Modifier.isAbstract(m.getModifiers()); |
331 } |
323 } |
332 |
324 |
333 private static |
325 private static boolean hasDefaultMethods(Class<?> intfc) { |
334 boolean hasDefaultMethods(Class<?> intfc) { |
|
335 for (Method m : intfc.getMethods()) { |
326 for (Method m : intfc.getMethods()) { |
336 if (!isObjectMethod(m) && |
327 if (!isObjectMethod(m) && |
337 !Modifier.isAbstract(m.getModifiers())) { |
328 !Modifier.isAbstract(m.getModifiers())) { |
338 return true; |
329 return true; |
339 } |
330 } |
340 } |
331 } |
341 return false; |
332 return false; |
342 } |
333 } |
343 |
334 |
344 private static |
335 private static Object callDefaultMethod(ConcurrentHashMap<Method, MethodHandle> defaultMethodMap, |
345 Object callDefaultMethod(ConcurrentHashMap<Method, MethodHandle> defaultMethodMap, |
|
346 Object self, Class<?> intfc, Method m, Object[] args) throws Throwable { |
336 Object self, Class<?> intfc, Method m, Object[] args) throws Throwable { |
347 assert(isDefaultMethod(m) && !isObjectMethod(m)) : m; |
337 assert(isDefaultMethod(m) && !isObjectMethod(m)) : m; |
348 |
338 |
349 // Lazily compute the associated method handle from the method |
339 // Lazily compute the associated method handle from the method |
350 MethodHandle dmh = defaultMethodMap.computeIfAbsent(m, mk -> { |
340 MethodHandle dmh = defaultMethodMap.computeIfAbsent(m, mk -> { |