📄 containerimpl.java
字号:
/** * Copyright (C) 2006 Google Inc. * * 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 com.opensymphony.xwork2.inject;import com.opensymphony.xwork2.inject.util.ReferenceCache;import java.lang.annotation.Annotation;import java.lang.reflect.AccessibleObject;import java.lang.reflect.AnnotatedElement;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Member;import java.lang.reflect.Method;import java.lang.reflect.Modifier;import java.util.ArrayList;import java.util.Arrays;import java.util.Collections;import java.util.HashMap;import java.util.HashSet;import java.util.Iterator;import java.util.List;import java.util.Map;import java.util.Set;import java.util.Map.Entry;import java.io.Serializable;/** * Default {@link Container} implementation. * * @see ContainerBuilder * @author crazybob@google.com (Bob Lee) */class ContainerImpl implements Container { final Map<Key<?>, InternalFactory<?>> factories; final Map<Class<?>,Set<String>> factoryNamesByType; ContainerImpl(Map<Key<?>, InternalFactory<?>> factories) { this.factories = factories; Map<Class<?>,Set<String>> map = new HashMap<Class<?>,Set<String>>(); for (Key<?> key : factories.keySet()) { Set<String> names = map.get(key.getType()); if (names == null) { names = new HashSet<String>(); map.put(key.getType(), names); } names.add(key.getName()); } for (Entry<Class<?>,Set<String>> entry : map.entrySet()) { entry.setValue(Collections.unmodifiableSet(entry.getValue())); } this.factoryNamesByType = Collections.unmodifiableMap(map); } @SuppressWarnings("unchecked") <T> InternalFactory<? extends T> getFactory(Key<T> key) { return (InternalFactory<T>) factories.get(key); } /** * Field and method injectors. */ final Map<Class<?>, List<Injector>> injectors = new ReferenceCache<Class<?>, List<Injector>>() { protected List<Injector> create(Class<?> key) { List<Injector> injectors = new ArrayList<Injector>(); addInjectors(key, injectors); return injectors; } }; /** * Recursively adds injectors for fields and methods from the given class to * the given list. Injects parent classes before sub classes. */ void addInjectors(Class clazz, List<Injector> injectors) { if (clazz == Object.class) { return; } // Add injectors for superclass first. addInjectors(clazz.getSuperclass(), injectors); // TODO (crazybob): Filter out overridden members. addInjectorsForFields(clazz.getDeclaredFields(), false, injectors); addInjectorsForMethods(clazz.getDeclaredMethods(), false, injectors); } void injectStatics(List<Class<?>> staticInjections) { final List<Injector> injectors = new ArrayList<Injector>(); for (Class<?> clazz : staticInjections) { addInjectorsForFields(clazz.getDeclaredFields(), true, injectors); addInjectorsForMethods(clazz.getDeclaredMethods(), true, injectors); } callInContext(new ContextualCallable<Void>() { public Void call(InternalContext context) { for (Injector injector : injectors) { injector.inject(context, null); } return null; } }); } void addInjectorsForMethods(Method[] methods, boolean statics, List<Injector> injectors) { addInjectorsForMembers(Arrays.asList(methods), statics, injectors, new InjectorFactory<Method>() { public Injector create(ContainerImpl container, Method method, String name) throws MissingDependencyException { return new MethodInjector(container, method, name); } }); } void addInjectorsForFields(Field[] fields, boolean statics, List<Injector> injectors) { addInjectorsForMembers(Arrays.asList(fields), statics, injectors, new InjectorFactory<Field>() { public Injector create(ContainerImpl container, Field field, String name) throws MissingDependencyException { return new FieldInjector(container, field, name); } }); } <M extends Member & AnnotatedElement> void addInjectorsForMembers( List<M> members, boolean statics, List<Injector> injectors, InjectorFactory<M> injectorFactory) { for (M member : members) { if (isStatic(member) == statics) { Inject inject = member.getAnnotation(Inject.class); if (inject != null) { try { injectors.add(injectorFactory.create(this, member, inject.value())); } catch (MissingDependencyException e) { if (inject.required()) { throw new DependencyException(e); } } } } } } interface InjectorFactory<M extends Member & AnnotatedElement> { Injector create(ContainerImpl container, M member, String name) throws MissingDependencyException; } private boolean isStatic(Member member) { return Modifier.isStatic(member.getModifiers()); } static class FieldInjector implements Injector { final Field field; final InternalFactory<?> factory; final ExternalContext<?> externalContext; public FieldInjector(ContainerImpl container, Field field, String name) throws MissingDependencyException { this.field = field; field.setAccessible(true); Key<?> key = Key.newInstance(field.getType(), name); factory = container.getFactory(key); if (factory == null) { throw new MissingDependencyException( "No mapping found for dependency " + key + " in " + field + "."); } this.externalContext = ExternalContext.newInstance(field, key, container); } public void inject(InternalContext context, Object o) { ExternalContext<?> previous = context.getExternalContext(); context.setExternalContext(externalContext); try { field.set(o, factory.create(context)); } catch (IllegalAccessException e) { throw new AssertionError(e); } finally { context.setExternalContext(previous); } } } /** * Gets parameter injectors. * * @param member to which the parameters belong * @param annotations on the parameters * @param parameterTypes parameter types * @return injections */ <M extends AccessibleObject & Member> ParameterInjector<?>[] getParametersInjectors(M member, Annotation[][] annotations, Class[] parameterTypes, String defaultName) throws MissingDependencyException { List<ParameterInjector<?>> parameterInjectors = new ArrayList<ParameterInjector<?>>(); Iterator<Annotation[]> annotationsIterator = Arrays.asList(annotations).iterator(); for (Class<?> parameterType : parameterTypes) { Inject annotation = findInject(annotationsIterator.next()); String name = annotation == null ? defaultName : annotation.value(); Key<?> key = Key.newInstance(parameterType, name); parameterInjectors.add(createParameterInjector(key, member)); } return toArray(parameterInjectors); } <T> ParameterInjector<T> createParameterInjector( Key<T> key, Member member) throws MissingDependencyException { InternalFactory<? extends T> factory = getFactory(key); if (factory == null) { throw new MissingDependencyException( "No mapping found for dependency " + key + " in " + member + "."); } ExternalContext<T> externalContext = ExternalContext.newInstance(member, key, this); return new ParameterInjector<T>(externalContext, factory); } @SuppressWarnings("unchecked") private ParameterInjector<?>[] toArray( List<ParameterInjector<?>> parameterInjections) { return parameterInjections.toArray( new ParameterInjector[parameterInjections.size()]); } /** * Finds the {@link Inject} annotation in an array of annotations. */ Inject findInject(Annotation[] annotations) { for (Annotation annotation : annotations) { if (annotation.annotationType() == Inject.class) { return Inject.class.cast(annotation); } } return null; } static class MethodInjector implements Injector { final Method method; final ParameterInjector<?>[] parameterInjectors; public MethodInjector(ContainerImpl container, Method method, String name) throws MissingDependencyException { this.method = method; method.setAccessible(true); Class<?>[] parameterTypes = method.getParameterTypes(); if (parameterTypes.length == 0) { throw new DependencyException( method + " has no parameters to inject."); } parameterInjectors = container.getParametersInjectors( method, method.getParameterAnnotations(), parameterTypes, name); } public void inject(InternalContext context, Object o) { try { method.invoke(o, getParameters(method, context, parameterInjectors)); } catch (Exception e) { throw new RuntimeException(e); } } } Map<Class<?>, ConstructorInjector> constructors =
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -