/** * {@inheritDoc} */ @SuppressWarnings("deprecation") // Due to isAccessible() call. @SuppressFBWarnings(value = "REC_CATCH_EXCEPTION", justification = "Exception should always be wrapped for clarity") public AnnotationValue<?, ?> getValue(MethodDescription.InDefinedShape property) { if (!property.getDeclaringType().represents(annotation.annotationType())) { throw new IllegalArgumentException(property + " does not represent " + annotation.annotationType()); } try { boolean accessible = property.getDeclaringType().isPublic(); // method is required to be public Method method = property instanceof MethodDescription.ForLoadedMethod ? ((MethodDescription.ForLoadedMethod) property).getLoadedMethod() : null; if (method == null || method.getDeclaringClass() != annotation.annotationType() || (!accessible && !method.isAccessible())) { method = annotation.annotationType().getMethod(property.getName()); if (!accessible) { AccessController.doPrivileged(new SetAccessibleAction<Method>(method)); } } return asValue(method.invoke(annotation), method.getReturnType()); } catch (InvocationTargetException exception) { throw new IllegalStateException("Error reading annotation property " + property, exception.getCause()); } catch (Exception exception) { throw new IllegalStateException("Cannot access annotation property " + property, exception); } }
/** * Extracts the only method from a given type description which is validated for the required properties for * using the type as a proxy base type. * * @param typeDescription The type description to evaluate. * @return The only method which was found to be compatible to the proxy requirements. */ private static MethodDescription.InDefinedShape onlyMethod(TypeDescription typeDescription) { if (!typeDescription.isInterface()) { throw new IllegalArgumentException(typeDescription + " is not an interface"); } else if (!typeDescription.getInterfaces().isEmpty()) { throw new IllegalArgumentException(typeDescription + " must not extend other interfaces"); } else if (!typeDescription.isPublic()) { throw new IllegalArgumentException(typeDescription + " is not public"); } MethodList<MethodDescription.InDefinedShape> methodCandidates = typeDescription.getDeclaredMethods().filter(isAbstract()); if (methodCandidates.size() != 1) { throw new IllegalArgumentException(typeDescription + " must declare exactly one abstract method"); } return methodCandidates.getOnly(); }
/** * Creates a binder by installing a single proxy type where annotating a parameter with {@link FieldProxy} allows * getting and setting values for a given field. * * @param typeDescription A type which declares exactly one abstract getter and an abstract setter for the {@link Object} * type. The type is allowed to be generic. * @return A binder for the {@link FieldProxy} annotation. */ public static TargetMethodAnnotationDrivenBinder.ParameterBinder<FieldProxy> install(TypeDescription typeDescription) { if (!typeDescription.isInterface()) { throw new IllegalArgumentException(typeDescription + " is not an interface"); } else if (!typeDescription.getInterfaces().isEmpty()) { throw new IllegalArgumentException(typeDescription + " must not extend other interfaces"); } else if (!typeDescription.isPublic()) { throw new IllegalArgumentException(typeDescription + " is not public"); } MethodList<MethodDescription.InDefinedShape> methodCandidates = typeDescription.getDeclaredMethods().filter(isAbstract()); if (methodCandidates.size() != 2) { throw new IllegalArgumentException(typeDescription + " does not declare exactly two non-abstract methods"); } MethodList<MethodDescription.InDefinedShape> getterCandidates = methodCandidates.filter(isGetter(Object.class)); if (getterCandidates.size() != 1) { throw new IllegalArgumentException(typeDescription + " does not declare a getter with an Object type"); } MethodList<MethodDescription.InDefinedShape> setterCandidates = methodCandidates.filter(isSetter(Object.class)); if (setterCandidates.size() != 1) { throw new IllegalArgumentException(typeDescription + " does not declare a setter with an Object type"); } return new Binder(typeDescription, getterCandidates.getOnly(), setterCandidates.getOnly()); }
/** * Locates the only method of a type that is compatible to being overridden for invoking the proxy. * * @param typeDescription The type that is being installed. * @return Its only method after validation. */ private static MethodDescription onlyMethod(TypeDescription typeDescription) { if (!typeDescription.isInterface()) { throw new IllegalArgumentException(typeDescription + " is not an interface"); } else if (!typeDescription.getInterfaces().isEmpty()) { throw new IllegalArgumentException(typeDescription + " must not extend other interfaces"); } else if (!typeDescription.isPublic()) { throw new IllegalArgumentException(typeDescription + " is mot public"); } MethodList<?> methodCandidates = typeDescription.getDeclaredMethods().filter(isAbstract()); if (methodCandidates.size() != 1) { throw new IllegalArgumentException(typeDescription + " must declare exactly one abstract method"); } MethodDescription methodDescription = methodCandidates.getOnly(); if (!methodDescription.getReturnType().asErasure().represents(Object.class)) { throw new IllegalArgumentException(methodDescription + " does not return an Object-type"); } else if (methodDescription.getParameters().size() != 1 || !methodDescription.getParameters().getOnly().getType().asErasure().represents(Object.class)) { throw new IllegalArgumentException(methodDescription + " does not take a single Object-typed argument"); } return methodDescription; }
/** * Extracts the only method of a given type and validates to fit the constraints of the morph annotation. * * @param typeDescription The type to extract the method from. * @return The only method after validation. */ private static MethodDescription onlyMethod(TypeDescription typeDescription) { if (!typeDescription.isInterface()) { throw new IllegalArgumentException(typeDescription + " is not an interface"); } else if (!typeDescription.getInterfaces().isEmpty()) { throw new IllegalArgumentException(typeDescription + " must not extend other interfaces"); } else if (!typeDescription.isPublic()) { throw new IllegalArgumentException(typeDescription + " is mot public"); } MethodList<?> methodCandidates = typeDescription.getDeclaredMethods().filter(isAbstract()); if (methodCandidates.size() != 1) { throw new IllegalArgumentException(typeDescription + " must declare exactly one abstract method"); } MethodDescription methodDescription = methodCandidates.getOnly(); if (!methodDescription.getReturnType().asErasure().represents(Object.class)) { throw new IllegalArgumentException(methodDescription + " does not return an Object-type"); } else if (methodDescription.getParameters().size() != 1 || !methodDescription.getParameters().get(0).getType().asErasure().represents(Object[].class)) { throw new IllegalArgumentException(methodDescription + " does not take a single argument of type Object[]"); } return methodDescription; }