Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* JBoss, Home of Professional Open Source
* Copyright 2012, Red Hat, Inc., and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.weld.util;
import java.lang.reflect.Method;
import java.security.AccessController;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.enterprise.event.Observes;
import javax.enterprise.inject.Disposes;
import javax.enterprise.inject.Produces;
import javax.enterprise.inject.spi.AnnotatedMethod;
import javax.enterprise.inject.spi.AnnotatedType;
import javax.enterprise.inject.spi.Bean;
import javax.inject.Inject;
import org.jboss.weld.annotated.enhanced.EnhancedAnnotatedMethod;
import org.jboss.weld.annotated.enhanced.EnhancedAnnotatedType;
import org.jboss.weld.injection.InjectionPointFactory;
import org.jboss.weld.injection.MethodInjectionPoint;
import org.jboss.weld.injection.MethodInjectionPoint.MethodInjectionPointType;
import org.jboss.weld.interceptor.reader.InterceptorMetadataUtils;
import org.jboss.weld.interceptor.spi.model.InterceptionType;
import org.jboss.weld.interceptor.util.InterceptionTypeRegistry;
import org.jboss.weld.logging.BeanLogger;
import org.jboss.weld.logging.EventLogger;
import org.jboss.weld.logging.UtilLogger;
import org.jboss.weld.manager.BeanManagerImpl;
import org.jboss.weld.security.SetAccessibleAction;
import org.jboss.weld.util.collections.ImmutableList;
import org.jboss.weld.util.collections.ImmutableSet;
import org.jboss.weld.util.collections.WeldCollections;
import org.jboss.weld.util.reflection.Formats;
public class BeanMethods {
private BeanMethods() {
}
/**
* We need to employ different strategies when discovering a list of specific methods of a {@link Bean} (e.g. initializer
* methods, producer methods, lifecycle event callback listeners, etc.) An implementation of this interface knows how to
* establish a list of certain methods.
*
* The user of this implementation starts interaction by calling {@link #getAllMethods(EnhancedAnnotatedType)} which obtains
* a collection of all methods of a given kind. Afterwards, iterates over the class hierarchy of
* {@link AnnotatedType#getJavaClass()} from the most specific class to {@link Object}. For each class in the hierarchy it
* calls {@link #levelStart(Class)}. Then it calls {@link #processMethod(EnhancedAnnotatedMethod)} for each method out of
* the collection of all methods of the given kind (see above) which is declared by the current class (current level). Once
* all the methods declared by the current class are processed, {@link #levelFinish()} is called and the iteration may
* continue with a superclass of the current class (provided there is any).
*
* Finally, {@link #create()} is called to obtain the result.
*
* @author Jozef Hartinger
*
* @param the class declaring the annotated type
* @param type of result (e.g. a list of AnnotatedMethods, a list of sets of AnnotatedMethods, etc.)
*/
private interface MethodListBuilder {
/**
* Returns all methods of a given kind (e.g. all observer methods) of a given {@link EnhancedAnnotatedType}. This
* includes methods defined on classes upper in the class hierarchy. Overridden methods are not returned.
*/
Collection> getAllMethods(EnhancedAnnotatedType type);
/**
* This method is called before methods declared by a specific class in the class hierarchy are processed. Only classes
* declared by this specific class are processed until {@link #levelFinish()} is called.
*/
void levelStart(Class super T> clazz);
/**
* Allows an implementation to process a method. By default the method would be added to the list of methods being
* built.
*/
void processMethod(EnhancedAnnotatedMethod, ? super T> method);
/**
* Indicates that processing of methods declared by a given class has ended. There are no more methods declared by the
* given class to be processed.
*/
void levelFinish();
/**
* Obtains the result. This method may not be idempotent and it is therefore not safe to call it multiple times.
*
* @return the list of methods of a given kind
*/
R create();
}
/**
* Get all methods of a given kind using a given {@link MethodListBuilder}.
*/
private static R getMethods(EnhancedAnnotatedType type, MethodListBuilder builder) {
Collection> methods = filterMethods(builder.getAllMethods(type));
for (Class super T> clazz = type.getJavaClass(); clazz != null && clazz != Object.class; clazz = clazz
.getSuperclass()) {
builder.levelStart(clazz);
for (EnhancedAnnotatedMethod, ? super T> method : methods) {
if (method.getJavaMember().getDeclaringClass().equals(clazz)) {
builder.processMethod(method);
}
}
builder.levelFinish();
}
return builder.create();
}
/**
* For lifecycle event callback we need an ordered list. Lifecycle callback methods defined on the most specific class go
* first in the list. A given class in the class hierarchy may define at most one method.
*
* @author Jozef Hartinger
*/
private abstract static class AbstractLifecycleEventCallbackMethodListBuilder implements
MethodListBuilder>> {
protected List> result = new ArrayList>();
protected EnhancedAnnotatedMethod, ? super T> foundMethod = null;
@Override
public void levelStart(Class super T> clazz) {
foundMethod = null;
}
@Override
public void processMethod(EnhancedAnnotatedMethod, ? super T> method) {
if (methodHasNoParameters(method)) {
if (foundMethod != null) {
duplicateMethod(method);
}
foundMethod = method;
}
}
private boolean methodHasNoParameters(EnhancedAnnotatedMethod, ? super T> method) {
return method.getParameterTypesAsArray().length == 0;
}
@Override
public void levelFinish() {
if (foundMethod != null) {
result.add(processLevelResult(foundMethod).slim());
}
}
@Override
public List> create() {
Collections.reverse(result);
return WeldCollections.immutableListView(result);
}
/**
* Called when a given hierarchy level defines multiple lifecycle event callback of a given type.
*/
protected abstract void duplicateMethod(EnhancedAnnotatedMethod, ? super T> method);
/**
* Called when a unique method is found for a given hierarchy level.
*/
protected abstract EnhancedAnnotatedMethod, ? super T> processLevelResult(EnhancedAnnotatedMethod, ? super T> method);
}
/**
* For initializers we need to return a {@link List} of {@link Set}s of initializer methods (because a class may declare
* multiple initializers). The list is ordered the same way as for lifecycle event callbacks.
*
* @author Jozef Hartinger
*/
private static class InitializerMethodListBuilder implements MethodListBuilder>>> {
private final List>> result = new ArrayList>>();
private ImmutableSet.Builder> currentLevel = null;
private final EnhancedAnnotatedType type;
private final BeanManagerImpl manager;
private final Bean> declaringBean;
public InitializerMethodListBuilder(EnhancedAnnotatedType type, Bean> declaringBean, BeanManagerImpl manager) {
this.type = type;
this.manager = manager;
this.declaringBean = declaringBean;
}
@Override
public Collection> getAllMethods(EnhancedAnnotatedType type) {
return type.getEnhancedMethods(Inject.class);
}
@Override
public void levelStart(Class super T> clazz) {
currentLevel = ImmutableSet.builder();
}
@Override
public void processMethod(EnhancedAnnotatedMethod, ? super T> method) {
if (method.isAnnotationPresent(Inject.class)) {
if (method.getAnnotation(Produces.class) != null) {
throw UtilLogger.LOG.initializerCannotBeProducer(method, Formats.formatAsStackTraceElement(method.getJavaMember()));
} else if (method.getEnhancedParameters(Disposes.class).size() > 0) {
throw UtilLogger.LOG.initializerCannotBeDisposalMethod(method, Formats.formatAsStackTraceElement(method.getJavaMember()));
} else if (method.getEnhancedParameters(Observes.class).size() > 0) {
throw EventLogger.LOG.invalidInitializer(method, Formats.formatAsStackTraceElement(method.getJavaMember()));
} else if (method.isGeneric()) {
throw UtilLogger.LOG.initializerMethodIsGeneric(method, Formats.formatAsStackTraceElement(method.getJavaMember()));
}
if (!method.isStatic()) {
currentLevel.add(InjectionPointFactory.instance().createMethodInjectionPoint(MethodInjectionPointType.INITIALIZER, method, declaringBean,
type.getJavaClass(), null, manager));
}
}
}
@Override
public void levelFinish() {
result.add(currentLevel.build());
}
@Override
public List>> create() {
Collections.reverse(result); // because we want methods that are lower in the hierarchy to be called first
return WeldCollections.immutableListView(result);
}
}
public static List> getPostConstructMethods(final EnhancedAnnotatedType type) {
return getMethods(type, new AbstractLifecycleEventCallbackMethodListBuilder() {
@Override
public Collection> getAllMethods(EnhancedAnnotatedType type) {
return type.getEnhancedMethods(PostConstruct.class);
}
@Override
protected void duplicateMethod(EnhancedAnnotatedMethod, ? super T> method) {
throw UtilLogger.LOG.tooManyPostConstructMethods(type);
}
@Override
protected EnhancedAnnotatedMethod, ? super T> processLevelResult(EnhancedAnnotatedMethod, ? super T> method) {
BeanLogger.LOG.foundOnePostConstructMethod(method, type);
return method;
}
});
}
public static List> getPreDestroyMethods(final EnhancedAnnotatedType type) {
return getMethods(type, new AbstractLifecycleEventCallbackMethodListBuilder() {
@Override
public Collection> getAllMethods(EnhancedAnnotatedType type) {
return type.getEnhancedMethods(PreDestroy.class);
}
@Override
protected void duplicateMethod(EnhancedAnnotatedMethod, ? super T> method) {
throw UtilLogger.LOG.tooManyPreDestroyMethods(type);
}
@Override
protected EnhancedAnnotatedMethod, ? super T> processLevelResult(EnhancedAnnotatedMethod, ? super T> method) {
BeanLogger.LOG.foundOnePreDestroyMethod(method, type);
return method;
}
});
}
public static List>> getInitializerMethods(Bean> declaringBean, EnhancedAnnotatedType type, BeanManagerImpl manager) {
return getMethods(type, new InitializerMethodListBuilder(type, declaringBean, manager));
}
public static Collection> getObserverMethods(final EnhancedAnnotatedType type) {
return filterMethods(type.getEnhancedMethodsWithAnnotatedParameters(Observes.class));
}
/**
* 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.
*
* Moreover, JDK8u60 propagates parameter annotations to the synthetic method generated for a lambda. Therefore, we should also ignore synthetic methods.
*
* @param methods
* @return a collection view with bridge and synthetic methods filtered out
* @see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6695379
* @see https://issues.jboss.org/browse/WELD-2019
*/
public static Collection> filterMethods(final Collection> methods) {
List> filteredMethods = new ArrayList<>(methods.size());
for (EnhancedAnnotatedMethod, ? super T> method : methods) {
if (!method.getJavaMember().isBridge() && !method.getJavaMember().isSynthetic()) {
filteredMethods.add(method);
}
}
return Collections.unmodifiableList(filteredMethods);
}
public static List getInterceptorMethods(EnhancedAnnotatedType type, final InterceptionType interceptionType, final boolean targetClass) {
return getMethods(type, new MethodListBuilder>() {
List methodMetadata = null;
@Override
public Collection> getAllMethods(EnhancedAnnotatedType type) {
return type.getEnhancedMethods(InterceptionTypeRegistry.getAnnotationClass(interceptionType));
}
@Override
public void levelStart(Class super T> clazz) {
}
@Override
public void processMethod(EnhancedAnnotatedMethod, ? super T> method) {
final Method javaMethod = method.getJavaMember();
if (InterceptorMetadataUtils.isInterceptorMethod(interceptionType, javaMethod, targetClass)) {
if (methodMetadata == null) {
methodMetadata = new LinkedList();
}
if (System.getSecurityManager() == null) {
javaMethod.setAccessible(true);
} else {
AccessController.doPrivileged(SetAccessibleAction.of(javaMethod));
}
methodMetadata.add(method.getJavaMember());
}
}
@Override
public void levelFinish() {
}
@Override
public List create() {
if (methodMetadata == null) {
return Collections.emptyList();
}
Collections.reverse(methodMetadata);
return ImmutableList.copyOf(methodMetadata);
}
});
}
}