001: /**
002: * Copyright (C) 2007 Google Inc.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */package com.bm.ejb3guice.inject;
016:
017: import com.bm.ejb3guice.internal.StackTraceElements;
018: import com.bm.ejb3guice.spi.SourceProvider;
019: import com.bm.ejb3guice.spi.SourceProviders;
020:
021: import java.lang.annotation.Annotation;
022: import java.lang.reflect.InvocationTargetException;
023: import java.lang.reflect.Method;
024: import java.lang.reflect.Type;
025: import java.util.ArrayList;
026: import java.util.List;
027:
028: /**
029: * Creates bindings to methods annotated with {@link
030: * @com.bm.ejb3guice.Provides}. Use the scope and binding annotations on the
031: * provider method to configure the binding.
032: */
033: public class ProviderMethods {
034:
035: /**
036: * Returns a module which creates bindings for provider methods from the
037: * given object.
038: */
039: public static Module from(Object providers) {
040: return new ProviderMethodsModule(providers);
041: }
042:
043: static class ProviderMethodsModule extends AbstractModule {
044:
045: final Object providers;
046:
047: Object source;
048:
049: final SourceProvider sourceProvider = new SourceProvider() {
050: public Object source() {
051: return source;
052: }
053: };
054:
055: ProviderMethodsModule(Object providers) {
056: this .providers = providers;
057: }
058:
059: protected void configure() {
060: SourceProviders.withDefault(sourceProvider, new Runnable() {
061: public void run() {
062: bindProviderMethods(providers.getClass());
063: }
064: });
065: }
066:
067: void bindProviderMethods(Class<?> clazz) {
068: if (clazz == Object.class) {
069: return;
070: }
071:
072: bindProviderMethods(clazz.getSuperclass());
073:
074: for (Method method : clazz.getDeclaredMethods()) {
075: if (method.isAnnotationPresent(Provides.class)) {
076: bindProviderMethod(method);
077: }
078: }
079: }
080:
081: void bindProviderMethod(final Method method) {
082: this .source = StackTraceElements.forMember(method);
083:
084: method.setAccessible(true);
085:
086: Class<? extends Annotation> scopeAnnotation = findScopeAnnotation(method
087: .getAnnotations());
088: Annotation bindingAnnotation = findBindingAnnotation(method
089: .getAnnotations());
090:
091: final List<Provider<?>> parameterProviders = findParameterProviders(method);
092:
093: Provider<Object> provider = new Provider<Object>() {
094: public Object get() {
095: Object[] parameters = new Object[parameterProviders
096: .size()];
097: for (int i = 0; i < parameters.length; i++) {
098: parameters[i] = parameterProviders.get(i).get();
099: }
100:
101: try {
102: return method.invoke(providers, parameters);
103: } catch (IllegalAccessException e) {
104: throw new AssertionError(e);
105: } catch (InvocationTargetException e) {
106: throw new RuntimeException(e);
107: }
108: }
109: };
110:
111: // TODO: Fix type warnings.
112: Class type = method.getReturnType();
113: if (scopeAnnotation == null && bindingAnnotation == null) {
114: bind(type).toProvider(provider);
115: } else if (scopeAnnotation == null) {
116: bind(type).annotatedWith(bindingAnnotation).toProvider(
117: provider);
118: } else if (bindingAnnotation == null) {
119: bind(type).toProvider(provider).in(scopeAnnotation);
120: } else {
121: bind(type).annotatedWith(bindingAnnotation).toProvider(
122: provider).in(scopeAnnotation);
123: }
124: }
125:
126: List<Provider<?>> findParameterProviders(Method method) {
127: List<Provider<?>> parameterProviders = new ArrayList<Provider<?>>();
128:
129: Type[] parameterTypes = method.getGenericParameterTypes();
130: Annotation[][] parameterAnnotations = method
131: .getParameterAnnotations();
132: for (int i = 0; i < parameterTypes.length; i++) {
133: Annotation bindingAnnotation = findBindingAnnotation(parameterAnnotations[i]);
134: Key<?> key = bindingAnnotation == null ? Key
135: .get(parameterTypes[i]) : Key.get(
136: parameterTypes[i], bindingAnnotation);
137: Provider<?> provider = getProvider(key);
138: parameterProviders.add(provider);
139: }
140:
141: return parameterProviders;
142: }
143:
144: Class<? extends Annotation> findScopeAnnotation(
145: Annotation[] annotations) {
146: Class<? extends Annotation> found = null;
147:
148: for (Annotation annotation : annotations) {
149: if (annotation.annotationType().isAnnotationPresent(
150: ScopeAnnotation.class)) {
151: if (found != null) {
152: addError(
153: ErrorMessages.DUPLICATE_SCOPE_ANNOTATIONS,
154: "@" + found.getSimpleName(), "@"
155: + annotation.annotationType()
156: .getSimpleName());
157: } else {
158: found = annotation.annotationType();
159: }
160: }
161: }
162:
163: return found;
164: }
165:
166: Annotation findBindingAnnotation(Annotation[] annotations) {
167: Annotation found = null;
168:
169: for (Annotation annotation : annotations) {
170: if (annotation.annotationType().isAnnotationPresent(
171: BindingAnnotation.class)) {
172: if (found != null) {
173: addError(
174: ErrorMessages.DUPLICATE_BINDING_ANNOTATIONS,
175: "@"
176: + found.annotationType()
177: .getSimpleName(), "@"
178: + annotation.annotationType()
179: .getSimpleName());
180: } else {
181: found = annotation;
182: }
183: }
184: }
185:
186: return found;
187: }
188: }
189: }
|