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