Skip to content

Commit

Permalink
WELD-1838 Revise the use of reflection in Weld SE and Servlet
Browse files Browse the repository at this point in the history
  • Loading branch information
mkouba authored and jharting committed Jan 23, 2015
1 parent c585ac9 commit ba640be
Show file tree
Hide file tree
Showing 20 changed files with 513 additions and 345 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package org.jboss.weld.environment.deployment.discovery;

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

import org.jboss.weld.bootstrap.api.Bootstrap;
Expand Down Expand Up @@ -45,10 +46,15 @@ private DiscoveryStrategyFactory() {
* @return the discovery strategy
*/
public static DiscoveryStrategy create(ResourceLoader resourceLoader, Bootstrap bootstrap, Set<Class<? extends Annotation>> initialBeanDefiningAnnotations) {

if (Reflections.isClassLoadable(JANDEX_INDEX_CLASS_NAME, resourceLoader)) {
if (Reflections.isClassLoadable(resourceLoader, JANDEX_INDEX_CLASS_NAME)) {
CommonLogger.LOG.usingJandex();
return Reflections.newInstance(resourceLoader, JANDEX_DISCOVERY_STRATEGY_CLASS_NAME, resourceLoader, bootstrap, initialBeanDefiningAnnotations);
try {
return Reflections.cast(SecurityActions.getConstructor(Reflections.classForName(resourceLoader, JANDEX_DISCOVERY_STRATEGY_CLASS_NAME),
ResourceLoader.class, Bootstrap.class, Set.class).newInstance(resourceLoader, bootstrap, initialBeanDefiningAnnotations));
} catch (Exception e) {
throw CommonLogger.LOG.unableToInstantiate(JANDEX_DISCOVERY_STRATEGY_CLASS_NAME,
Arrays.toString(new Object[] { resourceLoader, bootstrap, initialBeanDefiningAnnotations }), e);
}
}
return new ReflectionDiscoveryStrategy(resourceLoader, bootstrap, initialBeanDefiningAnnotations);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* JBoss, Home of Professional Open Source
* Copyright 2015, 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.environment.deployment.discovery;

import java.lang.reflect.Constructor;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;

import org.jboss.weld.exceptions.WeldException;
import org.jboss.weld.security.GetConstructorAction;

/**
*
* @author Martin Kouba
*/
final class SecurityActions {

private SecurityActions() {
}

/**
* Does not perform {@link PrivilegedAction} unless necessary.
*
* @param javaClass
* @param parameterTypes
* @return a declared constructor
* @throws NoSuchMethodException
*/
static <T> Constructor<T> getConstructor(Class<T> javaClass, Class<?>... parameterTypes) throws NoSuchMethodException {
if (System.getSecurityManager() != null) {
try {
return AccessController.doPrivileged(GetConstructorAction.of(javaClass, parameterTypes));
} catch (PrivilegedActionException e) {
if (e.getCause() instanceof NoSuchMethodException) {
throw (NoSuchMethodException) e.getCause();
}
throw new WeldException(e.getCause());
}
} else {
return javaClass.getConstructor(parameterTypes);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,6 @@ public interface CommonLogger extends WeldEnvironmentLogger {
@Message(id = 16, value = "Missing beans.xml file in META-INF", format = Format.MESSAGE_FORMAT)
IllegalStateException missingBeansXml();

@Message(id = 17, value = "Error loading Weld bootstrap, check that Weld is on the classpath", format = Format.MESSAGE_FORMAT)
IllegalStateException errorLoadingWeld();

@Message(id = 18, value = "Unable to resolve a bean for {0} with bindings {1}", format = Format.MESSAGE_FORMAT)
UnsatisfiedResolutionException unableToResolveBean(Object param1, Object param2);

Expand Down Expand Up @@ -109,10 +106,14 @@ public interface CommonLogger extends WeldEnvironmentLogger {
@Message(id = 26, value = "Unable to instantiate {0} using parameters: {1}.", format = Format.MESSAGE_FORMAT)
IllegalStateException unableToInstantiate(Object param1, Object param2, @Cause Throwable cause);

@Message(id = 27, value = "Unable to find constructor for of {0} accepting parameters: {1}.", format = Format.MESSAGE_FORMAT)
IllegalStateException unableToFindConstructor(Object param1, Object param2);

@LogMessage(level = Level.INFO)
@Message(id = 28, value = "Weld initialization skipped - no bean archive found")
void initSkippedNoBeanArchiveFound();

@Message(id = 29, value = "Cannot load class for {0}.", format = Format.MESSAGE_FORMAT)
IllegalStateException cannotLoadClass(Object param1, @Cause Throwable cause);

@LogMessage(level = Level.DEBUG)
@Message(id = 30, value = "Cannot load class using the ResourceLoader: {0}", format = Format.MESSAGE_FORMAT)
void cannotLoadClassUsingResourceLoader(String className);
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,36 @@
/*
* JBoss, Home of Professional Open Source
* Copyright 2008, Red Hat Middleware LLC, 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.environment.util;

import java.lang.annotation.Annotation;
import java.lang.annotation.Inherited;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;

import org.jboss.weld.environment.logging.CommonLogger;
import org.jboss.weld.resources.spi.ResourceLoader;
import org.jboss.weld.resources.spi.ResourceLoadingException;

/**
* Reflection utilities.
*
* @author Pete Muir
* @author Martin Kouba
*/
public final class Reflections {

private Reflections() {
Expand Down Expand Up @@ -56,51 +76,63 @@ public static boolean containsAnnotation(Class<?> javaClass, Class<? extends Ann
return false;
}

public static <T> T newInstance(ResourceLoader loader, String className, Object... parameters) {
final Class<?>[] parameterTypes = new Class<?>[parameters.length];
for (int i = 0; i < parameters.length; i++) {
parameterTypes[i] = parameters[i].getClass();
}
try {
final Class<T> clazz = cast(loader.classForName(className));
final Constructor<T> constructor = findConstructor(clazz, parameters);
return constructor.newInstance(parameters);
} catch (Exception e) {
throw CommonLogger.LOG.unableToInstantiate(className, Arrays.toString(parameters), e);
}
}

@SuppressWarnings("unchecked")
public static <T> T cast(Object obj) {
return (T) obj;
}

public static boolean isClassLoadable(String className, ResourceLoader resourceLoader) {
return loadClass(className, resourceLoader) != null;
/**
*
* @param resourceLoader
* @param className
* @return <code>true</code> if a class with the given name can be loaded, <code>false</code> otherwise
* @see #loadClass(ResourceLoader, String)
*/
public static boolean isClassLoadable(ResourceLoader resourceLoader, String className) {
return loadClass(resourceLoader, className) != null;
}

/**
* Tries to load a class using the specified ResourceLoader. Returns null if the class is not found.
* @param className
*
* @param resourceLoader
* @param className
* @return the loaded class or null if the given class cannot be loaded
* @see #classForName(ResourceLoader, String)
*/
public static <T> Class<T> loadClass(String className, ResourceLoader resourceLoader) {
public static <T> Class<T> loadClass(ResourceLoader resourceLoader, String className) {
try {
return cast(resourceLoader.classForName(className));
} catch (ResourceLoadingException e) {
return null;
} catch (SecurityException e) {
return classForName(resourceLoader, className);
} catch (Exception e) {
return null;
}
}

/**
* First try to load a class using the specified ResourceLoader. If not successful, try {@link Class#forName(String)} as a fallback.
*
* @param resourceLoader
* @param className
* @return the loaded class
*/
public static <T> Class<T> classForName(ResourceLoader resourceLoader, String className) {
try {
return cast(resourceLoader.classForName(className));
} catch (Exception e) {
CommonLogger.LOG.cannotLoadClassUsingResourceLoader(className);
CommonLogger.LOG.catchingTrace(e);
}
try {
return cast(Class.forName(className));
} catch (Exception e) {
throw CommonLogger.LOG.cannotLoadClass(className, e);
}
}

/**
*
* @param annotations
* @param metaAnnotationType
* @return <code>true</code> if any of the annotations specified has the given meta annotation type specified, <code>false</code>
* otherwise
* @return <code>true</code> if any of the annotations specified has the given meta annotation type specified, <code>false</code> otherwise
*/
public static boolean hasBeanDefiningMetaAnnotationSpecified(Annotation[] annotations, Class<? extends Annotation> metaAnnotationType) {
for (Annotation annotation : annotations) {
Expand All @@ -111,25 +143,6 @@ public static boolean hasBeanDefiningMetaAnnotationSpecified(Annotation[] annota
return false;
}

/**
* Does constructor lookup respecting parameter covariance.
*/
private static <T> Constructor<T> findConstructor(Class<T> clazz, Object... parameters) {
for (Constructor<?> constructor : clazz.getConstructors()) {
boolean match = true;
for (int i = 0; i < parameters.length; i++) {
if (!constructor.getParameterTypes()[i].isAssignableFrom(parameters[i].getClass())) {
match = false;
break;
}
}
if (match) {
return cast(constructor);
}
}
throw CommonLogger.LOG.unableToFindConstructor(clazz, Arrays.toString(parameters));
}

private static boolean containsAnnotations(Annotation[] annotations, Class<? extends Annotation> requiredAnnotation) {
return containsAnnotation(annotations, requiredAnnotation, true);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.Extension;

import org.jboss.weld.bootstrap.WeldBootstrap;
import org.jboss.weld.bootstrap.api.Bootstrap;
import org.jboss.weld.bootstrap.api.CDI11Bootstrap;
import org.jboss.weld.bootstrap.api.Environments;
Expand Down Expand Up @@ -77,8 +78,6 @@ public class Weld {

public static final String ARCHIVE_ISOLATION_SYSTEM_PROPERTY = "org.jboss.weld.se.archive.isolation";

private static final String BOOTSTRAP_IMPL_CLASS_NAME = "org.jboss.weld.bootstrap.WeldBootstrap";

static {
if (!(SingletonProvider.instance() instanceof RegistrySingletonProvider)) {
// make sure RegistrySingletonProvider is used (required for supporting multiple parallel Weld instances)
Expand Down Expand Up @@ -124,22 +123,14 @@ public void addExtension(Extension extension) {
* @return weld container
*/
public WeldContainer initialize() {
ResourceLoader resourceLoader = new WeldResourceLoader();
final ResourceLoader resourceLoader = new WeldResourceLoader();
// check for beans.xml
if (resourceLoader.getResource(WeldDeployment.BEANS_XML) == null) {
throw CommonLogger.LOG.missingBeansXml();
}

final CDI11Bootstrap bootstrap;
try {
bootstrap = (CDI11Bootstrap) resourceLoader.classForName(BOOTSTRAP_IMPL_CLASS_NAME).newInstance();
} catch (InstantiationException ex) {
throw CommonLogger.LOG.errorLoadingWeld();
} catch (IllegalAccessException ex) {
throw CommonLogger.LOG.errorLoadingWeld();
}

Deployment deployment = createDeployment(resourceLoader, bootstrap);
final CDI11Bootstrap bootstrap = new WeldBootstrap();
final Deployment deployment = createDeployment(resourceLoader, bootstrap);


// Set up the container
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@

package org.jboss.weld.environment;

import org.jboss.weld.environment.servlet.util.Reflections;
import org.jboss.weld.environment.util.Reflections;
import org.jboss.weld.resources.spi.ResourceLoader;

/**
* Abstract container.
Expand All @@ -33,8 +34,8 @@ public abstract class AbstractContainer implements Container {
*/
protected abstract String classToCheck();

public boolean touch(ContainerContext context) throws Exception {
Reflections.classForName(classToCheck());
public boolean touch(ResourceLoader resourceLoader, ContainerContext context) throws Exception {
Reflections.classForName(resourceLoader, classToCheck());
return true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

package org.jboss.weld.environment;

import org.jboss.weld.resources.spi.ResourceLoader;


/**
* Abstract the web container setup notion.
Expand All @@ -32,11 +34,12 @@ public interface Container {
* Touch if this container can be used.
* We should throw an exception if it cannot be used.
*
* @param resourceLoader the ResourceLoader to use for class-availability testing
* @param context the container context
* @return true if touch was successful, false or exception otherwise
* @throws Exception for any error
*/
boolean touch(ContainerContext context) throws Exception;
boolean touch(ResourceLoader resourceLoader, ContainerContext context) throws Exception;

/**
* Initialize web container.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,9 @@
import org.jboss.weld.environment.jetty.AbstractJettyContainer;
import org.jboss.weld.environment.jetty.JettyWeldInjector;
import org.jboss.weld.environment.servlet.logging.JettyLogger;
import org.jboss.weld.environment.servlet.util.Reflections;
import org.jboss.weld.manager.api.WeldManager;

/**
*
*
*/
public class GwtDevHostedModeContainer extends AbstractJettyContainer {
Expand All @@ -50,9 +49,7 @@ protected Class<?> getWeldServletHandlerClass() {
public void initialize(ContainerContext context) {
// Try pushing a Jetty Injector into the servlet context
try {
Class<?> clazz = Reflections.classForName(JettyWeldInjector.class.getName());
Object injector = clazz.getConstructor(WeldManager.class).newInstance(context.getManager());
context.getServletContext().setAttribute(INJECTOR_ATTRIBUTE_NAME, injector);
context.getServletContext().setAttribute(INJECTOR_ATTRIBUTE_NAME, new JettyWeldInjector(context.getManager()));
JettyLogger.LOG.gwtHostedModeDetected();

Class<?> decoratorClass = getWeldServletHandlerClass();
Expand Down
Loading

0 comments on commit ba640be

Please sign in to comment.