Skip to content

Commit

Permalink
WELD-1617, WELD-1618 Filter out bridge methods
Browse files Browse the repository at this point in the history
  • Loading branch information
mkouba committed Apr 1, 2014
1 parent 6c42dff commit 5a8b871
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -164,13 +164,13 @@ protected <T> void createObserversProducersDisposers(AbstractClassBean<T> bean)
}

protected <X> void createProducerMethods(AbstractClassBean<X> declaringBean, WeldClass<X> annotatedClass) {
for (WeldMethod<?, ? super X> method : annotatedClass.getDeclaredWeldMethods(Produces.class)) {
for (WeldMethod<?, ? super X> method : Beans.getProducerMethods(annotatedClass)) {
createProducerMethod(declaringBean, method);
}
}

protected <X> void createDisposalMethods(AbstractClassBean<X> declaringBean, WeldClass<X> annotatedClass) {
for (WeldMethod<?, ? super X> method : annotatedClass.getDeclaredWeldMethodsWithAnnotatedParameters(Disposes.class)) {
for (WeldMethod<?, ? super X> method : Beans.getDisposerMethods(annotatedClass)) {
DisposalMethod<? super X, ?> disposalBean = DisposalMethod.of(manager, method, declaringBean, services);
disposalBean.initialize(getEnvironment());
getEnvironment().addDisposesMethod(disposalBean);
Expand Down
70 changes: 54 additions & 16 deletions impl/src/main/java/org/jboss/weld/util/Beans.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,12 @@
import javax.enterprise.inject.spi.InjectionPoint;
import javax.inject.Inject;

import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
import com.google.common.collect.Collections2;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;

import org.jboss.weld.Container;
import org.jboss.weld.bean.AbstractReceiverBean;
import org.jboss.weld.bean.DecoratorImpl;
Expand Down Expand Up @@ -106,7 +109,6 @@
import static org.jboss.weld.logging.messages.UtilMessage.TOO_MANY_PRE_DESTROY_METHODS;
import static org.jboss.weld.logging.messages.UtilMessage.UNABLE_TO_FIND_CONSTRUCTOR;
import static org.jboss.weld.util.reflection.Reflections.EMPTY_ANNOTATIONS;
import static org.jboss.weld.util.reflection.Reflections.cast;

/**
* Helper class for bean inspection
Expand All @@ -121,6 +123,22 @@ public class Beans {
// TODO Convert messages
private static final LocLogger log = loggerFactory().getLogger(BEAN);

/**
* Oracle JDK 8 compiler (unlike prev versions) generates bridge methods which have method and parameter annotations copied from the original method.
* However such methods should not become observers, producers, disposers, initializers and lifecycle callbacks.
*
* This predicate determines true if the given method is not a bridge method.
*
* @see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6695379
*/
@SuppressWarnings("rawtypes")
private static final Predicate<WeldMethod> BRIDGE_METHOD_FILTER_PREDICATE = new Predicate<WeldMethod>() {
@Override
public boolean apply(WeldMethod method) {
return !method.getJavaMember().isBridge();
}
};

/**
* Indicates if a bean's scope type is passivating
*
Expand Down Expand Up @@ -265,7 +283,7 @@ private static void validateInjectableField(WeldField<?, ?> field) {
WeldClass<? super T> t = type;
List<WeldMethod<?, ? super T>> methods = new ArrayList<WeldMethod<?, ? super T>>();
while (!t.getJavaClass().equals(Object.class)) {
Collection<WeldMethod<?, ? super T>> declaredMethods = filterOutOverriddenMethods(type, Reflections.<Collection<WeldMethod<?, ? super T>>>cast(t.getDeclaredWeldMethods(PostConstruct.class)));
Collection<WeldMethod<?, ? super T>> declaredMethods = filterOutOverriddenAndBridgeMethods(type, Reflections.<Collection<WeldMethod<?, ? super T>>>cast(t.getDeclaredWeldMethods(PostConstruct.class)));
log.trace(FOUND_POST_CONSTRUCT_METHODS, declaredMethods, type);
if (declaredMethods.size() > 1) {
throw new DefinitionException(TOO_MANY_POST_CONSTRUCT_METHODS, type);
Expand All @@ -279,29 +297,30 @@ private static void validateInjectableField(WeldField<?, ?> field) {
return methods;
}

private static <T> Collection<WeldMethod<?, ? super T>> filterOutOverriddenMethods(WeldClass<T> type, Collection<WeldMethod<?, ? super T>> methods) {
Collection<WeldMethod<?, ? super T>> notOverriddenMethods = new ArrayList<WeldMethod<?, ? super T>>();
private static <T> Collection<WeldMethod<?, ? super T>> filterOutOverriddenAndBridgeMethods(WeldClass<T> type, Collection<WeldMethod<?, ? super T>> methods) {
Collection<WeldMethod<?, ? super T>> filteredMethods = new ArrayList<WeldMethod<?, ? super T>>();
for (WeldMethod<?, ? super T> method : methods) {
if (!type.isMethodOverridden(method)) {
notOverriddenMethods.add(method);
if (!type.isMethodOverridden(method) && BRIDGE_METHOD_FILTER_PREDICATE.apply(method)) {
filteredMethods.add(method);
}
}
return Collections.unmodifiableCollection(notOverriddenMethods);
return Collections.unmodifiableCollection(filteredMethods);
}

public static <T> List<WeldMethod<?, ? super T>> getObserverMethods(WeldClass<T> type) {
List<WeldMethod<?, ? super T>> observerMethods = new ArrayList<WeldMethod<?, ? super T>>();
// Keep track of all seen methods so we can ignore overridden methods
Multimap<MethodSignature, Package> seenMethods = Multimaps.newSetMultimap(new HashMap<MethodSignature, Collection<Package>>(), new Supplier<Set<Package>>() {
Multimap<MethodSignature, Package> seenMethods = Multimaps.newSetMultimap(new HashMap<MethodSignature, Collection<Package>>(),
new Supplier<Set<Package>>() {

public Set<Package> get() {
return new HashSet<Package>();
}
public Set<Package> get() {
return new HashSet<Package>();
}

});
});
WeldClass<? super T> t = type;
while (t != null && !t.getJavaClass().equals(Object.class)) {
for (WeldMethod<?, ? super T> method : t.getDeclaredWeldMethods()) {
for (WeldMethod<?, ? super T> method : Collections2.filter(t.getDeclaredWeldMethods(), BRIDGE_METHOD_FILTER_PREDICATE)) {
if (!isOverridden(method, seenMethods) && !method.getWeldParameters(Observes.class).isEmpty()) {
observerMethods.add(method);
}
Expand All @@ -316,7 +335,7 @@ public Set<Package> get() {
WeldClass<?> t = type;
List<WeldMethod<?, ? super T>> methods = new ArrayList<WeldMethod<?, ? super T>>();
while (!t.getJavaClass().equals(Object.class)) {
Collection<WeldMethod<?, ? super T>> declaredMethods = filterOutOverriddenMethods(type, Reflections.<Collection<WeldMethod<?, ? super T>>>cast(t.getDeclaredWeldMethods(PreDestroy.class)));
Collection<WeldMethod<?, ? super T>> declaredMethods = filterOutOverriddenAndBridgeMethods(type, Reflections.<Collection<WeldMethod<?, ? super T>>>cast(t.getDeclaredWeldMethods(PreDestroy.class)));
log.trace(FOUND_PRE_DESTROY_METHODS, declaredMethods, type);
if (declaredMethods.size() > 1) {
throw new DefinitionException(TOO_MANY_PRE_DESTROY_METHODS, type);
Expand Down Expand Up @@ -413,7 +432,7 @@ private static boolean isInterceptorMethod(WeldMethod<?, ?> annotatedMethod) {
Class<?> clazz = weldClass.getJavaClass();
while (clazz != null) {
ArraySet<MethodInjectionPoint<?, ?>> set = new ArraySet<MethodInjectionPoint<?, ?>>();
for (WeldMethod<?, ?> weldMethod : weldClass.getWeldMethods()) {
for (WeldMethod<?, ?> weldMethod : Collections2.filter(weldClass.getWeldMethods(), BRIDGE_METHOD_FILTER_PREDICATE)) {
if (weldMethod.getJavaMember().getDeclaringClass().equals(clazz)) {
processPossibleInitializerMethod(declaringBean, weldClass, weldMethod, seenMethods, set);
}
Expand All @@ -434,7 +453,7 @@ private static boolean isInterceptorMethod(WeldMethod<?, ?> annotatedMethod) {
WeldClass<?> clazz = weldClass;
while (clazz != null && !clazz.getJavaClass().equals(Object.class)) {
ArraySet<MethodInjectionPoint<?, ?>> set = new ArraySet<MethodInjectionPoint<?, ?>>();
Collection declaredWeldMethods = clazz.getDeclaredWeldMethods();
Collection declaredWeldMethods = Collections2.filter(clazz.getDeclaredWeldMethods(), BRIDGE_METHOD_FILTER_PREDICATE);
for (WeldMethod<?, ?> method : (Collection<WeldMethod<?, ?>>) declaredWeldMethods) {
processPossibleInitializerMethod(declaringBean, weldClass, method, seenMethods, set);
}
Expand Down Expand Up @@ -849,4 +868,23 @@ public static InjectionPoint getDelegateInjectionPoint(javax.enterprise.inject.s
}
return null;
}

/**
*
* @param weldClass
* @return a set of producer methods, bridge methods are filtered out
*/
public static <T> Collection<WeldMethod<?, ? super T>> getProducerMethods(WeldClass<T> weldClass) {
return Collections2.filter(weldClass.getDeclaredWeldMethods(Produces.class), BRIDGE_METHOD_FILTER_PREDICATE);
}

/**
*
* @param weldClass
* @return a set of disposer methods, bridge methods are filtered out
*/
public static <T> Collection<WeldMethod<?, ? super T>> getDisposerMethods(WeldClass<T> weldClass) {
return Collections2.filter(weldClass.getDeclaredWeldMethodsWithAnnotatedParameters(Disposes.class), BRIDGE_METHOD_FILTER_PREDICATE);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,12 @@ FAILED_TO_SET_THREAD_LOCAL_ON_PROXY=Failed to set ThreadLocal for serialization
CREATED_NEW_CLIENT_PROXY_TYPE=Created new client proxy of type {0} for bean {1} with ID {2}
LOOKED_UP_CLIENT_PROXY=Located client proxy of type {0} for bean {1}
INJECTION_TARGET_CANNOT_BE_CREATED_FOR_INTERFACE=Cannot create an InjectionTarget from {0} as it is an interface
SPECIALIZING_BEAN_MISSING_SPECIALIZED_TYPE=Specializing bean {0} does not have bean type {1} of specialized bean {2}
INVALID_INJECTION_POINT_TYPE={0} cannot be constructed for {1}
INVALID_ANNOTATED_CALLABLE=An implementation of AnnotatedCallable must implement either AnnotatedConstructor or AnnotatedMethod, {0}
INVALID_ANNOTATED_MEMBER=An implementation of AnnotatedMember must implement either AnnotatedConstructor, AnnotatedMethod or AnnotatedField, {0}
UNABLE_TO_LOAD_MEMBER=Unable to load annotated member {0}
NAMED_RESOURCE_PRODUCER_FIELD=Resource producer field [{0}] must not have an EL name
PASSIVATING_BEAN_HAS_NON_PASSIVATION_CAPABLE_DECORATOR=Managed bean declaring a passivating scope has a non-passivation capable decorator. Bean: {0} Decorator: {1}
PASSIVATING_BEAN_HAS_NON_PASSIVATION_CAPABLE_INTERCEPTOR=Managed bean declaring a passivating scope has a non-serializable interceptor. Bean: {0} Interceptor: {1}
DESERIALIZATED_BEAN_WAS_NULL=Failed to deserialize proxy object with beanId {0}.
DESERIALIZATED_BEAN_WAS_NULL=Failed to deserialize proxy object with beanId {0}.

0 comments on commit 5a8b871

Please sign in to comment.