001 /*
002 * Copyright 2008-2014 the original author or authors.
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 */
016 package org.codehaus.griffon.runtime.core.injection;
017
018 import griffon.core.injection.*;
019 import griffon.util.AnnotationUtils;
020
021 import javax.annotation.Nonnull;
022 import javax.annotation.Nullable;
023 import javax.inject.Provider;
024 import javax.inject.Qualifier;
025 import java.lang.annotation.Annotation;
026 import java.util.List;
027
028 import static griffon.util.AnnotationUtils.harvestQualifiers;
029 import static java.util.Objects.requireNonNull;
030
031 /**
032 * @author Andres Almiray
033 * @since 2.0.0
034 */
035 public class Bindings {
036 public static <T> AnnotatedBindingBuilder<T> bind(@Nonnull Class<T> clazz) {
037 requireNonNull(clazz, "Argument 'class' must not be null");
038 return new AnnotatedBindingBuilderImpl<>(clazz);
039 }
040
041 private static abstract class SingletonBindingBuilderImpl<T> implements SingletonBindingBuilder<T> {
042 protected boolean singleton;
043
044 @Override
045 public void asSingleton() {
046 singleton = true;
047 }
048 }
049
050 private abstract static class LinkedBindingBuilderImpl<T> extends SingletonBindingBuilderImpl<T> implements LinkedBindingBuilder<T> {
051 protected Class<? extends T> target;
052 protected T instance;
053 protected Provider<T> provider;
054 protected Class<? extends Provider<T>> providerType;
055
056 @Nonnull
057 @Override
058 public SingletonBindingBuilder<T> to(@Nonnull Class<? extends T> target) {
059 this.target = requireNonNull(target, "Argument 'target' must not be null");
060 return this;
061 }
062
063 @Override
064 public void toInstance(@Nonnull T instance) {
065 this.instance = requireNonNull(instance, "Argument 'instance' must not be null");
066 }
067
068 @Nonnull
069 @Override
070 public SingletonBindingBuilder<T> toProvider(@Nonnull Provider<T> provider) {
071 this.provider = requireNonNull(provider, "Argument 'provider' must not be null");
072 return this;
073 }
074
075 @Nonnull
076 @Override
077 public SingletonBindingBuilder<T> toProvider(@Nonnull Class<? extends Provider<T>> providerType) {
078 this.providerType = requireNonNull(providerType, "Argument 'providerType' must not be null");
079 return this;
080 }
081 }
082
083 private static class AnnotatedBindingBuilderImpl<T> extends LinkedBindingBuilderImpl<T> implements AnnotatedBindingBuilder<T> {
084 private final Class<T> source;
085 private Annotation classifier;
086 private Class<? extends Annotation> classifierType;
087
088 private AnnotatedBindingBuilderImpl(@Nonnull Class<T> source) {
089 this.source = requireNonNull(source, "Argument 'source' must not be null");
090 }
091
092 @Nonnull
093 @Override
094 public Binding<T> getBinding() {
095 if (instance != null) {
096 return classifier != null ? new InstanceBindingImpl<>(source, classifier, instance) : new InstanceBindingImpl<>(source, classifierType, instance);
097 } else if (providerType != null) {
098 return classifier != null ? new ProviderTypeBindingImpl<>(source, providerType, classifier, singleton) : new ProviderTypeBindingImpl<>(source, providerType, classifierType, singleton);
099 } else if (provider != null) {
100 return classifier != null ? new ProviderBindingImpl<>(source, provider, classifier, singleton) : new ProviderBindingImpl<>(source, provider, classifierType, singleton);
101 } else if (target != null) {
102 return classifier != null ? new TargetBindingImpl<>(source, target, classifier, singleton) : new TargetBindingImpl<>(source, target, classifierType, singleton);
103 }
104
105 return classifier != null ? new TargetBindingImpl<>(source, source, classifier, singleton) : new TargetBindingImpl<>(source, source, classifierType, singleton);
106 }
107
108 @Nonnull
109 @Override
110 public LinkedBindingBuilder<T> withClassifier(@Nonnull Class<? extends Annotation> annotationType) {
111 requireNonNull(annotationType, "Argument 'annotationType' must not be null");
112 AnnotationUtils.requireAnnotation(annotationType, Qualifier.class);
113 this.classifierType = annotationType;
114 return this;
115 }
116
117 @Nonnull
118 @Override
119 public LinkedBindingBuilder<T> withClassifier(@Nonnull Annotation annotation) {
120 requireNonNull(annotation, "Argument 'annotation' must not be null");
121 this.classifier = annotation;
122 withClassifier(annotation.getClass());
123 return this;
124 }
125 }
126
127 private static abstract class AbstractBindingImpl<T> implements Binding<T> {
128 protected final Class<T> source;
129 protected final boolean singleton;
130 protected Annotation classifier;
131 protected Class<? extends Annotation> classifierType;
132
133 protected AbstractBindingImpl(@Nonnull Class<T> source, @Nonnull Annotation classifier, boolean singleton) {
134 this.source = source;
135 this.singleton = singleton;
136 this.classifier = classifier;
137 this.classifierType = classifier.getClass();
138 }
139
140 protected AbstractBindingImpl(@Nonnull Class<T> source, @Nonnull Class<? extends Annotation> classifierType, boolean singleton) {
141 this.source = source;
142 this.singleton = singleton;
143 this.classifierType = classifierType;
144 }
145
146 @Nonnull
147 @Override
148 public Class<T> getSource() {
149 return source;
150 }
151
152 @Nullable
153 @Override
154 public Class<? extends Annotation> getClassifierType() {
155 return classifierType;
156 }
157
158 @Nullable
159 @Override
160 public Annotation getClassifier() {
161 return classifier;
162 }
163
164 @Override
165 public boolean isSingleton() {
166 return singleton;
167 }
168
169 protected void updateClassifier(Class<?> klass) {
170 if (this.classifier == null) {
171 List<Annotation> qualifiers = harvestQualifiers(klass);
172 if (!qualifiers.isEmpty()) {
173 this.classifier = qualifiers.get(0);
174 }
175 }
176 }
177
178 protected void updateClassifierType(Class<?> klass) {
179 if (this.classifierType == null) {
180 List<Annotation> qualifiers = harvestQualifiers(klass);
181 if (!qualifiers.isEmpty()) {
182 this.classifier = qualifiers.get(0);
183 }
184 }
185 }
186 }
187
188 private static class TargetBindingImpl<T> extends AbstractBindingImpl<T> implements TargetBinding<T> {
189 private final Class<? extends T> target;
190
191 private TargetBindingImpl(@Nonnull Class<T> source, @Nonnull Class<? extends T> target, @Nonnull Annotation classifier, boolean singleton) {
192 super(source, classifier, singleton);
193 this.target = target;
194 updateClassifier(target);
195 }
196
197 private TargetBindingImpl(@Nonnull Class<T> source, @Nonnull Class<? extends T> target, @Nonnull Class<? extends Annotation> classifierType, boolean singleton) {
198 super(source, classifierType, singleton);
199 this.target = target;
200 updateClassifierType(target);
201 }
202
203 @Nonnull
204 @Override
205 public Class<? extends T> getTarget() {
206 return target;
207 }
208
209 @Override
210 public String toString() {
211 final StringBuilder sb = new StringBuilder("TargetBinding[");
212 sb.append("source=").append(source.getName());
213 if (classifier != null) {
214 sb.append(", classifier=").append(classifier);
215 } else if (classifierType != null) {
216 sb.append(", classifierType=").append(classifierType.getName());
217 }
218 sb.append(", target=").append(target.getName());
219 sb.append(", singleton=").append(singleton);
220 sb.append(']');
221 return sb.toString();
222 }
223 }
224
225 private static class InstanceBindingImpl<T> extends AbstractBindingImpl<T> implements InstanceBinding<T> {
226 private final T instance;
227
228 protected InstanceBindingImpl(@Nonnull Class<T> source, @Nonnull Annotation classifier, @Nonnull T instance) {
229 super(source, classifier, true);
230 this.instance = instance;
231 updateClassifier(instance.getClass());
232 }
233
234 protected InstanceBindingImpl(@Nonnull Class<T> source, @Nonnull Class<? extends Annotation> classifierType, @Nonnull T instance) {
235 super(source, classifierType, true);
236 this.instance = instance;
237 updateClassifierType(instance.getClass());
238 }
239
240 @Nonnull
241 @Override
242 public T getInstance() {
243 return instance;
244 }
245
246 @Override
247 public String toString() {
248 final StringBuilder sb = new StringBuilder("InstanceBinding[");
249 sb.append("source=").append(source.getName());
250 if (classifier != null) {
251 sb.append(", classifier=").append(classifier);
252 } else if (classifierType != null) {
253 sb.append(", classifierType=").append(classifierType.getName());
254 }
255 sb.append(", instance=").append(instance);
256 sb.append(", singleton=").append(singleton);
257 sb.append(']');
258 return sb.toString();
259 }
260 }
261
262 private static class ProviderBindingImpl<T> extends AbstractBindingImpl<T> implements ProviderBinding<T> {
263 private final Provider<T> provider;
264
265 private ProviderBindingImpl(@Nonnull Class<T> source, @Nonnull Provider<T> provider, @Nonnull Annotation classifier, boolean singleton) {
266 super(source, classifier, singleton);
267 this.provider = provider;
268 updateClassifier(provider.getClass());
269 }
270
271
272 private ProviderBindingImpl(@Nonnull Class<T> source, @Nonnull Provider<T> provider, @Nonnull Class<? extends Annotation> classifierType, boolean singleton) {
273 super(source, classifierType, singleton);
274 this.provider = provider;
275 updateClassifierType(provider.getClass());
276 }
277
278 @Nonnull
279 @Override
280 public Provider<T> getProvider() {
281 return provider;
282 }
283
284 @Override
285 public String toString() {
286 final StringBuilder sb = new StringBuilder("ProviderBinding[");
287 sb.append("source=").append(source.getName());
288 if (classifier != null) {
289 sb.append(", classifier=").append(classifier);
290 } else if (classifierType != null) {
291 sb.append(", classifierType=").append(classifierType.getName());
292 }
293 sb.append(", provider=").append(provider);
294 sb.append(", singleton=").append(singleton);
295 sb.append(']');
296 return sb.toString();
297 }
298 }
299
300 private static class ProviderTypeBindingImpl<T> extends AbstractBindingImpl<T> implements ProviderTypeBinding<T> {
301 private final Class<? extends Provider<T>> providerType;
302
303 private ProviderTypeBindingImpl(@Nonnull Class<T> source, @Nonnull Class<? extends Provider<T>> providerType, @Nonnull Annotation classifier, boolean singleton) {
304 super(source, classifier, singleton);
305 this.providerType = providerType;
306 updateClassifier(providerType);
307 }
308
309
310 private ProviderTypeBindingImpl(@Nonnull Class<T> source, @Nonnull Class<? extends Provider<T>> providerType, @Nonnull Class<? extends Annotation> classifierType, boolean singleton) {
311 super(source, classifierType, singleton);
312 this.providerType = providerType;
313 updateClassifierType(providerType);
314 }
315
316 @Nonnull
317 @Override
318 public Class<? extends Provider<T>> getProviderType() {
319 return providerType;
320 }
321
322 @Override
323 public String toString() {
324 final StringBuilder sb = new StringBuilder("ProviderTypeBinding[");
325 sb.append("source=").append(source.getName());
326 if (classifier != null) {
327 sb.append(", classifier=").append(classifier);
328 } else if (classifierType != null) {
329 sb.append(", classifierType=").append(classifierType.getName());
330 }
331 sb.append(", providerType=").append(providerType);
332 sb.append(", singleton=").append(singleton);
333 sb.append(']');
334 return sb.toString();
335 }
336 }
337 }
|