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