org.javabits.yar.Ids Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of yar-api Show documentation
Show all versions of yar-api Show documentation
Yar API: provide the main interfaces to manipulate the registry
package org.javabits.yar;
import javax.annotation.Nullable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import static java.util.Objects.requireNonNull;
import static org.javabits.yar.Annotations.checkRuntimeRetention;
/**
* This class provides utility methods to construct and deal with {@link Id}.
* This class provide 3 main ways to build {@code Id}:
*
* - from {@code Class}
* - from {@code TypeToken}
* - from {@code Type}
*
* As follow:
* Class based construction:
*
* Ids.newId(MyInterface.class);
* Ids.newId(MyInterface.class, MyAnnotation.class);
* Ids.newId(MyInterface.class, Names.named("my-name"));
*
* TypeToken based construction:
*
* Ids.newId(new TypeToken>(){});
* Ids.newId(new TypeToken>(){}, MyAnnotation.class);
* Ids.newId(new TypeToken>(){}, Names.named("my-name"));
*
* Type based construction
*
* Ids.newId(aMethod.getGenericParameterTypes()[0]);
* Ids.newId(aMethod.getGenericParameterTypes()[0], MyAnnotation.class);
* Ids.newId(aMethod.getGenericParameterTypes()[0], Names.named("my-name"));
*
*
* @author Romain Gilles
*/
public final class Ids {
private Ids() {
throw new AssertionError("Not for you!");
}
/**
* Returns a new {@link Id} for the given type.
*
* @param type the {@code Type} from which the {@code Id} must be constructed.
* @param the type of the Id.
* @return an new {@code Id} based on the given type.
*/
@SuppressWarnings("unchecked")
public static Id newId(final Class type) {
return (Id) newId((Type) type);
}
/**
* Returns a new {@link Id} which represents the {@code type} qualified by
* the {@code annotationClass}.
*
* @param type the type to which the new id has to be associated.
* @param annotationClass the qualifying annotation type.
* @param the type of the id.
* @return an new {@code Id} based on the given type and annotation type.
*/
@SuppressWarnings("unchecked")
public static Id newId(final Class type, final Class extends Annotation> annotationClass) {
return (Id) newId((Type) type, annotationClass);
}
/**
* Returns a new {@link Id} which represents the {@code type} qualified by
* the {@code annotation} instance.
*
* @param type the type to which the new id has to be associated.
* @param annotation the qualifying annotation.
* @param the type of the id.
* @return an new {@code Id} based on the given type and annotation.
*/
@SuppressWarnings("unchecked")
public static Id newId(final Class type, final Annotation annotation) {
return (Id) newId((Type) type, annotation);
}
/**
* Returns a new {@link Id} which represents the {@code type}.
*
* @param type the type to which the new id has to be associated.
* @return an new {@code Id} based on the given type.
*/
public static Id> newId(final Type type) {
return IdImpl.newId(type);
}
/**
* Returns a new {@link Id} which represents the {@code type} qualified by
* the {@code annotationClass}.
*
* @param type the type to which the new id has to be associated.
* @param annotationClass the qualifying annotation type.
* @return an new {@code Id} based on the given type and annotation type.
*/
public static Id> newId(final Type type, final Class extends Annotation> annotationClass) {
return IdImpl.newId(type, annotationClass);
}
/**
* Returns a new {@link Id} which represents the {@code type} qualified by
* the {@code annotation} instance.
*
* @param type the type to which the new id has to be associated.
* @param annotation the qualifying annotation.
* @return an new {@code Id} based on the given type and annotation.
*/
public static Id> newId(final Type type, final Annotation annotation) {
return IdImpl.newId(type, annotation);
}
static final class IdImpl implements Id {
private final Type type;
private final AnnotationStrategy annotationStrategy;
private final int hashCode;
private IdImpl(Type type, AnnotationStrategy annotationStrategy) {
this.type = requireNonNull(type, "type");
this.annotationStrategy = requireNonNull(annotationStrategy, "annotationStrategy");
this.hashCode = computeHashCode(type, annotationStrategy);
}
private static Id> newId(final Type type) {
return new IdImpl<>(type, AbstractAnnotationStrategy.NULL_STRATEGY);
}
private static Id> newId(final Type type, final Class extends Annotation> annotationClass) {
return new IdImpl<>(type, AbstractAnnotationStrategy.strategyFor(annotationClass));
}
private static Id> newId(final Type type, final Annotation annotation) {
return new IdImpl<>(type, AbstractAnnotationStrategy.strategyFor(annotation));
}
@Override
public Type type() {
return type;
}
@Override
public Class extends Annotation> annotationType() {
return annotationStrategy.getAnnotationType();
}
@Override
public Annotation annotation() {
return annotationStrategy.getAnnotation();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
IdImpl id = (IdImpl) o;
return annotationStrategy.equals(id.annotationStrategy) && type.equals(id.type);
}
@Override
public int hashCode() {
return hashCode;
}
private int computeHashCode(Type type, AnnotationStrategy annotationStrategy) {
int result = requireNonNull(type, "type").hashCode();
result = 31 * result + requireNonNull(annotationStrategy, "annotationStrategy").hashCode();
return result;
}
@Override
public String toString() {
return "Id[type=" + toString(type) + ", annotation=" + annotationStrategy + "]";
}
static String toString(Type type) {
return (type instanceof Class)
? ((Class>) type).getName()
: type.toString();
}
interface AnnotationStrategy {
@Nullable
Annotation getAnnotation();
@Nullable
Class extends Annotation> getAnnotationType();
@Override
int hashCode();
@Override
boolean equals(Object o);
}
static abstract class AbstractAnnotationStrategy implements AnnotationStrategy {
static final AnnotationStrategy NULL_STRATEGY = new NullAnnotationStrategy();
static AnnotationStrategy strategyFor(Class extends Annotation> annotationClass) {
return new TypeAnnotationStrategy(annotationClass);
}
public static AnnotationStrategy strategyFor(Annotation annotation) {
if (Annotations.isMarker(annotation)) {
return new TypeAnnotationStrategy(annotation.annotationType());
}
return new InstanceAnnotationStrategy(annotation);
}
}
static final class NullAnnotationStrategy extends AbstractAnnotationStrategy {
NullAnnotationStrategy() {
}
@Nullable
@Override
public Annotation getAnnotation() {
return null;
}
@Override
public Class extends Annotation> getAnnotationType() {
return null;
}
@Override
public String toString() {
return "[none]";
}
}
static final class TypeAnnotationStrategy extends AbstractAnnotationStrategy {
private final Class extends Annotation> annotationClass;
TypeAnnotationStrategy(Class extends Annotation> annotationClass) {
this.annotationClass = checkRuntimeRetention(annotationClass, "annotationClass");
}
@Override
public Annotation getAnnotation() {
return null;
}
@Override
public Class extends Annotation> getAnnotationType() {
return annotationClass;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TypeAnnotationStrategy that = (TypeAnnotationStrategy) o;
return annotationClass.equals(that.annotationClass);
}
@Override
public int hashCode() {
return annotationClass.hashCode();
}
@Override
public String toString() {
return "@" + annotationClass.toString();
}
}
static final class InstanceAnnotationStrategy extends AbstractAnnotationStrategy {
private final Annotation annotation;
InstanceAnnotationStrategy(Annotation annotation) {
this.annotation = annotation;
}
@Nullable
@Override
public Annotation getAnnotation() {
return annotation;
}
@Override
public Class extends Annotation> getAnnotationType() {
return annotation.annotationType();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
InstanceAnnotationStrategy that = (InstanceAnnotationStrategy) o;
return annotation.equals(that.annotation);
}
@Override
public int hashCode() {
return annotation.hashCode();
}
@Override
public String toString() {
return annotation.toString();
}
}
}
}