package org.jboss.weld.interceptor.reader;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.interceptor.InvocationContext;
import org.jboss.weld.annotated.enhanced.EnhancedAnnotatedType;
import org.jboss.weld.interceptor.spi.model.InterceptionType;
import org.jboss.weld.interceptor.util.InterceptionTypeRegistry;
import org.jboss.weld.logging.ValidatorLogger;
import org.jboss.weld.manager.BeanManagerImpl;
import org.jboss.weld.util.BeanMethods;
import org.jboss.weld.util.collections.ImmutableMap;
import org.jboss.weld.util.reflection.Formats;
/**
* @author Marius Bogoevici
* @author Marko Luksa
*/
public class InterceptorMetadataUtils {
protected static final String OBJECT_CLASS_NAME = Object.class.getName();
private InterceptorMetadataUtils() {
}
public static boolean isInterceptorMethod(InterceptionType interceptionType, Method method, boolean forTargetClass) {
if (interceptionType.isLifecycleCallback()) {
if (forTargetClass) {
return isValidTargetClassLifecycleInterceptorMethod(interceptionType, method);
} else {
return isValidInterceptorClassLifecycleInterceptorMethod(interceptionType, method);
}
} else {
return isValidBusinessMethodInterceptorMethod(interceptionType, method);
}
}
private static boolean isValidTargetClassLifecycleInterceptorMethod(InterceptionType interceptionType, Method method) {
/*
* This check is relaxed (WELD-1399) because we are not able to distinguish a CDI managed bean from
* an interceptor class bound using @Interceptors.
*
* This will be revisited as part of https://issues.jboss.org/browse/WELD-1401
*
if (interceptionType == InterceptionType.AROUND_CONSTRUCT) {
throw new DefinitionException(ValidatorMessage.AROUND_CONSTRUCT_INTERCEPTOR_METHOD_NOT_ALLOWED_ON_TARGET_CLASS,
javaMethod.getName(), javaMethod.getDeclaringClass().getName(),
interceptionType.annotationClassName());
}
*/
/*
* Again, we relax the check and allow both void and Object return types as we cannot distinguish between
* a managed bean and an interceptor class.
*/
if (!Void.TYPE.equals(method.getReturnType()) && !Object.class.equals(method.getReturnType())) {
throw ValidatorLogger.LOG.interceptorMethodDoesNotHaveVoidReturnType(
method.getName(), method.getDeclaringClass().getName(),
interceptionType.annotationClassName(), Void.TYPE.getName(), Formats.formatAsStackTraceElement(method));
}
Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length == 1) {
ValidatorLogger.LOG.interceptorMethodDoesNotHaveZeroParameters(
method.getName(), method.getDeclaringClass().getName(),
interceptionType.annotationClassName());
}
if (parameterTypes.length > 1) {
throw ValidatorLogger.LOG.interceptorMethodDeclaresMultipleParameters(
method.getName(), method.getDeclaringClass().getName(),
interceptionType.annotationClassName(), Formats.formatAsStackTraceElement(method));
}
Class<?>[] exceptionTypes = method.getExceptionTypes();
if (exceptionTypes.length != 0) {
for (Class<?> exceptionType : exceptionTypes) {
if (!RuntimeException.class.isAssignableFrom(exceptionType)) {
ValidatorLogger.LOG.interceptorMethodShouldNotThrowCheckedExceptions(
method.getName(), method.getDeclaringClass().getName(),
exceptionType.getName(), Formats.formatAsStackTraceElement(method));
}
}
}
return parameterTypes.length == 0;
}
private static boolean isValidInterceptorClassLifecycleInterceptorMethod(InterceptionType interceptionType, Method method) {
if (!Object.class.equals(method.getReturnType()) && !Void.TYPE.equals(method.getReturnType())) {
throw ValidatorLogger.LOG.interceptorMethodDoesNotReturnObjectOrVoid(method.getName(), method.getDeclaringClass().getName(),
interceptionType.annotationClassName(), Void.TYPE.getName(), OBJECT_CLASS_NAME, Formats.formatAsStackTraceElement(method));
}
Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length == 0) {
return false;
} else if (parameterTypes.length == 1) {
if (InvocationContext.class.isAssignableFrom(parameterTypes[0])) {
return true;
}
throw ValidatorLogger.LOG.interceptorMethodDoesNotHaveCorrectTypeOfParameter(method.getName(), method.getDeclaringClass().getName(),
interceptionType.annotationClassName(), InvocationContext.class.getName(), Formats.formatAsStackTraceElement(method));
} else {
throw ValidatorLogger.LOG.interceptorMethodDoesNotHaveExactlyOneParameter(method.getName(), method.getDeclaringClass().getName(),
interceptionType.annotationClassName(), Formats.formatAsStackTraceElement(method));
}
}
private static boolean isValidBusinessMethodInterceptorMethod(InterceptionType interceptionType, Method method) {
if (!Object.class.equals(method.getReturnType())) {
throw ValidatorLogger.LOG.interceptorMethodDoesNotReturnObject(method.getName(), method.getDeclaringClass().getName(),
interceptionType.annotationClassName(), OBJECT_CLASS_NAME, Formats.formatAsStackTraceElement(method));
}
Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length != 1) {
throw ValidatorLogger.LOG.interceptorMethodDoesNotHaveExactlyOneParameter(method.getName(), method.getDeclaringClass().getName(),
interceptionType.annotationClassName(), Formats.formatAsStackTraceElement(method));
}
if (!InvocationContext.class.isAssignableFrom(parameterTypes[0])) {
throw ValidatorLogger.LOG.interceptorMethodDoesNotHaveCorrectTypeOfParameter(method.getName(), method.getDeclaringClass().getName(),
interceptionType.annotationClassName(), InvocationContext.class.getName(), Formats.formatAsStackTraceElement(method));
}
return true;
}
public static Map<InterceptionType, List<Method>> buildMethodMap(EnhancedAnnotatedType<?> type, boolean forTargetClass, BeanManagerImpl manager) {
ImmutableMap.Builder<InterceptionType, List<Method>> builder = null;
for (InterceptionType interceptionType : InterceptionTypeRegistry.getSupportedInterceptionTypes()) {
List<Method> value = BeanMethods.getInterceptorMethods(type, interceptionType, forTargetClass);
if (!value.isEmpty()) {
if (builder == null) {
builder = ImmutableMap.builder();
}
builder.put(interceptionType, value);
}
}
if (builder == null) {
return Collections.emptyMap();
}
return builder.build();
}
}