Skip to content

Commit

Permalink
First shot at Invokable methods implementation in Weld
Browse files Browse the repository at this point in the history
  • Loading branch information
manovotn committed Aug 1, 2023
1 parent 151019b commit 313d464
Show file tree
Hide file tree
Showing 65 changed files with 2,293 additions and 5 deletions.
75 changes: 70 additions & 5 deletions impl/src/main/java/org/jboss/weld/bean/AbstractClassBean.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,25 +16,32 @@
*/
package org.jboss.weld.bean;

import java.util.Collections;
import java.util.List;
import java.util.Set;

import jakarta.enterprise.inject.spi.AnnotatedMethod;
import jakarta.enterprise.inject.spi.BeanAttributes;
import jakarta.enterprise.inject.spi.Decorator;
import jakarta.enterprise.inject.spi.InjectionPoint;
import jakarta.enterprise.inject.spi.InjectionTarget;
import jakarta.enterprise.inject.spi.Producer;

import jakarta.enterprise.invoke.Invokable;
import org.jboss.weld.annotated.enhanced.EnhancedAnnotatedType;
import org.jboss.weld.annotated.enhanced.MethodSignature;
import org.jboss.weld.annotated.enhanced.jlr.MethodSignatureImpl;
import org.jboss.weld.annotated.slim.SlimAnnotatedType;
import org.jboss.weld.bootstrap.BeanDeployerEnvironment;
import org.jboss.weld.interceptor.spi.model.InterceptionModel;
import org.jboss.weld.logging.BeanLogger;
import org.jboss.weld.manager.BeanManagerImpl;
import org.jboss.weld.metadata.cache.MetaAnnotationStore;
import org.jboss.weld.serialization.spi.BeanIdentifier;
import org.jboss.weld.util.Beans;

import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
* An abstract bean representation common for class-based beans
*
Expand All @@ -49,6 +56,8 @@ public abstract class AbstractClassBean<T> extends AbstractBean<T, Class<T>> imp
protected final SlimAnnotatedType<T> annotatedType;
protected volatile EnhancedAnnotatedType<T> enhancedAnnotatedItem;

protected Collection<AnnotatedMethod<? super T>> invokableMethods;

// Injection target for the bean
private InjectionTarget<T> producer;

Expand All @@ -63,6 +72,7 @@ protected AbstractClassBean(BeanAttributes<T> attributes, EnhancedAnnotatedType<
this.enhancedAnnotatedItem = type;
this.annotatedType = type.slim();
initType();
initInvokableMethods();
}

/**
Expand Down Expand Up @@ -172,4 +182,59 @@ public void setInjectionTarget(InjectionTarget<T> injectionTarget) {
public void setProducer(Producer<T> producer) {
throw new IllegalArgumentException("Class bean " + this + " requires an InjectionTarget but a Producer was provided instead " + producer);
}

private void initInvokableMethods() {
invokableMethods = new HashSet<>();
// this collection is used to detect overriden methods; return type checking should not be needed in this case
Collection<MethodSignature> encounteredMethods = new HashSet<>();
MetaAnnotationStore metaAnnotationStore = getBeanManager().getServices().get(MetaAnnotationStore.class);

EnhancedAnnotatedType<? super T> type = enhancedAnnotatedItem;
while (type != null) {
// inspect all class-level annotations and look for any invokable annotation
boolean hasClassLevelInvokableAnnotation = false;
for (Annotation an : type.getAnnotations()) {
if (isInvokableAnnotation(an.annotationType(), metaAnnotationStore)) {
hasClassLevelInvokableAnnotation = true;
break;
}
}

// iterate over all methods, if they belong to this type and either have the annotation or we know of a class
// level invokable annotation, we register them
for (AnnotatedMethod<? super T> method : type.getMethods()) {
if (!method.getDeclaringType().equals(type)) {
continue;
}
MethodSignature signature = MethodSignatureImpl.of(method);
if (!encounteredMethods.contains(signature) &&
(hasClassLevelInvokableAnnotation || method.getAnnotations().stream().anyMatch(a -> isInvokableAnnotation(a.annotationType(), metaAnnotationStore)))) {
invokableMethods.add(method);
}
encounteredMethods.add(signature);
}

// inspect super class in the same fashion
type = type.getEnhancedSuperclass();
}
}

/**
* Checks if the given annotation, or any annotation declared on this annotation, is {@link Invokable}.
*
* @param invokableCandidate annotation class to inspect
* @return true if the annotation is considered {@link Invokable}, false otherwise
*/
private boolean isInvokableAnnotation(Class<? extends Annotation> invokableCandidate, MetaAnnotationStore metaAnnotationStore) {
if (invokableCandidate.equals(Invokable.class)) {
return true;
} else {
// validity here means that the annotation contains @Invokable meta-annotation
// this accounts for both, actually present annotation in code, and added via extension
if (metaAnnotationStore.getInvokableModel(invokableCandidate).isValid()) {
return true;
}
}
return false;
}
}
9 changes: 9 additions & 0 deletions impl/src/main/java/org/jboss/weld/bean/ClassBean.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
*/
package org.jboss.weld.bean;

