diff options
author | Tavian Barnes <tavianator@tavianator.com> | 2014-05-07 21:32:35 -0400 |
---|---|---|
committer | Tavian Barnes <tavianator@tavianator.com> | 2014-05-07 21:32:35 -0400 |
commit | 1eeacfdd9d747c2add6957794e541e3a022218a7 (patch) | |
tree | 379cb88477ca5d67361c34ebdec2ac8293eb040c /sangria-core/src/main/java/com | |
parent | 505b147bd23e26d21932af2c3336c9f4607bbcce (diff) | |
download | sangria-1eeacfdd9d747c2add6957794e541e3a022218a7.tar.xz |
core: Add PotentialAnnotation helper to store different annotation possibilities (none, type, insance).
Diffstat (limited to 'sangria-core/src/main/java/com')
-rw-r--r-- | sangria-core/src/main/java/com/tavianator/sangria/core/PotentialAnnotation.java | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/sangria-core/src/main/java/com/tavianator/sangria/core/PotentialAnnotation.java b/sangria-core/src/main/java/com/tavianator/sangria/core/PotentialAnnotation.java new file mode 100644 index 0000000..302e5e1 --- /dev/null +++ b/sangria-core/src/main/java/com/tavianator/sangria/core/PotentialAnnotation.java @@ -0,0 +1,241 @@ +/**************************************************************************** + * Sangria * + * Copyright (C) 2014 Tavian Barnes <tavianator@tavianator.com> * + * * + * 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.tavianator.sangria.core; + +import java.lang.annotation.Annotation; +import java.util.*; + +import com.google.inject.CreationException; +import com.google.inject.Key; +import com.google.inject.TypeLiteral; +import com.google.inject.spi.Message; + +/** + * A record of stored annotations, perfect for builders with {@code annotatedWith()} methods. + * + * @author Tavian Barnes (tavianator@tavianator.com) + * @version 1.1 + * @since 1.1 + */ +public abstract class PotentialAnnotation { + /** + * A visitor interface to examine a {@link PotentialAnnotation}'s annotation, if it exists. + * + * @param <T> The type to return. + * @author Tavian Barnes (tavianator@tavianator.com) + * @version 1.1 + * @since 1.1 + */ + public interface Visitor<T> { + /** + * Called when there is no annotation. + * + * @return Any value. + */ + T visitNoAnnotation(); + + /** + * Called when an annotation type is stored. + * + * @param annotationType The annotation type. + * @return Any value. + */ + T visitAnnotationType(Class<? extends Annotation> annotationType); + + /** + * Called when an annotation instance is stored. + * + * @param annotation The annotation instance. + * @return Any value. + */ + T visitAnnotationInstance(Annotation annotation); + } + + private static final PotentialAnnotation NONE = new NoAnnotation(); + + /** + * @return A {@link PotentialAnnotation} with no annotation. + */ + public static PotentialAnnotation none() { + return NONE; + } + + private PotentialAnnotation() { + } + + /** + * Add an annotation. + * + * @param annotationType The annotation type to add. + * @return A new {@link PotentialAnnotation} associated with the given annotation type. + * @throws CreationException If an annotation is already present. + */ + public PotentialAnnotation annotatedWith(Class<? extends Annotation> annotationType) { + throw annotationAlreadyPresent(); + } + + /** + * Add an annotation. + * + * @param annotation The annotation instance to add. + * @return A new {@link PotentialAnnotation} associated with the given annotation instance. + * @throws CreationException If an annotation is already present. + */ + public PotentialAnnotation annotatedWith(Annotation annotation) { + throw annotationAlreadyPresent(); + } + + private CreationException annotationAlreadyPresent() { + Message message = new Message("An annotation was already present"); + return new CreationException(Collections.singletonList(message)); + } + + /** + * @return Whether an annotation is present. + */ + public abstract boolean hasAnnotation(); + + /** + * Create a {@link Key} with the given type and the stored annotation. + * + * @param type The type of the key to create. + * @param <T> The type of the key to create. + * @return A {@link Key}. + */ + public <T> Key<T> getKey(Class<T> type) { + return getKey(TypeLiteral.get(type)); + } + + /** + * Create a {@link Key} with the given type and the stored annotation. + * + * @param type The type of the key to create. + * @param <T> The type of the key to create. + * @return A {@link Key}. + */ + public abstract <T> Key<T> getKey(TypeLiteral<T> type); + + /** + * Accept a {@link Visitor}. + * + * @param visitor The visitor to accept. + * @param <T> The type for the visitor to return. + * @return The value produced by the visitor. + */ + public abstract <T> T accept(Visitor<T> visitor); + + @Override + public abstract String toString(); + + /** + * Implementation of {@link #none()}. + */ + private static class NoAnnotation extends PotentialAnnotation { + @Override + public PotentialAnnotation annotatedWith(Class<? extends Annotation> annotationType) { + return new AnnotationType(annotationType); + } + + @Override + public PotentialAnnotation annotatedWith(Annotation annotation) { + return new AnnotationInstance(annotation); + } + + @Override + public boolean hasAnnotation() { + return false; + } + + @Override + public <T> Key<T> getKey(TypeLiteral<T> type) { + return Key.get(type); + } + + @Override + public <T> T accept(Visitor<T> visitor) { + return visitor.visitNoAnnotation(); + } + + @Override + public String toString() { + return "[no annotation]"; + } + } + + /** + * Implementation of {@link #annotatedWith(Class)}. + */ + private static class AnnotationType extends PotentialAnnotation { + private final Class<? extends Annotation> annotationType; + + AnnotationType(Class<? extends Annotation> annotationType) { + this.annotationType = annotationType; + } + + @Override + public boolean hasAnnotation() { + return true; + } + + @Override + public <T> Key<T> getKey(TypeLiteral<T> type) { + return Key.get(type, annotationType); + } + + @Override + public <T> T accept(Visitor<T> visitor) { + return visitor.visitAnnotationType(annotationType); + } + + @Override + public String toString() { + return "@" + annotationType.getCanonicalName(); + } + } + + /** + * Implementation of {@link #annotatedWith(Annotation)}. + */ + private static class AnnotationInstance extends PotentialAnnotation { + private final Annotation annotation; + + AnnotationInstance(Annotation annotation) { + this.annotation = annotation; + } + + @Override + public boolean hasAnnotation() { + return true; + } + + @Override + public <T> Key<T> getKey(TypeLiteral<T> type) { + return Key.get(type, annotation); + } + + @Override + public <T> T accept(Visitor<T> visitor) { + return visitor.visitAnnotationInstance(annotation); + } + + @Override + public String toString() { + return annotation.toString(); + } + } +} |