Skip to content

Commit

Permalink
static resolution of FT methods (@Fallback.fallbackMethod, @BeforeRet…
Browse files Browse the repository at this point in the history
…ry.methodName)
  • Loading branch information
Ladicek committed Oct 8, 2024
1 parent b9afadb commit edaff07
Show file tree
Hide file tree
Showing 14 changed files with 213 additions and 120 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.smallrye.faulttolerance.autoconfig;

import java.lang.annotation.Annotation;
import java.util.List;
import java.util.Set;

import org.eclipse.microprofile.faulttolerance.Asynchronous;
Expand Down Expand Up @@ -66,6 +67,10 @@ public class FaultToleranceMethod {
// other annotations, if present, were declared on the type
public Set<Class<? extends Annotation>> annotationsPresentDirectly;

public MethodDescriptor fallbackMethod;
public List<MethodDescriptor> fallbackMethodsWithExceptionParameter;
public MethodDescriptor beforeRetryMethod;

public boolean isLegitimate() {
if (!KotlinSupport.isLegitimate(method)) {
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
import jakarta.inject.Inject;
import jakarta.inject.Singleton;

import org.eclipse.microprofile.faulttolerance.exceptions.FaultToleranceDefinitionException;

import io.smallrye.faulttolerance.config.FaultToleranceMethods;
import io.smallrye.faulttolerance.config.FaultToleranceOperation;

Expand Down Expand Up @@ -74,7 +76,7 @@ protected boolean isMethodDeclaredInHierarchy(Class<?> beanClass, Method method)
}
}
} catch (PrivilegedActionException e) {
throw new IllegalStateException("Unable to get declared methods of " + beanClass);
throw new FaultToleranceDefinitionException(e);
}
beanClass = beanClass.getSuperclass();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ void changeInterceptorPriority(@Observes ProcessAnnotatedType<FaultToleranceInte
void collectFaultToleranceOperations(@Observes ProcessManagedBean<?> event) {
AnnotatedType<?> annotatedType = event.getAnnotatedBeanClass();
for (AnnotatedMethod<?> annotatedMethod : annotatedType.getMethods()) {
FaultToleranceMethod method = FaultToleranceMethods.create(annotatedMethod);
FaultToleranceMethod method = FaultToleranceMethods.create(annotatedType.getJavaClass(), annotatedMethod);
if (method.isLegitimate()) {
FaultToleranceOperation operation = FaultToleranceOperation.create(method);
operation.validate();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -558,7 +558,7 @@ private <V> Function<FailureContext, V> prepareFallbackFunction(InterceptionPoin

String fallbackMethodName = operation.getFallback().fallbackMethod();
FallbackMethodCandidates candidates = !"".equals(fallbackMethodName)
? cache.getFallbackMethodCandidates(point, fallbackMethodName)
? cache.getFallbackMethodCandidates(point, operation)
: null;

Function<FailureContext, V> fallbackFunction;
Expand Down Expand Up @@ -606,7 +606,7 @@ private <V> Function<FailureContext, V> prepareFallbackFunction(InterceptionPoin
private Consumer<FailureContext> prepareBeforeRetryFunction(InterceptionPoint point, FaultToleranceOperation operation) {
String methodName = operation.getBeforeRetry().methodName();
BeforeRetryMethod method = !"".equals(methodName)
? cache.getBeforeRetryMethod(point, methodName)
? cache.getBeforeRetryMethod(point, operation)
: null;

Consumer<FailureContext> beforeRetryFunction;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,40 +1,17 @@
package io.smallrye.faulttolerance.config;

import java.lang.reflect.Method;

import org.eclipse.microprofile.faulttolerance.exceptions.FaultToleranceDefinitionException;

import io.smallrye.faulttolerance.api.BeforeRetry;
import io.smallrye.faulttolerance.autoconfig.AutoConfig;
import io.smallrye.faulttolerance.autoconfig.Config;
import io.smallrye.faulttolerance.internal.BeforeRetryMethod;
import io.smallrye.faulttolerance.internal.InterceptionPoint;

@AutoConfig
public interface BeforeRetryConfig extends BeforeRetry, Config {
default void validate() {
final String INVALID_BEFORE_RETRY_ON = "Invalid @BeforeRetry on ";

Method guardedMethod;
try {
guardedMethod = method().reflect();
} catch (NoSuchMethodException e) {
throw new FaultToleranceDefinitionException(e);
}

if (!"".equals(methodName())) {
if (!BeforeRetry.DEFAULT.class.equals(value())) {
throw new FaultToleranceDefinitionException(INVALID_BEFORE_RETRY_ON + method()
+ ": before retry handler class and before retry method can't be specified both at the same time");
}

BeforeRetryMethod beforeRetryMethod = BeforeRetryMethod.find(
new InterceptionPoint(beanClass(), guardedMethod), methodName());
if (beforeRetryMethod == null) {
throw new FaultToleranceDefinitionException(INVALID_BEFORE_RETRY_ON + method()
+ ": can't find before retry method '" + methodName()
+ "' with no parameter and return type of void");
}
if (!"".equals(methodName()) && !DEFAULT.class.equals(value())) {
throw new FaultToleranceDefinitionException("Invalid @BeforeRetry on " + method()
+ ": before retry handler class and before retry method can't be specified both at the same time");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,8 @@
import org.eclipse.microprofile.faulttolerance.FallbackHandler;
import org.eclipse.microprofile.faulttolerance.exceptions.FaultToleranceDefinitionException;

import io.smallrye.faulttolerance.SpecCompatibility;
import io.smallrye.faulttolerance.autoconfig.AutoConfig;
import io.smallrye.faulttolerance.autoconfig.Config;
import io.smallrye.faulttolerance.internal.FallbackMethodCandidates;
import io.smallrye.faulttolerance.internal.InterceptionPoint;

@AutoConfig
public interface FallbackConfig extends Fallback, Config {
Expand All @@ -27,21 +24,9 @@ default void validate() {
throw new FaultToleranceDefinitionException(e);
}

if (!"".equals(fallbackMethod())) {
if (!Fallback.DEFAULT.class.equals(value())) {
throw new FaultToleranceDefinitionException(INVALID_FALLBACK_ON + method()
+ ": fallback handler class and fallback method can't be specified both at the same time");
}

SpecCompatibility specCompatibility = SpecCompatibility.createFromConfig();
FallbackMethodCandidates candidates = FallbackMethodCandidates.create(
new InterceptionPoint(beanClass(), guardedMethod), fallbackMethod(),
specCompatibility.allowFallbackMethodExceptionParameter());
if (candidates.isEmpty()) {
throw new FaultToleranceDefinitionException(INVALID_FALLBACK_ON + method()
+ ": can't find fallback method '" + fallbackMethod()
+ "' with matching parameter types and return type");
}
if (!"".equals(fallbackMethod()) && !DEFAULT.class.equals(value())) {
throw new FaultToleranceDefinitionException(INVALID_FALLBACK_ON + method()
+ ": fallback handler class and fallback method can't be specified both at the same time");
}

if (!Fallback.DEFAULT.class.equals(value())) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.security.PrivilegedActionException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import jakarta.enterprise.inject.spi.AnnotatedMethod;
Expand All @@ -13,6 +18,7 @@
import org.eclipse.microprofile.faulttolerance.Fallback;
import org.eclipse.microprofile.faulttolerance.Retry;
import org.eclipse.microprofile.faulttolerance.Timeout;
import org.eclipse.microprofile.faulttolerance.exceptions.FaultToleranceDefinitionException;

import io.smallrye.common.annotation.Blocking;
import io.smallrye.common.annotation.NonBlocking;
Expand All @@ -29,12 +35,12 @@
import io.smallrye.faulttolerance.autoconfig.MethodDescriptor;

public class FaultToleranceMethods {
public static FaultToleranceMethod create(AnnotatedMethod<?> method) {
public static FaultToleranceMethod create(Class<?> beanClass, AnnotatedMethod<?> method) {
Set<Class<? extends Annotation>> annotationsPresentDirectly = new HashSet<>();

FaultToleranceMethod result = new FaultToleranceMethod();

result.beanClass = method.getDeclaringType().getJavaClass();
result.beanClass = beanClass;
result.method = createMethodDescriptor(method);

result.applyFaultTolerance = getAnnotation(ApplyFaultTolerance.class, method, annotationsPresentDirectly);
Expand All @@ -60,6 +66,12 @@ public static FaultToleranceMethod create(AnnotatedMethod<?> method) {

result.annotationsPresentDirectly = annotationsPresentDirectly;

try {
searchForMethods(result, beanClass, method.getJavaMember());
} catch (PrivilegedActionException e) {
throw new FaultToleranceDefinitionException(e);
}

return result;
}

Expand All @@ -81,6 +93,8 @@ private static <A extends Annotation> A getAnnotation(Class<A> annotationType, A
return cdiMethod.getDeclaringType().getAnnotation(annotationType);
}

// ---

public static FaultToleranceMethod create(Class<?> beanClass, Method method) {
Set<Class<? extends Annotation>> annotationsPresentDirectly = new HashSet<>();

Expand Down Expand Up @@ -113,6 +127,12 @@ public static FaultToleranceMethod create(Class<?> beanClass, Method method) {

result.annotationsPresentDirectly = annotationsPresentDirectly;

try {
searchForMethods(result, beanClass, method);
} catch (PrivilegedActionException e) {
throw new FaultToleranceDefinitionException(e);
}

return result;
}

Expand Down Expand Up @@ -144,4 +164,53 @@ private static <A extends Annotation> A getAnnotationFromClass(Class<?> clazz, C
}
return null;
}

// ---

private static void searchForMethods(FaultToleranceMethod result, Class<?> beanClass, Method method)
throws PrivilegedActionException {
if (result.fallback != null) {
FallbackConfig fallbackConfig = FallbackConfigImpl.create(result);
if (fallbackConfig != null) {
String fallbackMethod = fallbackConfig.fallbackMethod();
if (!"".equals(fallbackMethod)) {
Class<?> declaringClass = method.getDeclaringClass();
Type[] parameterTypes = method.getGenericParameterTypes();
Type returnType = method.getGenericReturnType();
result.fallbackMethod = createMethodDescriptorIfNotNull(
SecurityActions.findFallbackMethod(beanClass, declaringClass, fallbackMethod,
parameterTypes, returnType));
result.fallbackMethodsWithExceptionParameter = createMethodDescriptorsIfNotEmpty(
SecurityActions.findFallbackMethodsWithExceptionParameter(beanClass, declaringClass, fallbackMethod,
parameterTypes, returnType));
}
}
}

if (result.beforeRetry != null) {
BeforeRetryConfig beforeRetryConfig = BeforeRetryConfigImpl.create(result);
if (beforeRetryConfig != null) {
String beforeRetryMethod = beforeRetryConfig.methodName();
if (!"".equals(beforeRetryMethod)) {
result.beforeRetryMethod = createMethodDescriptorIfNotNull(
SecurityActions.findBeforeRetryMethod(beanClass, method.getDeclaringClass(), beforeRetryMethod));
}
}
}
}

private static MethodDescriptor createMethodDescriptorIfNotNull(Method reflectiveMethod) {
return reflectiveMethod == null ? null : createMethodDescriptor(reflectiveMethod);
}

private static List<MethodDescriptor> createMethodDescriptorsIfNotEmpty(Collection<Method> reflectiveMethods) {
if (reflectiveMethods.isEmpty()) {
return null;
}
List<MethodDescriptor> result = new ArrayList<>(reflectiveMethods.size());
for (Method reflectiveMethod : reflectiveMethods) {
result.add(createMethodDescriptor(reflectiveMethod));
}
return result;
}
}
Loading

0 comments on commit edaff07

Please sign in to comment.