import jakarta.enterprise.inject.spi.AnnotatedMethod;
import jakarta.enterprise.inject.spi.Bean;
import jakarta.enterprise.inject.spi.BeanManager;
import jakarta.enterprise.inject.spi.InjectionTarget;
Expand All @@ -24,6 +25,8 @@
import org.jboss.weld.annotated.slim.SlimAnnotatedType;
import org.jboss.weld.manager.BeanManagerImpl;

import java.util.Collection;

/**
* Marker for {@link Bean} implementations that are defined by a Java class.
*
Expand Down Expand Up @@ -59,4 +62,10 @@ public interface ClassBean<T> extends WeldBean<T> {
* @return the injection target
*/
InjectionTarget<T> getProducer();

/**
* Returns a subset of methods of this class bean for which an invoker might be registered.
* @return a collection of annotated methods for which an invoker can be registered
*/
Collection<AnnotatedMethod<? super T>> getInvokableMethods();
}
7 changes: 7 additions & 0 deletions impl/src/main/java/org/jboss/weld/bean/ManagedBean.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@

import static org.jboss.weld.bean.BeanIdentifiers.forManagedBean;

import java.util.Collection;
import java.util.Set;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.context.Dependent;
import jakarta.enterprise.context.RequestScoped;
import jakarta.enterprise.context.spi.CreationalContext;
import jakarta.enterprise.inject.spi.AnnotatedMethod;
import jakarta.enterprise.inject.spi.Bean;
import jakarta.enterprise.inject.spi.BeanAttributes;
import jakarta.enterprise.inject.spi.Decorator;
Expand Down Expand Up @@ -301,4 +303,9 @@ private boolean initHasPostConstructCallback(InjectionTarget<T> producer) {
// otherwise we assume there is a post construct callback, just to be safe
return true;
}

