mirror of
https://github.com/jlengrand/quarkus.git
synced 2026-03-10 08:41:22 +00:00
Arc - make it possible to get interceptor bindings from
InvocationContext - resolves #29
This commit is contained in:
@@ -14,6 +14,8 @@ import org.jboss.jandex.AnnotationValue;
|
||||
import org.jboss.jandex.ArrayType;
|
||||
import org.jboss.jandex.ClassInfo;
|
||||
import org.jboss.jandex.MethodInfo;
|
||||
import org.jboss.jandex.PrimitiveType;
|
||||
import org.jboss.jandex.Type;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.jboss.protean.arc.ComputingCache;
|
||||
import org.jboss.protean.arc.processor.AnnotationLiteralProcessor.CacheKey;
|
||||
@@ -72,47 +74,94 @@ public class AnnotationLiteralGenerator extends AbstractGenerator {
|
||||
value = method.defaultValue();
|
||||
}
|
||||
ResultHandle retValue = null;
|
||||
if (value != null) {
|
||||
if (value == null) {
|
||||
switch (method.returnType().kind()) {
|
||||
case CLASS:
|
||||
case ARRAY:
|
||||
retValue = valueMethod.loadNull();
|
||||
break;
|
||||
case PRIMITIVE:
|
||||
PrimitiveType primitiveType = method.returnType().asPrimitiveType();
|
||||
switch (primitiveType.primitive()) {
|
||||
case BOOLEAN:
|
||||
retValue = valueMethod.load(false);
|
||||
break;
|
||||
case BYTE:
|
||||
case SHORT:
|
||||
case INT:
|
||||
retValue = valueMethod.load(0);
|
||||
break;
|
||||
case LONG:
|
||||
retValue = valueMethod.load(0L);
|
||||
break;
|
||||
case FLOAT:
|
||||
retValue = valueMethod.load(0.0f);
|
||||
break;
|
||||
case DOUBLE:
|
||||
retValue = valueMethod.load(0.0d);
|
||||
break;
|
||||
case CHAR:
|
||||
retValue = valueMethod.load('\u0000');
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (value.kind()) {
|
||||
case BOOLEAN:
|
||||
retValue = value != null ? valueMethod.load(value.asBoolean()) : valueMethod.load(false);
|
||||
retValue = valueMethod.load(value.asBoolean());
|
||||
break;
|
||||
case STRING:
|
||||
retValue = value != null ? valueMethod.load(value.asString()) : valueMethod.loadNull();
|
||||
retValue = valueMethod.load(value.asString());
|
||||
break;
|
||||
case BYTE:
|
||||
retValue = value != null ? valueMethod.load(value.asByte()) : valueMethod.load(0);
|
||||
retValue = valueMethod.load(value.asByte());
|
||||
break;
|
||||
case SHORT:
|
||||
retValue = value != null ? valueMethod.load(value.asShort()) : valueMethod.load(0);
|
||||
retValue = valueMethod.load(value.asShort());
|
||||
break;
|
||||
case LONG:
|
||||
retValue = value != null ? valueMethod.load(value.asLong()) : valueMethod.load(0L);
|
||||
retValue = valueMethod.load(value.asLong());
|
||||
break;
|
||||
case INTEGER:
|
||||
retValue = value != null ? valueMethod.load(value.asInt()) : valueMethod.load(0);
|
||||
retValue = valueMethod.load(value.asInt());
|
||||
break;
|
||||
case FLOAT:
|
||||
retValue = value != null ? valueMethod.load(value.asFloat()) : valueMethod.load(0.0f);
|
||||
retValue = valueMethod.load(value.asFloat());
|
||||
break;
|
||||
case DOUBLE:
|
||||
retValue = value != null ? valueMethod.load(value.asDouble()) : valueMethod.load(0.0d);
|
||||
retValue = valueMethod.load(value.asDouble());
|
||||
break;
|
||||
case CHARACTER:
|
||||
retValue = value != null ? valueMethod.load(value.asChar()) : valueMethod.load('\u0000');
|
||||
retValue = valueMethod.load(value.asChar());
|
||||
break;
|
||||
case CLASS:
|
||||
retValue = value != null ? valueMethod.loadClass(value.asClass().toString()) : valueMethod.loadNull();
|
||||
retValue = valueMethod.loadClass(value.asClass().toString());
|
||||
break;
|
||||
case ARRAY:
|
||||
// Always return an empty array
|
||||
// Array members must be Nonbinding
|
||||
retValue = value != null ? valueMethod.newArray(componentType(method), valueMethod.load(0)) : valueMethod.loadNull();
|
||||
switch (value.componentKind()) {
|
||||
case CLASS:
|
||||
Type[] classArray = value.asClassArray();
|
||||
retValue = valueMethod.newArray(componentType(method), valueMethod.load(classArray.length));
|
||||
for (int i = 0; i < classArray.length; i++) {
|
||||
valueMethod.writeArrayValue(retValue, valueMethod.load(i), valueMethod.loadClass(classArray[i].name().toString()));
|
||||
}
|
||||
break;
|
||||
// TODO other types of array components
|
||||
// Note that array members should be Nonbinding in CDI
|
||||
default:
|
||||
// For an empty array component kind is UNKNOWN
|
||||
if (!method.returnType().name().equals(DotNames.CLASS)) {
|
||||
LOGGER.warnf("Unsupported array component type %s on %s - literal returns an empty array", method, annotationClass);
|
||||
}
|
||||
retValue = valueMethod.newArray(componentType(method), valueMethod.load(0));
|
||||
}
|
||||
break;
|
||||
case ENUM:
|
||||
retValue = value != null
|
||||
? valueMethod.readStaticField(FieldDescriptor.of(value.asEnumType().toString(), value.asEnum(), value.asEnumType().toString()))
|
||||
: valueMethod.loadNull();
|
||||
retValue = valueMethod
|
||||
.readStaticField(FieldDescriptor.of(value.asEnumType().toString(), value.asEnum(), value.asEnumType().toString()));
|
||||
break;
|
||||
case NESTED:
|
||||
default:
|
||||
|
||||
@@ -5,7 +5,6 @@ import static org.objectweb.asm.Opcodes.ACC_FINAL;
|
||||
import static org.objectweb.asm.Opcodes.ACC_PRIVATE;
|
||||
import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
@@ -43,9 +42,9 @@ import org.jboss.protean.arc.InitializedInterceptor;
|
||||
import org.jboss.protean.arc.InjectableBean;
|
||||
import org.jboss.protean.arc.InjectableInterceptor;
|
||||
import org.jboss.protean.arc.InjectableReferenceProvider;
|
||||
import org.jboss.protean.arc.InvocationContextImpl;
|
||||
import org.jboss.protean.arc.LazyValue;
|
||||
import org.jboss.protean.arc.Subclass;
|
||||
import org.jboss.protean.arc.processor.BeanInfo.InterceptionInfo;
|
||||
import org.jboss.protean.arc.processor.ResourceOutput.Resource;
|
||||
import org.jboss.protean.arc.processor.ResourceOutput.Resource.SpecialType;
|
||||
import org.jboss.protean.gizmo.BytecodeCreator;
|
||||
@@ -78,25 +77,29 @@ public class BeanGenerator extends AbstractGenerator {
|
||||
|
||||
private static final String FIELD_NAME_DECLARING_PROVIDER = "declaringProvider";
|
||||
|
||||
protected final AnnotationLiteralProcessor annotationLiterals;
|
||||
|
||||
public BeanGenerator(AnnotationLiteralProcessor annotationLiterals) {
|
||||
this.annotationLiterals = annotationLiterals;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param bean
|
||||
* @param annotationLiterals
|
||||
* @return a collection of resources
|
||||
*/
|
||||
Collection<Resource> generate(BeanInfo bean, AnnotationLiteralProcessor annotationLiterals, ReflectionRegistration reflectionRegistration) {
|
||||
Collection<Resource> generate(BeanInfo bean, ReflectionRegistration reflectionRegistration) {
|
||||
if (Kind.CLASS.equals(bean.getTarget().kind())) {
|
||||
return generateClassBean(bean, bean.getTarget().asClass(), annotationLiterals, reflectionRegistration);
|
||||
return generateClassBean(bean, bean.getTarget().asClass(), reflectionRegistration);
|
||||
} else if (Kind.METHOD.equals(bean.getTarget().kind())) {
|
||||
return generateProducerMethodBean(bean, bean.getTarget().asMethod(), annotationLiterals, reflectionRegistration);
|
||||
return generateProducerMethodBean(bean, bean.getTarget().asMethod(), reflectionRegistration);
|
||||
} else if (Kind.FIELD.equals(bean.getTarget().kind())) {
|
||||
return generateProducerFieldBean(bean, bean.getTarget().asField(), annotationLiterals, reflectionRegistration);
|
||||
return generateProducerFieldBean(bean, bean.getTarget().asField(), reflectionRegistration);
|
||||
}
|
||||
throw new IllegalArgumentException("Unsupported bean type");
|
||||
}
|
||||
|
||||
Collection<Resource> generateClassBean(BeanInfo bean, ClassInfo beanClass, AnnotationLiteralProcessor annotationLiterals,
|
||||
ReflectionRegistration reflectionRegistration) {
|
||||
Collection<Resource> generateClassBean(BeanInfo bean, ClassInfo beanClass, ReflectionRegistration reflectionRegistration) {
|
||||
|
||||
String baseName;
|
||||
if (beanClass.enclosingClass() != null) {
|
||||
@@ -135,7 +138,8 @@ public class BeanGenerator extends AbstractGenerator {
|
||||
if (!bean.hasDefaultDestroy()) {
|
||||
createDestroy(bean, beanCreator, providerTypeName, injectionPointToProviderField, reflectionRegistration);
|
||||
}
|
||||
createCreate(beanCreator, bean, providerTypeName, baseName, injectionPointToProviderField, interceptorToProviderField, reflectionRegistration);
|
||||
createCreate(classOutput, beanCreator, bean, providerTypeName, baseName, injectionPointToProviderField, interceptorToProviderField,
|
||||
reflectionRegistration);
|
||||
createGet(bean, beanCreator, providerTypeName);
|
||||
|
||||
createGetTypes(beanCreator, beanTypes.getFieldDescriptor());
|
||||
@@ -153,8 +157,7 @@ public class BeanGenerator extends AbstractGenerator {
|
||||
return classOutput.getResources();
|
||||
}
|
||||
|
||||
Collection<Resource> generateProducerMethodBean(BeanInfo bean, MethodInfo producerMethod, AnnotationLiteralProcessor annotationLiterals,
|
||||
ReflectionRegistration reflectionRegistration) {
|
||||
Collection<Resource> generateProducerMethodBean(BeanInfo bean, MethodInfo producerMethod, ReflectionRegistration reflectionRegistration) {
|
||||
|
||||
ClassInfo declaringClass = producerMethod.declaringClass();
|
||||
String declaringClassBase;
|
||||
@@ -196,7 +199,7 @@ public class BeanGenerator extends AbstractGenerator {
|
||||
if (!bean.hasDefaultDestroy()) {
|
||||
createDestroy(bean, beanCreator, providerTypeName, injectionPointToProviderField, reflectionRegistration);
|
||||
}
|
||||
createCreate(beanCreator, bean, providerTypeName, baseName, injectionPointToProviderField, Collections.emptyMap(), reflectionRegistration);
|
||||
createCreate(classOutput, beanCreator, bean, providerTypeName, baseName, injectionPointToProviderField, Collections.emptyMap(), reflectionRegistration);
|
||||
createGet(bean, beanCreator, providerTypeName);
|
||||
|
||||
createGetTypes(beanCreator, beanTypes.getFieldDescriptor());
|
||||
@@ -212,8 +215,7 @@ public class BeanGenerator extends AbstractGenerator {
|
||||
return classOutput.getResources();
|
||||
}
|
||||
|
||||
Collection<Resource> generateProducerFieldBean(BeanInfo bean, FieldInfo producerField, AnnotationLiteralProcessor annotationLiterals,
|
||||
ReflectionRegistration reflectionRegistration) {
|
||||
Collection<Resource> generateProducerFieldBean(BeanInfo bean, FieldInfo producerField, ReflectionRegistration reflectionRegistration) {
|
||||
|
||||
ClassInfo declaringClass = producerField.declaringClass();
|
||||
String declaringClassBase;
|
||||
@@ -251,7 +253,7 @@ public class BeanGenerator extends AbstractGenerator {
|
||||
if (!bean.hasDefaultDestroy()) {
|
||||
createDestroy(bean, beanCreator, providerTypeName, null, reflectionRegistration);
|
||||
}
|
||||
createCreate(beanCreator, bean, providerTypeName, baseName, Collections.emptyMap(), Collections.emptyMap(), reflectionRegistration);
|
||||
createCreate(classOutput, beanCreator, bean, providerTypeName, baseName, Collections.emptyMap(), Collections.emptyMap(), reflectionRegistration);
|
||||
createGet(bean, beanCreator, providerTypeName);
|
||||
|
||||
createGetTypes(beanCreator, beanTypes.getFieldDescriptor());
|
||||
@@ -541,6 +543,7 @@ public class BeanGenerator extends AbstractGenerator {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param classOutput
|
||||
* @param beanCreator
|
||||
* @param bean
|
||||
* @param baseName
|
||||
@@ -548,7 +551,7 @@ public class BeanGenerator extends AbstractGenerator {
|
||||
* @param interceptorToProviderField
|
||||
* @see Contextual#create(CreationalContext)
|
||||
*/
|
||||
protected void createCreate(ClassCreator beanCreator, BeanInfo bean, String providerTypeName, String baseName,
|
||||
protected void createCreate(ClassOutput classOutput, ClassCreator beanCreator, BeanInfo bean, String providerTypeName, String baseName,
|
||||
Map<InjectionPointInfo, String> injectionPointToProviderField, Map<InterceptorInfo, String> interceptorToProviderField,
|
||||
ReflectionRegistration reflectionRegistration) {
|
||||
|
||||
@@ -565,13 +568,13 @@ public class BeanGenerator extends AbstractGenerator {
|
||||
|
||||
if (bean.hasLifecycleInterceptors()) {
|
||||
// Note that we must share the interceptors instances with the intercepted subclass, if present
|
||||
List<InterceptorInfo> postConstructs = bean.getLifecycleInterceptors(InterceptionType.POST_CONSTRUCT);
|
||||
List<InterceptorInfo> aroundConstructs = bean.getLifecycleInterceptors(InterceptionType.AROUND_CONSTRUCT);
|
||||
InterceptionInfo postConstructs = bean.getLifecycleInterceptors(InterceptionType.POST_CONSTRUCT);
|
||||
InterceptionInfo aroundConstructs = bean.getLifecycleInterceptors(InterceptionType.AROUND_CONSTRUCT);
|
||||
|
||||
// Wrap InjectableInterceptors using InitializedInterceptor
|
||||
Set<InterceptorInfo> wraps = new HashSet<>();
|
||||
wraps.addAll(aroundConstructs);
|
||||
wraps.addAll(postConstructs);
|
||||
wraps.addAll(aroundConstructs.interceptors);
|
||||
wraps.addAll(postConstructs.interceptors);
|
||||
for (InterceptorInfo interceptor : wraps) {
|
||||
ResultHandle interceptorProvider = create.readInstanceField(
|
||||
FieldDescriptor.of(beanCreator.getClassName(), interceptorToProviderField.get(interceptor), InjectableInterceptor.class.getName()),
|
||||
@@ -586,14 +589,16 @@ public class BeanGenerator extends AbstractGenerator {
|
||||
if (!postConstructs.isEmpty()) {
|
||||
// postConstructs = new ArrayList<InterceptorInvocation>()
|
||||
postConstructsHandle = create.newInstance(MethodDescriptor.ofConstructor(ArrayList.class));
|
||||
for (InterceptorInfo interceptor : postConstructs) {
|
||||
for (InterceptorInfo interceptor : postConstructs.interceptors) {
|
||||
ResultHandle interceptorHandle = create.readInstanceField(FieldDescriptor.of(beanCreator.getClassName(),
|
||||
interceptorToProviderField.get(interceptor), InjectableInterceptor.class.getName()), create.getThis());
|
||||
ResultHandle childCtxHandle = create.invokeStaticMethod(MethodDescriptors.CREATIONAL_CTX_CHILD, create.getMethodParam(0));
|
||||
ResultHandle interceptorInstanceHandle = create.invokeInterfaceMethod(MethodDescriptors.INJECTABLE_REF_PROVIDER_GET, interceptorHandle,
|
||||
childCtxHandle);
|
||||
|
||||
ResultHandle interceptorInvocationHandle = create.invokeStaticMethod(MethodDescriptors.INTERCEPTOR_INVOCATION_POST_CONSTRUCT,
|
||||
interceptorHandle, interceptorInstanceHandle);
|
||||
|
||||
// postConstructs.add(InterceptorInvocation.postConstruct(interceptor,interceptor.get(CreationalContextImpl.child(ctx))))
|
||||
create.invokeInterfaceMethod(MethodDescriptors.LIST_ADD, postConstructsHandle, interceptorInvocationHandle);
|
||||
}
|
||||
@@ -601,14 +606,16 @@ public class BeanGenerator extends AbstractGenerator {
|
||||
if (!aroundConstructs.isEmpty()) {
|
||||
// aroundConstructs = new ArrayList<InterceptorInvocation>()
|
||||
aroundConstructsHandle = create.newInstance(MethodDescriptor.ofConstructor(ArrayList.class));
|
||||
for (InterceptorInfo interceptor : aroundConstructs) {
|
||||
for (InterceptorInfo interceptor : aroundConstructs.interceptors) {
|
||||
ResultHandle interceptorHandle = create.readInstanceField(FieldDescriptor.of(beanCreator.getClassName(),
|
||||
interceptorToProviderField.get(interceptor), InjectableInterceptor.class.getName()), create.getThis());
|
||||
ResultHandle childCtxHandle = create.invokeStaticMethod(MethodDescriptors.CREATIONAL_CTX_CHILD, create.getMethodParam(0));
|
||||
ResultHandle interceptorInstanceHandle = create.invokeInterfaceMethod(MethodDescriptors.INJECTABLE_REF_PROVIDER_GET, interceptorHandle,
|
||||
childCtxHandle);
|
||||
|
||||
ResultHandle interceptorInvocationHandle = create.invokeStaticMethod(MethodDescriptors.INTERCEPTOR_INVOCATION_AROUND_CONSTRUCT,
|
||||
interceptorHandle, interceptorInstanceHandle);
|
||||
|
||||
// aroundConstructs.add(InterceptorInvocation.aroundConstruct(interceptor,interceptor.get(CreationalContextImpl.child(ctx))))
|
||||
create.invokeInterfaceMethod(MethodDescriptors.LIST_ADD, aroundConstructsHandle, interceptorInvocationHandle);
|
||||
}
|
||||
@@ -616,7 +623,8 @@ public class BeanGenerator extends AbstractGenerator {
|
||||
}
|
||||
|
||||
// AroundConstruct lifecycle callback interceptors
|
||||
if (!bean.getLifecycleInterceptors(InterceptionType.AROUND_CONSTRUCT).isEmpty()) {
|
||||
InterceptionInfo aroundConstructs = bean.getLifecycleInterceptors(InterceptionType.AROUND_CONSTRUCT);
|
||||
if (!aroundConstructs.isEmpty()) {
|
||||
Optional<Injection> constructorInjection = bean.getConstructorInjection();
|
||||
ResultHandle constructorHandle;
|
||||
if (constructorInjection.isPresent()) {
|
||||
@@ -648,15 +656,21 @@ public class BeanGenerator extends AbstractGenerator {
|
||||
ResultHandle retHandle = newInstanceHandle(bean, beanCreator, funcBytecode, create, providerTypeName, baseName, providerHandles,
|
||||
reflectionRegistration);
|
||||
funcBytecode.returnValue(retHandle);
|
||||
// Interceptor bindings
|
||||
ResultHandle bindingsHandle = create.newInstance(MethodDescriptor.ofConstructor(HashSet.class));
|
||||
for (AnnotationInstance binding : aroundConstructs.bindings) {
|
||||
// Create annotation literals first
|
||||
ClassInfo bindingClass = bean.getDeployment().getInterceptorBinding(binding.name());
|
||||
String literalType = annotationLiterals.process(classOutput, bindingClass, binding, Types.getPackageName(beanCreator.getClassName()));
|
||||
create.invokeInterfaceMethod(MethodDescriptors.SET_ADD, bindingsHandle, create.newInstance(MethodDescriptor.ofConstructor(literalType)));
|
||||
}
|
||||
|
||||
// InvocationContextImpl.aroundConstruct(constructor,aroundConstructs,forward).proceed()
|
||||
ResultHandle invocationContextHandle = create.invokeStaticMethod(MethodDescriptor.ofMethod(InvocationContextImpl.class, "aroundConstruct",
|
||||
InvocationContextImpl.class, Constructor.class, List.class, Supplier.class), constructorHandle, aroundConstructsHandle,
|
||||
func.getInstance());
|
||||
ResultHandle invocationContextHandle = create.invokeStaticMethod(MethodDescriptors.INVOCATION_CONTEXT_AROUND_CONSTRUCT, constructorHandle,
|
||||
aroundConstructsHandle, func.getInstance(), bindingsHandle);
|
||||
ExceptionTable tryCatch = create.addTryCatch();
|
||||
CatchBlockCreator exceptionCatch = tryCatch.addCatchClause(Exception.class);
|
||||
// throw new RuntimeException(e)
|
||||
// TODO existing exception param
|
||||
exceptionCatch.throwException(RuntimeException.class, "Error invoking aroundConstructs", exceptionCatch.getCaughtException());
|
||||
instanceHandle = create.invokeInterfaceMethod(MethodDescriptor.ofMethod(InvocationContext.class, "proceed", Object.class),
|
||||
invocationContextHandle);
|
||||
@@ -716,17 +730,25 @@ public class BeanGenerator extends AbstractGenerator {
|
||||
}
|
||||
|
||||
// PostConstruct lifecycle callback interceptors
|
||||
if (!bean.getLifecycleInterceptors(InterceptionType.POST_CONSTRUCT).isEmpty()) {
|
||||
InterceptionInfo postConstructs = bean.getLifecycleInterceptors(InterceptionType.POST_CONSTRUCT);
|
||||
if (!postConstructs.isEmpty()) {
|
||||
|
||||
// Interceptor bindings
|
||||
ResultHandle bindingsHandle = create.newInstance(MethodDescriptor.ofConstructor(HashSet.class));
|
||||
for (AnnotationInstance binding : postConstructs.bindings) {
|
||||
// Create annotation literals first
|
||||
ClassInfo bindingClass = bean.getDeployment().getInterceptorBinding(binding.name());
|
||||
String literalType = annotationLiterals.process(classOutput, bindingClass, binding, Types.getPackageName(beanCreator.getClassName()));
|
||||
create.invokeInterfaceMethod(MethodDescriptors.SET_ADD, bindingsHandle, create.newInstance(MethodDescriptor.ofConstructor(literalType)));
|
||||
}
|
||||
|
||||
// InvocationContextImpl.postConstruct(instance,postConstructs).proceed()
|
||||
ResultHandle invocationContextHandle = create.invokeStaticMethod(
|
||||
MethodDescriptor.ofMethod(InvocationContextImpl.class, "postConstruct", InvocationContextImpl.class, Object.class, List.class),
|
||||
instanceHandle, postConstructsHandle);
|
||||
ResultHandle invocationContextHandle = create.invokeStaticMethod(MethodDescriptors.INVOCATION_CONTEXT_POST_CONSTRUCT, instanceHandle,
|
||||
postConstructsHandle, bindingsHandle);
|
||||
|
||||
ExceptionTable tryCatch = create.addTryCatch();
|
||||
CatchBlockCreator exceptionCatch = tryCatch.addCatchClause(Exception.class);
|
||||
// throw new RuntimeException(e)
|
||||
// TODO existing exception param
|
||||
exceptionCatch.throwException(RuntimeException.class, "Error invoking postConstructs", exceptionCatch.getCaughtException());
|
||||
create.invokeInterfaceMethod(MethodDescriptor.ofMethod(InvocationContext.class, "proceed", Object.class), invocationContextHandle);
|
||||
tryCatch.complete();
|
||||
|
||||
@@ -44,9 +44,9 @@ class BeanInfo {
|
||||
|
||||
private final DisposerInfo disposer;
|
||||
|
||||
private Map<MethodInfo, List<InterceptorInfo>> interceptedMethods;
|
||||
private Map<MethodInfo, InterceptionInfo> interceptedMethods;
|
||||
|
||||
private Map<InterceptionType, List<InterceptorInfo>> lifecycleInterceptors;
|
||||
private Map<InterceptionType, InterceptionInfo> lifecycleInterceptors;
|
||||
|
||||
private final Integer alternativePriority;
|
||||
|
||||
@@ -159,12 +159,12 @@ class BeanInfo {
|
||||
return injections.isEmpty() ? Optional.empty() : injections.stream().filter(i -> i.isConstructor()).findAny();
|
||||
}
|
||||
|
||||
Map<MethodInfo, List<InterceptorInfo>> getInterceptedMethods() {
|
||||
Map<MethodInfo, InterceptionInfo> getInterceptedMethods() {
|
||||
return interceptedMethods;
|
||||
}
|
||||
|
||||
List<InterceptorInfo> getLifecycleInterceptors(InterceptionType interceptionType) {
|
||||
return lifecycleInterceptors.containsKey(interceptionType) ? lifecycleInterceptors.get(interceptionType) : Collections.emptyList();
|
||||
InterceptionInfo getLifecycleInterceptors(InterceptionType interceptionType) {
|
||||
return lifecycleInterceptors.containsKey(interceptionType) ? lifecycleInterceptors.get(interceptionType) : InterceptionInfo.EMPTY;
|
||||
}
|
||||
|
||||
boolean hasLifecycleInterceptors() {
|
||||
@@ -193,11 +193,11 @@ class BeanInfo {
|
||||
*/
|
||||
List<InterceptorInfo> getBoundInterceptors() {
|
||||
List<InterceptorInfo> bound = new ArrayList<>();
|
||||
for (List<InterceptorInfo> interceptors : lifecycleInterceptors.values()) {
|
||||
bound.addAll(interceptors);
|
||||
for (InterceptionInfo interception : lifecycleInterceptors.values()) {
|
||||
bound.addAll(interception.interceptors);
|
||||
}
|
||||
if (!interceptedMethods.isEmpty()) {
|
||||
bound.addAll(interceptedMethods.values().stream().flatMap(list -> list.stream()).collect(Collectors.toList()));
|
||||
bound.addAll(interceptedMethods.values().stream().map(m -> m.interceptors).flatMap(list -> list.stream()).collect(Collectors.toList()));
|
||||
}
|
||||
return bound.isEmpty() ? Collections.emptyList() : bound.stream().distinct().sorted().collect(Collectors.toList());
|
||||
}
|
||||
@@ -241,9 +241,9 @@ class BeanInfo {
|
||||
}
|
||||
}
|
||||
|
||||
private Map<MethodInfo, List<InterceptorInfo>> initInterceptedMethods() {
|
||||
private Map<MethodInfo, InterceptionInfo> initInterceptedMethods() {
|
||||
if (!isInterceptor() && isClassBean()) {
|
||||
Map<MethodInfo, List<InterceptorInfo>> interceptedMethods = new HashMap<>();
|
||||
Map<MethodInfo, InterceptionInfo> interceptedMethods = new HashMap<>();
|
||||
Map<MethodKey, Set<AnnotationInstance>> candidates = new HashMap<>();
|
||||
// TODO interceptor bindings are transitive!!!
|
||||
|
||||
@@ -260,7 +260,7 @@ class BeanInfo {
|
||||
for (Entry<MethodKey, Set<AnnotationInstance>> entry : candidates.entrySet()) {
|
||||
List<InterceptorInfo> interceptors = beanDeployment.getInterceptorResolver().resolve(InterceptionType.AROUND_INVOKE, entry.getValue());
|
||||
if (!interceptors.isEmpty()) {
|
||||
interceptedMethods.put(entry.getKey().method, interceptors);
|
||||
interceptedMethods.put(entry.getKey().method, new InterceptionInfo(interceptors, entry.getValue()));
|
||||
}
|
||||
}
|
||||
return interceptedMethods;
|
||||
@@ -269,9 +269,9 @@ class BeanInfo {
|
||||
}
|
||||
}
|
||||
|
||||
private Map<InterceptionType, List<InterceptorInfo>> initLifecycleInterceptors() {
|
||||
private Map<InterceptionType, InterceptionInfo> initLifecycleInterceptors() {
|
||||
if (!isInterceptor() && isClassBean()) {
|
||||
Map<InterceptionType, List<InterceptorInfo>> lifecycleInterceptors = new HashMap<>();
|
||||
Map<InterceptionType, InterceptionInfo> lifecycleInterceptors = new HashMap<>();
|
||||
Set<AnnotationInstance> classLevelBindings = new HashSet<>();
|
||||
addClassLevelBindings(target.asClass(), classLevelBindings);
|
||||
putLifecycleInterceptors(lifecycleInterceptors, classLevelBindings, InterceptionType.POST_CONSTRUCT);
|
||||
@@ -283,11 +283,11 @@ class BeanInfo {
|
||||
}
|
||||
}
|
||||
|
||||
private void putLifecycleInterceptors(Map<InterceptionType, List<InterceptorInfo>> lifecycleInterceptors, Set<AnnotationInstance> classLevelBindings,
|
||||
private void putLifecycleInterceptors(Map<InterceptionType, InterceptionInfo> lifecycleInterceptors, Set<AnnotationInstance> classLevelBindings,
|
||||
InterceptionType interceptionType) {
|
||||
List<InterceptorInfo> interceptors = beanDeployment.getInterceptorResolver().resolve(interceptionType, classLevelBindings);
|
||||
if (!interceptors.isEmpty()) {
|
||||
lifecycleInterceptors.put(interceptionType, interceptors);
|
||||
lifecycleInterceptors.put(interceptionType, new InterceptionInfo(interceptors, classLevelBindings));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -303,6 +303,25 @@ class BeanInfo {
|
||||
}
|
||||
}
|
||||
|
||||
static class InterceptionInfo {
|
||||
|
||||
static final InterceptionInfo EMPTY = new InterceptionInfo(Collections.emptyList(), Collections.emptySet());
|
||||
|
||||
final List<InterceptorInfo> interceptors;
|
||||
|
||||
final Set<AnnotationInstance> bindings;
|
||||
|
||||
InterceptionInfo(List<InterceptorInfo> interceptors, Set<AnnotationInstance> bindings) {
|
||||
this.interceptors = interceptors;
|
||||
this.bindings = bindings;
|
||||
}
|
||||
|
||||
boolean isEmpty() {
|
||||
return interceptors.isEmpty();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getType() + " bean [types=" + types + ", qualifiers=" + qualifiers + ", target=" + target + "]";
|
||||
|
||||
@@ -74,19 +74,18 @@ public class BeanProcessor {
|
||||
BeanDeployment beanDeployment = new BeanDeployment(new IndexWrapper(index), additionalBeanDefiningAnnotations, annotationTransformers);
|
||||
beanDeployment.init();
|
||||
|
||||
BeanGenerator beanGenerator = new BeanGenerator();
|
||||
AnnotationLiteralProcessor annotationLiterals = new AnnotationLiteralProcessor(name, sharedAnnotationLiterals);
|
||||
BeanGenerator beanGenerator = new BeanGenerator(annotationLiterals);
|
||||
ClientProxyGenerator clientProxyGenerator = new ClientProxyGenerator();
|
||||
InterceptorGenerator interceptorGenerator = new InterceptorGenerator();
|
||||
SubclassGenerator subclassGenerator = new SubclassGenerator();
|
||||
ObserverGenerator observerGenerator = new ObserverGenerator();
|
||||
InterceptorGenerator interceptorGenerator = new InterceptorGenerator(annotationLiterals);
|
||||
SubclassGenerator subclassGenerator = new SubclassGenerator(annotationLiterals);
|
||||
ObserverGenerator observerGenerator = new ObserverGenerator(annotationLiterals);
|
||||
AnnotationLiteralGenerator annotationLiteralsGenerator = new AnnotationLiteralGenerator();
|
||||
|
||||
Map<BeanInfo, String> beanToGeneratedName = new HashMap<>();
|
||||
Map<ObserverInfo, String> observerToGeneratedName = new HashMap<>();
|
||||
Map<InterceptorInfo, String> interceptorToGeneratedName = new HashMap<>();
|
||||
|
||||
AnnotationLiteralProcessor annotationLiterals = new AnnotationLiteralProcessor(name, sharedAnnotationLiterals);
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
List<Resource> resources = new ArrayList<>();
|
||||
|
||||
@@ -103,7 +102,7 @@ public class BeanProcessor {
|
||||
|
||||
// Generate beans
|
||||
for (BeanInfo bean : beanDeployment.getBeans()) {
|
||||
for (Resource resource : beanGenerator.generate(bean, annotationLiterals, reflectionRegistration)) {
|
||||
for (Resource resource : beanGenerator.generate(bean, reflectionRegistration)) {
|
||||
resources.add(resource);
|
||||
if (SpecialType.BEAN.equals(resource.getSpecialType())) {
|
||||
if (bean.getScope().isNormal()) {
|
||||
@@ -120,7 +119,7 @@ public class BeanProcessor {
|
||||
|
||||
// Generate observers
|
||||
for (ObserverInfo observer : beanDeployment.getObservers()) {
|
||||
for (Resource resource : observerGenerator.generate(observer, annotationLiterals, reflectionRegistration)) {
|
||||
for (Resource resource : observerGenerator.generate(observer, reflectionRegistration)) {
|
||||
resources.add(resource);
|
||||
if (SpecialType.OBSERVER.equals(resource.getSpecialType())) {
|
||||
observerToGeneratedName.put(observer, resource.getName());
|
||||
|
||||
@@ -54,6 +54,7 @@ final class DotNames {
|
||||
static final DotName ALTERNATIVE = DotName.createSimple(Alternative.class.getName());
|
||||
static final DotName STEREOTYPE = DotName.createSimple(Stereotype.class.getName());
|
||||
static final DotName TYPED = DotName.createSimple(Typed.class.getName());
|
||||
static final DotName CLASS = DotName.createSimple(Class.class.getName());
|
||||
|
||||
private DotNames() {
|
||||
}
|
||||
|
||||
@@ -40,6 +40,14 @@ public class InterceptorGenerator extends BeanGenerator {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(InterceptorGenerator.class);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param annotationLiterals
|
||||
*/
|
||||
public InterceptorGenerator(AnnotationLiteralProcessor annotationLiterals) {
|
||||
super(annotationLiterals);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param interceptor bean
|
||||
@@ -75,8 +83,9 @@ public class InterceptorGenerator extends BeanGenerator {
|
||||
|
||||
createProviderFields(interceptorCreator, interceptor, injectionPointToProviderField, interceptorToProviderField);
|
||||
createConstructor(classOutput, interceptorCreator, interceptor, baseName, injectionPointToProviderField, interceptorToProviderField,
|
||||
annotationLiterals, bindings.getFieldDescriptor());
|
||||
createCreate(interceptorCreator, interceptor, providerTypeName, baseName, injectionPointToProviderField, interceptorToProviderField, reflectionRegistration);
|
||||
bindings.getFieldDescriptor());
|
||||
createCreate(classOutput, interceptorCreator, interceptor, providerTypeName, baseName, injectionPointToProviderField, interceptorToProviderField,
|
||||
reflectionRegistration);
|
||||
createGet(interceptor, interceptorCreator, providerTypeName);
|
||||
createGetTypes(interceptorCreator, beanTypes.getFieldDescriptor());
|
||||
// Interceptors are always @Dependent and have always default qualifiers
|
||||
@@ -93,8 +102,7 @@ public class InterceptorGenerator extends BeanGenerator {
|
||||
}
|
||||
|
||||
protected void createConstructor(ClassOutput classOutput, ClassCreator creator, InterceptorInfo interceptor, String baseName,
|
||||
Map<InjectionPointInfo, String> injectionPointToProviderField, Map<InterceptorInfo, String> interceptorToProviderField,
|
||||
AnnotationLiteralProcessor annotationLiterals, FieldDescriptor bindings) {
|
||||
Map<InjectionPointInfo, String> injectionPointToProviderField, Map<InterceptorInfo, String> interceptorToProviderField, FieldDescriptor bindings) {
|
||||
|
||||
MethodCreator constructor = initConstructor(classOutput, creator, interceptor, baseName, injectionPointToProviderField, interceptorToProviderField,
|
||||
annotationLiterals);
|
||||
@@ -107,8 +115,7 @@ public class InterceptorGenerator extends BeanGenerator {
|
||||
// Create annotation literal first
|
||||
ClassInfo bindingClass = interceptor.getDeployment().getInterceptorBinding(bindingAnnotation.name());
|
||||
String literalType = annotationLiterals.process(classOutput, bindingClass, bindingAnnotation, Types.getPackageName(creator.getClassName()));
|
||||
constructor.invokeInterfaceMethod(MethodDescriptors.SET_ADD, bindingsHandle,
|
||||
constructor.newInstance(MethodDescriptor.ofConstructor(literalType)));
|
||||
constructor.invokeInterfaceMethod(MethodDescriptors.SET_ADD, bindingsHandle, constructor.newInstance(MethodDescriptor.ofConstructor(literalType)));
|
||||
}
|
||||
constructor.writeInstanceField(bindings, constructor.getThis(), bindingsHandle);
|
||||
constructor.returnValue(null);
|
||||
@@ -171,7 +178,8 @@ public class InterceptorGenerator extends BeanGenerator {
|
||||
intercept.returnValue(intercept.loadNull());
|
||||
}
|
||||
|
||||
private void addIntercept(MethodCreator intercept, MethodInfo interceptorMethod, InterceptionType interceptionType, String providerTypeName, ReflectionRegistration reflectionRegistration) {
|
||||
private void addIntercept(MethodCreator intercept, MethodInfo interceptorMethod, InterceptionType interceptionType, String providerTypeName,
|
||||
ReflectionRegistration reflectionRegistration) {
|
||||
if (interceptorMethod != null) {
|
||||
ResultHandle enumValue = intercept
|
||||
.readStaticField(FieldDescriptor.of(InterceptionType.class.getName(), interceptionType.name(), InterceptionType.class.getName()));
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
package org.jboss.protean.arc.processor;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import javax.enterprise.context.spi.CreationalContext;
|
||||
import javax.enterprise.inject.spi.EventContext;
|
||||
@@ -14,6 +17,7 @@ import org.jboss.protean.arc.CreationalContextImpl;
|
||||
import org.jboss.protean.arc.InjectableBean;
|
||||
import org.jboss.protean.arc.InjectableInterceptor;
|
||||
import org.jboss.protean.arc.InjectableReferenceProvider;
|
||||
import org.jboss.protean.arc.InvocationContextImpl;
|
||||
import org.jboss.protean.arc.InvocationContextImpl.InterceptorInvocation;
|
||||
import org.jboss.protean.arc.Reflections;
|
||||
import org.jboss.protean.gizmo.MethodDescriptor;
|
||||
@@ -72,6 +76,18 @@ final class MethodDescriptors {
|
||||
|
||||
static final MethodDescriptor EVENT_CONTEXT_GET_METADATA = MethodDescriptor.ofMethod(EventContext.class, "getMetadata", EventMetadata.class);
|
||||
|
||||
static final MethodDescriptor INVOCATION_CONTEXT_AROUND_INVOKE = MethodDescriptor.ofMethod(InvocationContextImpl.class, "aroundInvoke",
|
||||
InvocationContextImpl.class, Object.class, Method.class, Object[].class, List.class, Function.class, Set.class);
|
||||
|
||||
static final MethodDescriptor INVOCATION_CONTEXT_AROUND_CONSTRUCT = MethodDescriptor.ofMethod(InvocationContextImpl.class, "aroundConstruct",
|
||||
InvocationContextImpl.class, Constructor.class, List.class, Supplier.class, Set.class);
|
||||
|
||||
static final MethodDescriptor INVOCATION_CONTEXT_POST_CONSTRUCT = MethodDescriptor.ofMethod(InvocationContextImpl.class, "postConstruct",
|
||||
InvocationContextImpl.class, Object.class, List.class, Set.class);
|
||||
|
||||
static final MethodDescriptor INVOCATION_CONTEXT_PRE_DESTROY = MethodDescriptor.ofMethod(InvocationContextImpl.class, "preDestroy",
|
||||
InvocationContextImpl.class, Object.class, List.class, Set.class);
|
||||
|
||||
private MethodDescriptors() {
|
||||
}
|
||||
|
||||
|
||||
@@ -51,13 +51,22 @@ public class ObserverGenerator extends AbstractGenerator {
|
||||
|
||||
private static final AtomicInteger OBSERVER_INDEX = new AtomicInteger();
|
||||
|
||||
private final AnnotationLiteralProcessor annotationLiterals;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param annotationLiterals
|
||||
*/
|
||||
public ObserverGenerator(AnnotationLiteralProcessor annotationLiterals) {
|
||||
this.annotationLiterals = annotationLiterals;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param observer
|
||||
* @param annotationLiterals
|
||||
* @return a collection of resources
|
||||
*/
|
||||
Collection<Resource> generate(ObserverInfo observer, AnnotationLiteralProcessor annotationLiterals, ReflectionRegistration reflectionRegistration) {
|
||||
Collection<Resource> generate(ObserverInfo observer, ReflectionRegistration reflectionRegistration) {
|
||||
|
||||
ClassInfo declaringClass = observer.getObserverMethod().declaringClass();
|
||||
String declaringClassBase;
|
||||
|
||||
@@ -7,6 +7,7 @@ import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
@@ -19,6 +20,7 @@ import javax.enterprise.context.spi.CreationalContext;
|
||||
import javax.enterprise.inject.spi.InterceptionType;
|
||||
import javax.interceptor.InvocationContext;
|
||||
|
||||
import org.jboss.jandex.AnnotationInstance;
|
||||
import org.jboss.jandex.ClassInfo;
|
||||
import org.jboss.jandex.DotName;
|
||||
import org.jboss.jandex.MethodInfo;
|
||||
@@ -26,14 +28,15 @@ import org.jboss.jandex.Type;
|
||||
import org.jboss.protean.arc.CreationalContextImpl;
|
||||
import org.jboss.protean.arc.InjectableInterceptor;
|
||||
import org.jboss.protean.arc.InjectableReferenceProvider;
|
||||
import org.jboss.protean.arc.InvocationContextImpl;
|
||||
import org.jboss.protean.arc.InvocationContextImpl.InterceptorInvocation;
|
||||
import org.jboss.protean.arc.Reflections;
|
||||
import org.jboss.protean.arc.Subclass;
|
||||
import org.jboss.protean.arc.processor.BeanInfo.InterceptionInfo;
|
||||
import org.jboss.protean.arc.processor.ResourceOutput.Resource;
|
||||
import org.jboss.protean.gizmo.BytecodeCreator;
|
||||
import org.jboss.protean.gizmo.CatchBlockCreator;
|
||||
import org.jboss.protean.gizmo.ClassCreator;
|
||||
import org.jboss.protean.gizmo.ClassOutput;
|
||||
import org.jboss.protean.gizmo.DescriptorUtils;
|
||||
import org.jboss.protean.gizmo.ExceptionTable;
|
||||
import org.jboss.protean.gizmo.FieldCreator;
|
||||
@@ -55,6 +58,16 @@ public class SubclassGenerator extends AbstractGenerator {
|
||||
return DotNames.packageName(providerTypeName).replace(".", "/") + "/" + baseName + SUBCLASS_SUFFIX;
|
||||
}
|
||||
|
||||
private final AnnotationLiteralProcessor annotationLiterals;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param annotationLiterals
|
||||
*/
|
||||
public SubclassGenerator(AnnotationLiteralProcessor annotationLiterals) {
|
||||
this.annotationLiterals = annotationLiterals;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param bean
|
||||
@@ -75,14 +88,15 @@ public class SubclassGenerator extends AbstractGenerator {
|
||||
ClassCreator subclass = ClassCreator.builder().classOutput(classOutput).className(generatedName).superClass(providerTypeName).interfaces(Subclass.class)
|
||||
.build();
|
||||
|
||||
FieldDescriptor preDestroyField = createConstructor(bean, subclass, providerTypeName, reflectionRegistration);
|
||||
createDestroy(subclass, preDestroyField);
|
||||
FieldDescriptor preDestroyField = createConstructor(classOutput, bean, subclass, providerTypeName, reflectionRegistration);
|
||||
createDestroy(classOutput, bean, subclass, preDestroyField);
|
||||
|
||||
subclass.close();
|
||||
return classOutput.getResources();
|
||||
}
|
||||
|
||||
protected FieldDescriptor createConstructor(BeanInfo bean, ClassCreator subclass, String providerTypeName, ReflectionRegistration reflectionRegistration) {
|
||||
protected FieldDescriptor createConstructor(ClassOutput classOutput, BeanInfo bean, ClassCreator subclass, String providerTypeName,
|
||||
ReflectionRegistration reflectionRegistration) {
|
||||
|
||||
List<String> parameterTypes = new ArrayList<>();
|
||||
|
||||
@@ -122,7 +136,7 @@ public class SubclassGenerator extends AbstractGenerator {
|
||||
|
||||
// PreDestroy interceptors
|
||||
FieldCreator preDestroysField = null;
|
||||
List<InterceptorInfo> preDestroys = bean.getLifecycleInterceptors(InterceptionType.PRE_DESTROY);
|
||||
InterceptionInfo preDestroys = bean.getLifecycleInterceptors(InterceptionType.PRE_DESTROY);
|
||||
if (!preDestroys.isEmpty()) {
|
||||
// private final List<InvocationContextImpl.InterceptorInvocation> preDestroys
|
||||
preDestroysField = subclass.getFieldCreator("preDestroys", DescriptorUtils.extToInt(ArrayList.class.getName()))
|
||||
@@ -130,7 +144,7 @@ public class SubclassGenerator extends AbstractGenerator {
|
||||
// preDestroys = new ArrayList<>()
|
||||
constructor.writeInstanceField(preDestroysField.getFieldDescriptor(), constructor.getThis(),
|
||||
constructor.newInstance(MethodDescriptor.ofConstructor(ArrayList.class)));
|
||||
for (InterceptorInfo interceptor : preDestroys) {
|
||||
for (InterceptorInfo interceptor : preDestroys.interceptors) {
|
||||
// preDestroys.add(InvocationContextImpl.InterceptorInvocation.preDestroy(provider1,provider1.get(CreationalContextImpl.child(ctx))))
|
||||
ResultHandle creationalContext = constructor.invokeStaticMethod(
|
||||
MethodDescriptor.ofMethod(CreationalContextImpl.class, "child", CreationalContextImpl.class, CreationalContext.class),
|
||||
@@ -148,8 +162,7 @@ public class SubclassGenerator extends AbstractGenerator {
|
||||
|
||||
// Init intercepted methods and interceptor chains
|
||||
// private final Map<String, List<InvocationContextImpl.InterceptorInvocation>> interceptorChains
|
||||
FieldCreator interceptorChainsField = subclass.getFieldCreator("interceptorChains", DescriptorUtils.extToInt(Map.class.getName()))
|
||||
.setModifiers(ACC_PRIVATE | ACC_FINAL);
|
||||
FieldCreator interceptorChainsField = subclass.getFieldCreator("interceptorChains", Map.class.getName()).setModifiers(ACC_PRIVATE | ACC_FINAL);
|
||||
// interceptorChains = new HashMap<>()
|
||||
constructor.writeInstanceField(interceptorChainsField.getFieldDescriptor(), constructor.getThis(),
|
||||
constructor.newInstance(MethodDescriptor.ofConstructor(HashMap.class)));
|
||||
@@ -161,7 +174,7 @@ public class SubclassGenerator extends AbstractGenerator {
|
||||
ResultHandle methodsHandle = constructor.readInstanceField(methodsField.getFieldDescriptor(), constructor.getThis());
|
||||
|
||||
int methodIdx = 1;
|
||||
for (Entry<MethodInfo, List<InterceptorInfo>> entry : bean.getInterceptedMethods().entrySet()) {
|
||||
for (Entry<MethodInfo, InterceptionInfo> entry : bean.getInterceptedMethods().entrySet()) {
|
||||
String methodId = "m" + methodIdx++;
|
||||
MethodInfo method = entry.getKey();
|
||||
ResultHandle methodIdHandle = constructor.load(methodId);
|
||||
@@ -169,7 +182,8 @@ public class SubclassGenerator extends AbstractGenerator {
|
||||
// First create interceptor chains
|
||||
// List<InvocationContextImpl.InterceptorInvocation> m1Chain = new ArrayList<>()
|
||||
ResultHandle chainHandle = constructor.newInstance(MethodDescriptor.ofConstructor(ArrayList.class));
|
||||
for (InterceptorInfo interceptor : entry.getValue()) {
|
||||
InterceptionInfo interceptedMethod = entry.getValue();
|
||||
for (InterceptorInfo interceptor : interceptedMethod.interceptors) {
|
||||
// m1Chain.add(InvocationContextImpl.InterceptorInvocation.aroundInvoke(p3,p3.get(CreationalContextImpl.child(ctx))))
|
||||
ResultHandle creationalContext = constructor.invokeStaticMethod(
|
||||
MethodDescriptor.ofMethod(CreationalContextImpl.class, "child", CreationalContextImpl.class, CreationalContext.class),
|
||||
@@ -208,16 +222,16 @@ public class SubclassGenerator extends AbstractGenerator {
|
||||
reflectionRegistration.registerMethod(method);
|
||||
|
||||
// Finally create the forwarding method
|
||||
createForwardingMethod(method, methodId, subclass, providerTypeName, interceptorChainsField.getFieldDescriptor(),
|
||||
methodsField.getFieldDescriptor());
|
||||
createForwardingMethod(classOutput, bean, method, methodId, subclass, providerTypeName, interceptorChainsField.getFieldDescriptor(),
|
||||
methodsField.getFieldDescriptor(), interceptedMethod);
|
||||
}
|
||||
|
||||
constructor.returnValue(null);
|
||||
return preDestroysField != null ? preDestroysField.getFieldDescriptor() : null;
|
||||
}
|
||||
|
||||
private void createForwardingMethod(MethodInfo method, String methodId, ClassCreator subclass, String providerTypeName,
|
||||
FieldDescriptor interceptorChainsField, FieldDescriptor methodsField) {
|
||||
private void createForwardingMethod(ClassOutput classOutput, BeanInfo bean, MethodInfo method, String methodId, ClassCreator subclass,
|
||||
String providerTypeName, FieldDescriptor interceptorChainsField, FieldDescriptor methodsField, InterceptionInfo interceptedMethod) {
|
||||
|
||||
MethodCreator forwardMethod = subclass.getMethodCreator(MethodDescriptor.of(method));
|
||||
|
||||
@@ -259,10 +273,18 @@ public class SubclassGenerator extends AbstractGenerator {
|
||||
forwardMethod.readInstanceField(methodsField, forwardMethod.getThis()), methodIdHandle);
|
||||
ResultHandle interceptedChainHandle = forwardMethod.invokeInterfaceMethod(MethodDescriptors.MAP_GET,
|
||||
forwardMethod.readInstanceField(interceptorChainsField, forwardMethod.getThis()), methodIdHandle);
|
||||
ResultHandle invocationContext = forwardMethod.invokeStaticMethod(
|
||||
MethodDescriptor.ofMethod(InvocationContextImpl.class, "aroundInvoke", InvocationContextImpl.class, Object.class, Method.class, Object[].class,
|
||||
List.class, Function.class),
|
||||
forwardMethod.getThis(), interceptedMethodHandle, paramsHandle, interceptedChainHandle, func.getInstance());
|
||||
// Interceptor bindings
|
||||
ResultHandle bindingsHandle = forwardMethod.newInstance(MethodDescriptor.ofConstructor(HashSet.class));
|
||||
for (AnnotationInstance binding : interceptedMethod.bindings) {
|
||||
// Create annotation literals first
|
||||
ClassInfo bindingClass = bean.getDeployment().getInterceptorBinding(binding.name());
|
||||
String literalType = annotationLiterals.process(classOutput, bindingClass, binding, Types.getPackageName(subclass.getClassName()));
|
||||
forwardMethod.invokeInterfaceMethod(MethodDescriptors.SET_ADD, bindingsHandle,
|
||||
forwardMethod.newInstance(MethodDescriptor.ofConstructor(literalType)));
|
||||
}
|
||||
|
||||
ResultHandle invocationContext = forwardMethod.invokeStaticMethod(MethodDescriptors.INVOCATION_CONTEXT_AROUND_INVOKE, forwardMethod.getThis(),
|
||||
interceptedMethodHandle, paramsHandle, interceptedChainHandle, func.getInstance(), bindingsHandle);
|
||||
// InvocationContext.proceed()
|
||||
ResultHandle ret = forwardMethod.invokeInterfaceMethod(MethodDescriptor.ofMethod(InvocationContext.class, "proceed", Object.class), invocationContext);
|
||||
forwardMethod.returnValue(superResult != null ? ret : null);
|
||||
@@ -271,28 +293,41 @@ public class SubclassGenerator extends AbstractGenerator {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param classOutput
|
||||
* @param bean
|
||||
* @param subclass
|
||||
* @param preDestroysField
|
||||
* @see Subclass#destroy()
|
||||
*/
|
||||
protected void createDestroy(ClassCreator subclass, FieldDescriptor preDestroysField) {
|
||||
protected void createDestroy(ClassOutput classOutput, BeanInfo bean, ClassCreator subclass, FieldDescriptor preDestroysField) {
|
||||
if (preDestroysField != null) {
|
||||
MethodCreator destroyMethod = subclass.getMethodCreator(MethodDescriptor.ofMethod(Subclass.class, "destroy", void.class));
|
||||
ResultHandle predestroysHandle = destroyMethod.readInstanceField(preDestroysField, destroyMethod.getThis());
|
||||
MethodCreator destroy = subclass.getMethodCreator(MethodDescriptor.ofMethod(Subclass.class, "destroy", void.class));
|
||||
ResultHandle predestroysHandle = destroy.readInstanceField(preDestroysField, destroy.getThis());
|
||||
|
||||
// Interceptor bindings
|
||||
ResultHandle bindingsHandle = destroy.newInstance(MethodDescriptor.ofConstructor(HashSet.class));
|
||||
for (AnnotationInstance binding : bean.getLifecycleInterceptors(InterceptionType.PRE_DESTROY).bindings) {
|
||||
// Create annotation literals first
|
||||
ClassInfo bindingClass = bean.getDeployment().getInterceptorBinding(binding.name());
|
||||
String literalType = annotationLiterals.process(classOutput, bindingClass, binding, Types.getPackageName(subclass.getClassName()));
|
||||
destroy.invokeInterfaceMethod(MethodDescriptors.SET_ADD, bindingsHandle, destroy.newInstance(MethodDescriptor.ofConstructor(literalType)));
|
||||
}
|
||||
|
||||
// try
|
||||
ExceptionTable tryCatch = destroyMethod.addTryCatch();
|
||||
ExceptionTable tryCatch = destroy.addTryCatch();
|
||||
// catch (Exception e)
|
||||
CatchBlockCreator exception = tryCatch.addCatchClause(Exception.class);
|
||||
// throw new RuntimeException(e)
|
||||
exception.throwException(RuntimeException.class, "Error destroying subclass", exception.getCaughtException());
|
||||
|
||||
// InvocationContextImpl.preDestroy(this,predestroys)
|
||||
ResultHandle invocationContext = destroyMethod.invokeStaticMethod(
|
||||
MethodDescriptor.ofMethod(InvocationContextImpl.class, "preDestroy", InvocationContextImpl.class, Object.class, List.class),
|
||||
destroyMethod.getThis(), predestroysHandle);
|
||||
ResultHandle invocationContext = destroy.invokeStaticMethod(MethodDescriptors.INVOCATION_CONTEXT_PRE_DESTROY, destroy.getThis(), predestroysHandle,
|
||||
bindingsHandle);
|
||||
|
||||
// InvocationContext.proceed()
|
||||
destroyMethod.invokeInterfaceMethod(MethodDescriptor.ofMethod(InvocationContext.class, "proceed", Object.class), invocationContext);
|
||||
destroy.invokeInterfaceMethod(MethodDescriptor.ofMethod(InvocationContext.class, "proceed", Object.class), invocationContext);
|
||||
tryCatch.complete();
|
||||
destroyMethod.returnValue(null);
|
||||
destroy.returnValue(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,9 +26,9 @@ public class BeanGeneratorTest {
|
||||
BeanDeployment deployment = new BeanDeployment(index, null, null);
|
||||
deployment.init();
|
||||
|
||||
BeanGenerator generator = new BeanGenerator();
|
||||
BeanGenerator generator = new BeanGenerator(new AnnotationLiteralProcessor(BeanProcessor.DEFAULT_NAME, true));
|
||||
|
||||
deployment.getBeans().forEach(bean -> generator.generate(bean, new AnnotationLiteralProcessor(BeanProcessor.DEFAULT_NAME, true), ReflectionRegistration.NOOP));
|
||||
deployment.getBeans().forEach(bean -> generator.generate(bean, ReflectionRegistration.NOOP));
|
||||
// TODO test generated bytecode
|
||||
}
|
||||
|
||||
@@ -39,9 +39,9 @@ public class BeanGeneratorTest {
|
||||
BeanDeployment deployment = new BeanDeployment(index, null, null);
|
||||
deployment.init();
|
||||
|
||||
BeanGenerator generator = new BeanGenerator();
|
||||
BeanGenerator generator = new BeanGenerator(new AnnotationLiteralProcessor(BeanProcessor.DEFAULT_NAME, true));
|
||||
|
||||
deployment.getBeans().forEach(bean -> generator.generate(bean, new AnnotationLiteralProcessor(BeanProcessor.DEFAULT_NAME, true), ReflectionRegistration.NOOP));
|
||||
deployment.getBeans().forEach(bean -> generator.generate(bean, ReflectionRegistration.NOOP));
|
||||
// TODO test generated bytecode
|
||||
}
|
||||
|
||||
|
||||
@@ -24,11 +24,11 @@ public class ClientProxyGeneratorTest {
|
||||
BeanDeployment deployment = new BeanDeployment(index, null, null);
|
||||
deployment.init();
|
||||
|
||||
BeanGenerator beanGenerator = new BeanGenerator();
|
||||
BeanGenerator beanGenerator = new BeanGenerator( new AnnotationLiteralProcessor(BeanProcessor.DEFAULT_NAME, true));
|
||||
ClientProxyGenerator proxyGenerator = new ClientProxyGenerator();
|
||||
|
||||
deployment.getBeans().stream().filter(bean -> bean.getScope().isNormal()).forEach(bean -> {
|
||||
for (Resource resource : beanGenerator.generate(bean, new AnnotationLiteralProcessor(BeanProcessor.DEFAULT_NAME, true), ReflectionRegistration.NOOP)) {
|
||||
for (Resource resource : beanGenerator.generate(bean, ReflectionRegistration.NOOP)) {
|
||||
proxyGenerator.generate(bean, resource.getFullyQualifiedName(), ReflectionRegistration.NOOP);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -36,9 +36,9 @@ public class InterceptorGeneratorTest {
|
||||
assertEquals(1, myInterceptor.getBindings().size());
|
||||
assertNotNull(myInterceptor.getAroundInvoke());
|
||||
|
||||
InterceptorGenerator generator = new InterceptorGenerator();
|
||||
InterceptorGenerator generator = new InterceptorGenerator(new AnnotationLiteralProcessor(BeanProcessor.DEFAULT_NAME, true));
|
||||
|
||||
deployment.getInterceptors().forEach(interceptor -> generator.generate(interceptor, new AnnotationLiteralProcessor(BeanProcessor.DEFAULT_NAME, true), ReflectionRegistration.NOOP));
|
||||
deployment.getInterceptors().forEach(interceptor -> generator.generate(interceptor, ReflectionRegistration.NOOP));
|
||||
// TODO test generated bytecode
|
||||
}
|
||||
|
||||
|
||||
@@ -33,11 +33,12 @@ public class SubclassGeneratorTest {
|
||||
BeanDeployment deployment = new BeanDeployment(index, null, null);
|
||||
deployment.init();
|
||||
|
||||
BeanGenerator beanGenerator = new BeanGenerator();
|
||||
SubclassGenerator generator = new SubclassGenerator();
|
||||
AnnotationLiteralProcessor annotationLiteralProcessor = new AnnotationLiteralProcessor(BeanProcessor.DEFAULT_NAME, true);
|
||||
BeanGenerator beanGenerator = new BeanGenerator(annotationLiteralProcessor);
|
||||
SubclassGenerator generator = new SubclassGenerator(annotationLiteralProcessor);
|
||||
BeanInfo simpleBean = deployment.getBeans().stream()
|
||||
.filter(b -> b.getTarget().asClass().name().equals(DotName.createSimple(SimpleBean.class.getName()))).findAny().get();
|
||||
for (Resource resource : beanGenerator.generate(simpleBean, new AnnotationLiteralProcessor(BeanProcessor.DEFAULT_NAME, true), ReflectionRegistration.NOOP)) {
|
||||
for (Resource resource : beanGenerator.generate(simpleBean, ReflectionRegistration.NOOP)) {
|
||||
generator.generate(simpleBean, resource.getFullyQualifiedName(), ReflectionRegistration.NOOP);
|
||||
}
|
||||
// TODO test generated bytecode
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
package org.jboss.protean.arc;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
@@ -19,6 +21,8 @@ import javax.interceptor.InvocationContext;
|
||||
*/
|
||||
public class InvocationContextImpl implements InvocationContext {
|
||||
|
||||
public static final String KEY_INTERCEPTOR_BINDINGS = "org.jboss.protean.arc.interceptorBindings";
|
||||
|
||||
/**
|
||||
*
|
||||
* @param target
|
||||
@@ -26,42 +30,46 @@ public class InvocationContextImpl implements InvocationContext {
|
||||
* @param args
|
||||
* @param chain
|
||||
* @param aroundInvokeForward
|
||||
* @param interceptorBindings
|
||||
* @return a new {@link javax.interceptor.AroundInvoke} invocation context
|
||||
*/
|
||||
public static InvocationContextImpl aroundInvoke(Object target, Method method, Object[] args, List<InterceptorInvocation> chain,
|
||||
Function<InvocationContext, Object> aroundInvokeForward) {
|
||||
return new InvocationContextImpl(target, method, null, args, chain, aroundInvokeForward, null);
|
||||
Function<InvocationContext, Object> aroundInvokeForward, Set<Annotation> interceptorBindings) {
|
||||
return new InvocationContextImpl(target, method, null, args, chain, aroundInvokeForward, null, interceptorBindings);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param target
|
||||
* @param chain
|
||||
* @param interceptorBindings
|
||||
* @return a new {@link javax.annotation.PostConstruct} invocation context
|
||||
*/
|
||||
public static InvocationContextImpl postConstruct(Object target, List<InterceptorInvocation> chain) {
|
||||
return new InvocationContextImpl(target, null, null, null, chain, null, null);
|
||||
public static InvocationContextImpl postConstruct(Object target, List<InterceptorInvocation> chain, Set<Annotation> interceptorBindings) {
|
||||
return new InvocationContextImpl(target, null, null, null, chain, null, null, interceptorBindings);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param target
|
||||
* @param chain
|
||||
* @param interceptorBindings
|
||||
* @return a new {@link javax.annotation.PreDestroy} invocation context
|
||||
*/
|
||||
public static InvocationContextImpl preDestroy(Object target, List<InterceptorInvocation> chain) {
|
||||
return new InvocationContextImpl(target, null, null, null, chain, null, null);
|
||||
public static InvocationContextImpl preDestroy(Object target, List<InterceptorInvocation> chain, Set<Annotation> interceptorBindings) {
|
||||
return new InvocationContextImpl(target, null, null, null, chain, null, null, interceptorBindings);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param target
|
||||
* @param chain
|
||||
* @param interceptorBindings
|
||||
* @return a new {@link javax.interceptor.AroundConstruct} invocation context
|
||||
*/
|
||||
public static InvocationContextImpl aroundConstruct(Constructor<?> constructor, List<InterceptorInvocation> chain,
|
||||
Supplier<Object> aroundConstructForward) {
|
||||
return new InvocationContextImpl(null, null, constructor, null, chain, null, aroundConstructForward);
|
||||
public static InvocationContextImpl aroundConstruct(Constructor<?> constructor, List<InterceptorInvocation> chain, Supplier<Object> aroundConstructForward,
|
||||
Set<Annotation> interceptorBindings) {
|
||||
return new InvocationContextImpl(null, null, constructor, null, chain, null, aroundConstructForward, interceptorBindings);
|
||||
}
|
||||
|
||||
private final AtomicReference<Object> target;
|
||||
@@ -82,24 +90,31 @@ public class InvocationContextImpl implements InvocationContext {
|
||||
|
||||
private final Supplier<Object> aroundConstructForward;
|
||||
|
||||
private final Set<Annotation> interceptorBindings;
|
||||
|
||||
/**
|
||||
* @param target
|
||||
* @param method
|
||||
* @param constructor
|
||||
* @param args
|
||||
* @param chain
|
||||
* @param aroundInvokeForward
|
||||
* @param aroundConstructForward
|
||||
* @param interceptorBindings
|
||||
*/
|
||||
InvocationContextImpl(Object target, Method method, Constructor<?> constructor, Object[] args, List<InterceptorInvocation> chain,
|
||||
Function<InvocationContext, Object> aroundInvokeForward, Supplier<Object> aroundConstructForward) {
|
||||
Function<InvocationContext, Object> aroundInvokeForward, Supplier<Object> aroundConstructForward, Set<Annotation> interceptorBindings) {
|
||||
this.target = new AtomicReference<>(target);
|
||||
this.method = method;
|
||||
this.constructor = constructor;
|
||||
this.args = args;
|
||||
this.contextData = new HashMap<>();
|
||||
this.position = 0;
|
||||
this.chain = chain;
|
||||
this.aroundInvokeForward = aroundInvokeForward;
|
||||
this.aroundConstructForward = aroundConstructForward;
|
||||
this.interceptorBindings = interceptorBindings;
|
||||
contextData = new HashMap<>();
|
||||
contextData.put(KEY_INTERCEPTOR_BINDINGS, interceptorBindings);
|
||||
}
|
||||
|
||||
boolean hasNextInterceptor() {
|
||||
@@ -192,6 +207,10 @@ public class InvocationContextImpl implements InvocationContext {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Set<Annotation> getInterceptorBindings() {
|
||||
return interceptorBindings;
|
||||
}
|
||||
|
||||
public static class InterceptorInvocation {
|
||||
|
||||
public static InterceptorInvocation aroundInvoke(InjectableInterceptor<?> interceptor, Object interceptorInstance) {
|
||||
|
||||
@@ -10,6 +10,8 @@ import javax.interceptor.AroundConstruct;
|
||||
import javax.interceptor.Interceptor;
|
||||
import javax.interceptor.InvocationContext;
|
||||
|
||||
import org.jboss.protean.arc.InvocationContextImpl;
|
||||
|
||||
@Lifecycle
|
||||
@Priority(1)
|
||||
@Interceptor
|
||||
@@ -21,16 +23,28 @@ public class LifecycleInterceptor {
|
||||
|
||||
@PostConstruct
|
||||
void simpleInit(InvocationContext ctx) {
|
||||
Object bindings = ctx.getContextData().get(InvocationContextImpl.KEY_INTERCEPTOR_BINDINGS);
|
||||
if (bindings == null) {
|
||||
throw new IllegalArgumentException("No bindings found");
|
||||
}
|
||||
POST_CONSTRUCTS.add(ctx.getTarget());
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
void simpleDestroy(InvocationContext ctx) {
|
||||
Object bindings = ctx.getContextData().get(InvocationContextImpl.KEY_INTERCEPTOR_BINDINGS);
|
||||
if (bindings == null) {
|
||||
throw new IllegalArgumentException("No bindings found");
|
||||
}
|
||||
PRE_DESTROYS.add(ctx.getTarget());
|
||||
}
|
||||
|
||||
@AroundConstruct
|
||||
void simpleAroundConstruct(InvocationContext ctx) throws Exception {
|
||||
Object bindings = ctx.getContextData().get(InvocationContextImpl.KEY_INTERCEPTOR_BINDINGS);
|
||||
if (bindings == null) {
|
||||
throw new IllegalArgumentException("No bindings found");
|
||||
}
|
||||
try {
|
||||
AROUND_CONSTRUCTS.add(ctx.getConstructor());
|
||||
ctx.proceed();
|
||||
|
||||
@@ -6,6 +6,8 @@ import javax.interceptor.AroundInvoke;
|
||||
import javax.interceptor.Interceptor;
|
||||
import javax.interceptor.InvocationContext;
|
||||
|
||||
import org.jboss.protean.arc.InvocationContextImpl;
|
||||
|
||||
@Simple
|
||||
@Priority(1)
|
||||
@Interceptor
|
||||
@@ -16,6 +18,10 @@ public class SimpleInterceptor {
|
||||
|
||||
@AroundInvoke
|
||||
Object mySuperCoolAroundInvoke(InvocationContext ctx) throws Exception {
|
||||
Object bindings = ctx.getContextData().get(InvocationContextImpl.KEY_INTERCEPTOR_BINDINGS);
|
||||
if (bindings == null) {
|
||||
throw new IllegalArgumentException("No bindings found");
|
||||
}
|
||||
return "" + counter.get() + ctx.proceed() + counter.incrementAndGet();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
package org.jboss.protean.arc.test.interceptors.bindings;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import javax.annotation.Priority;
|
||||
import javax.inject.Singleton;
|
||||
import javax.interceptor.AroundInvoke;
|
||||
import javax.interceptor.Interceptor;
|
||||
import javax.interceptor.InvocationContext;
|
||||
|
||||
import org.jboss.protean.arc.Arc;
|
||||
import org.jboss.protean.arc.ArcContainer;
|
||||
import org.jboss.protean.arc.InvocationContextImpl;
|
||||
import org.jboss.protean.arc.test.ArcTestContainer;
|
||||
import org.jboss.protean.arc.test.interceptors.Simple;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
public class InvocationContextBindingsTest {
|
||||
|
||||
@Rule
|
||||
public ArcTestContainer container = new ArcTestContainer(Simple.class, MyTransactional.class, SimpleBean.class, SimpleInterceptor.class);
|
||||
|
||||
@Test
|
||||
public void testInterception() {
|
||||
ArcContainer arc = Arc.container();
|
||||
SimpleBean simpleBean = arc.instance(SimpleBean.class).get();
|
||||
// [@org.jboss.protean.arc.test.interceptors.Simple(),
|
||||
// @org.jboss.protean.arc.test.interceptors.bindings.MyTransactional(value={java.lang.String.class})]::foo
|
||||
String ret = simpleBean.foo();
|
||||
assertTrue(ret.contains(Simple.class.getName()));
|
||||
assertTrue(ret.contains(MyTransactional.class.getName()));
|
||||
assertTrue(ret.contains(String.class.getName()));
|
||||
}
|
||||
|
||||
@Singleton
|
||||
static class SimpleBean {
|
||||
|
||||
@MyTransactional({ String.class })
|
||||
@Simple
|
||||
String foo() {
|
||||
return "foo";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Simple
|
||||
@MyTransactional
|
||||
@Priority(1)
|
||||
@Interceptor
|
||||
public static class SimpleInterceptor {
|
||||
|
||||
@AroundInvoke
|
||||
Object mySuperCoolAroundInvoke(InvocationContext ctx) throws Exception {
|
||||
Object bindings = ctx.getContextData().get(InvocationContextImpl.KEY_INTERCEPTOR_BINDINGS);
|
||||
if (bindings != null) {
|
||||
return bindings.toString() + "::" + ctx.proceed();
|
||||
}
|
||||
return ctx.proceed();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package org.jboss.protean.arc.test.interceptors.bindings;
|
||||
|
||||
import static java.lang.annotation.ElementType.METHOD;
|
||||
import static java.lang.annotation.ElementType.TYPE;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import javax.enterprise.util.Nonbinding;
|
||||
import javax.interceptor.InterceptorBinding;
|
||||
|
||||
@Target({ TYPE, METHOD })
|
||||
@Retention(RUNTIME)
|
||||
@Documented
|
||||
@InterceptorBinding
|
||||
public @interface MyTransactional {
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Nonbinding
|
||||
Class[] value() default {};
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user