@Override
public Collection<AnnotatedMethod<? super T>> getInvokableMethods() {
return invokableMethods;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import org.jboss.weld.bootstrap.events.configurator.AnnotatedTypeConfiguratorImpl;
import org.jboss.weld.bootstrap.spi.Deployment;
import org.jboss.weld.literal.InterceptorBindingTypeLiteral;
import org.jboss.weld.literal.InvokableLiteral;
import org.jboss.weld.literal.NormalScopeLiteral;
import org.jboss.weld.literal.QualifierLiteral;
import org.jboss.weld.literal.ScopeLiteral;
Expand Down Expand Up @@ -83,6 +84,15 @@ public void addInterceptorBinding(Class<? extends Annotation> bindingType, Annot
BootstrapLogger.LOG.addInterceptorBindingCalled(getReceiver(), bindingType);
}

@Override
public void addInvokable(Class<? extends Annotation> aClass) {
checkWithinObserverNotification();
getTypeStore().add(aClass, InvokableLiteral.INSTANCE);
getBeanManager().getServices().get(ClassTransformer.class).clearAnnotationData(aClass);
getBeanManager().getServices().get(MetaAnnotationStore.class).clearAnnotationData(aClass);
BootstrapLogger.LOG.addInvokableCalled(getReceiver(), aClass);
}

@Override
public void addScope(Class<? extends Annotation> scopeType, boolean normal, boolean passivating) {
checkWithinObserverNotification();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,17 @@
*/
package org.jboss.weld.bootstrap.events;

import jakarta.enterprise.inject.spi.AnnotatedMethod;
import jakarta.enterprise.invoke.Invoker;
import jakarta.enterprise.invoke.InvokerBuilder;
import org.jboss.weld.bean.ManagedBean;
import org.jboss.weld.invokable.InvokerBuilderImpl;
import org.jboss.weld.manager.BeanManagerImpl;

import jakarta.enterprise.inject.spi.AnnotatedType;
import jakarta.enterprise.inject.spi.ProcessManagedBean;
import java.lang.reflect.Type;
import java.util.Collection;

public class ProcessManagedBeanImpl<X> extends AbstractProcessClassBean<X, ManagedBean<X>> implements ProcessManagedBean<X> {

Expand All @@ -41,4 +46,15 @@ public AnnotatedType<X> getAnnotatedBeanClass() {
return getBean().getAnnotated();
}

@Override
public Collection<AnnotatedMethod<? super X>> getInvokableMethods() {
return getBean().getInvokableMethods();
}

@Override
public InvokerBuilder<Invoker<X, ?>> createInvoker(AnnotatedMethod<? super X> annotatedMethod) {
checkWithinObserverNotification();
return new InvokerBuilderImpl<>(getBean(), annotatedMethod);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,17 @@
package org.jboss.weld.bootstrap.events;

import java.lang.reflect.Type;
import java.util.Collection;

import jakarta.enterprise.inject.spi.AnnotatedMethod;
import jakarta.enterprise.inject.spi.AnnotatedType;
import jakarta.enterprise.inject.spi.ProcessSessionBean;
import jakarta.enterprise.inject.spi.SessionBeanType;

import jakarta.enterprise.invoke.Invoker;
import jakarta.enterprise.invoke.InvokerBuilder;
import org.jboss.weld.bean.SessionBean;
import org.jboss.weld.invokable.InvokerBuilderImpl;
import org.jboss.weld.logging.BootstrapLogger;
import org.jboss.weld.manager.BeanManagerImpl;

Expand Down Expand Up @@ -62,4 +67,14 @@ public AnnotatedType<Object> getAnnotatedBeanClass() {
return getBean().getAnnotated();
}

@Override
public Collection<AnnotatedMethod<? super Object>> getInvokableMethods() {
return getBean().getInvokableMethods();
}

@Override
public InvokerBuilder<Invoker<Object, ?>> createInvoker(AnnotatedMethod<? super Object> annotatedMethod) {
checkWithinObserverNotification();
return new InvokerBuilderImpl<>(getBean(), annotatedMethod);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package org.jboss.weld.invokable;

import jakarta.enterprise.inject.spi.AnnotatedMethod;
import jakarta.enterprise.invoke.Invoker;
import jakarta.enterprise.invoke.InvokerBuilder;
import org.jboss.weld.bean.ClassBean;

// TODO add exception on repeated invocations of builder methods as per spec
public class InvokerBuilderImpl<T> implements InvokerBuilder<Invoker<T, ?>> {

final ClassBean<T> classBean;
final AnnotatedMethod<? super T> method;

boolean instanceLookup;
boolean[] argLookup;
TransformerMetadata instanceTransformer;
TransformerMetadata returnValueTransformer;
TransformerMetadata exceptionTransformer;
TransformerMetadata invocationWrapper;
final TransformerMetadata[] argTransformers;

public InvokerBuilderImpl(ClassBean<T> classBean, AnnotatedMethod<? super T> method) {
this.classBean = classBean;
this.method = method;
this.argLookup = new boolean[method.getParameters().size()];
this.argTransformers = new TransformerMetadata[method.getParameters().size()];
}


@Override
public InvokerBuilder<Invoker<T, ?>> setInstanceLookup() {
this.instanceLookup = true;
return this;
}

@Override
public InvokerBuilder<Invoker<T, ?>> setArgumentLookup(int i) {
if (i >= argLookup.length) {
// TODO better exception
throw new IllegalArgumentException("Error attempting to set CDI argument lookup for arg number " + i + " while the number of method args is " + argLookup.length);
}
argLookup[i] = true;
return this;
}

@Override
public InvokerBuilder<Invoker<T, ?>> setInstanceTransformer(Class<?> aClass, String s) {
this.instanceTransformer = new TransformerMetadata(aClass, s, TransformerType.INSTANCE);
return this;
}

@Override
public InvokerBuilder<Invoker<T, ?>> setArgumentTransformer(int i, Class<?> aClass, String s) {
if (i >= argLookup.length) {
// TODO better exception
throw new IllegalArgumentException("Error attempting to set an argument lookup. Number of method args: " + argLookup.length + " arg position: " + i);
}
this.argTransformers[i] = new TransformerMetadata(aClass, s, TransformerType.ARGUMENT);
return this;
}

@Override
public InvokerBuilder<Invoker<T, ?>> setReturnValueTransformer(Class<?> aClass, String s) {
this.returnValueTransformer = new TransformerMetadata(aClass, s, TransformerType.RETURN_VALUE);
return this;
}

@Override
public InvokerBuilder<Invoker<T, ?>> setExceptionTransformer(Class<?> aClass, String s) {
this.exceptionTransformer = new TransformerMetadata(aClass, s, TransformerType.EXCEPTION);
return this;
}

@Override
public InvokerBuilder<Invoker<T, ?>> setInvocationWrapper(Class<?> aClass, String s) {
this.invocationWrapper = new TransformerMetadata(aClass, s, TransformerType.WRAPPER);
return this;
}

@Override
public Invoker<T, ?> build() {
return new InvokerImpl<>(this);
}
}
Loading

0 comments on commit 313d464

Please sign in to comment.