home | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (Annotations.java)

This example Java source code file (Annotations.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

annotation, annotationchecker, boolean, cacheloader, class, deep_to_string_fn, errors, exception, map, member, method, object, override, reflection, string, util

The Annotations.java Java example source code

/**
 * Copyright (C) 2006 Google Inc.
 *
 * 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.google.inject.internal;

import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Joiner.MapJoiner;
import com.google.common.base.Preconditions;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.inject.BindingAnnotation;
import com.google.inject.Key;
import com.google.inject.ScopeAnnotation;
import com.google.inject.TypeLiteral;
import com.google.inject.internal.util.Classes;
import com.google.inject.name.Named;
import com.google.inject.name.Names;

import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;

import javax.inject.Qualifier;

/**
 * Annotation utilities.
 *
 * @author crazybob@google.com (Bob Lee)
 */
public class Annotations {

  /**
   * Returns {@code true} if the given annotation type has no attributes.
   */
  public static boolean isMarker(Class<? extends Annotation> annotationType) {
    return annotationType.getDeclaredMethods().length == 0;
  }

  public static boolean isAllDefaultMethods(Class<? extends Annotation> annotationType) {
    boolean hasMethods = false;
    for (Method m : annotationType.getDeclaredMethods()) {
      hasMethods = true;
      if (m.getDefaultValue() == null) {
        return false;
      }
    }
    return hasMethods;
  }

  private static final LoadingCache<Class cache =
      CacheBuilder.newBuilder().weakKeys().build(
          new CacheLoader<Class() {
            @Override
            public Annotation load(Class<? extends Annotation> input) {
              return generateAnnotationImpl(input);
            }
          });

  /**
   * Generates an Annotation for the annotation class. Requires that the annotation is all
   * optionals.
   */
  public static <T extends Annotation> T generateAnnotation(Class annotationType) {
    Preconditions.checkState(
        isAllDefaultMethods(annotationType), "%s is not all default methods", annotationType);
    return (T)cache.getUnchecked(annotationType);
  }

  private static <T extends Annotation> T generateAnnotationImpl(final Class annotationType) {
    final Map<String, Object> members = resolveMembers(annotationType);
    return annotationType.cast(Proxy.newProxyInstance(
        annotationType.getClassLoader(),
        new Class<?>[] { annotationType },
        new InvocationHandler() {
          @Override
          public Object invoke(Object proxy, Method method, Object[] args) throws Exception {
            String name = method.getName();
            if (name.equals("annotationType")) {
              return annotationType;
            } else if (name.equals("toString")) {
              return annotationToString(annotationType, members);
            } else if (name.equals("hashCode")) {
              return annotationHashCode(annotationType, members);
            } else if (name.equals("equals")) {
              return annotationEquals(annotationType, members, args[0]);
            } else {
              return members.get(name);
            }
          }
        }));
  }

  private static ImmutableMap<String, Object> resolveMembers(
      Class<? extends Annotation> annotationType) {
    ImmutableMap.Builder<String, Object> result = ImmutableMap.builder();
    for (Method method : annotationType.getDeclaredMethods()) {
      result.put(method.getName(), method.getDefaultValue());
    }
    return result.build();
  }

  /** Implements {@link Annotation#equals}. */
  private static boolean annotationEquals(Class<? extends Annotation> type,
      Map<String, Object> members, Object other) throws Exception {
    if (!type.isInstance(other)) {
      return false;
    }
    for (Method method : type.getDeclaredMethods()) {
      String name = method.getName();
      if (!Arrays.deepEquals(
          new Object[] {method.invoke(other)}, new Object[] {members.get(name)})) {
        return false;
      }
    }
    return true;
  }

  /** Implements {@link Annotation#hashCode}. */
  private static int annotationHashCode(Class<? extends Annotation> type,
      Map<String, Object> members) throws Exception {
    int result = 0;
    for (Method method : type.getDeclaredMethods()) {
      String name = method.getName();
      Object value = members.get(name);
      result += (127 * name.hashCode()) ^ (Arrays.deepHashCode(new Object[] {value}) - 31);
    }
    return result;
  }

  private static final MapJoiner JOINER = Joiner.on(", ").withKeyValueSeparator("=");

  private static final Function<Object, String> DEEP_TO_STRING_FN = new Function() {
    @Override
    public String apply(Object arg) {
      String s = Arrays.deepToString(new Object[] {arg});
      return s.substring(1, s.length() - 1); // cut off brackets
    }
  };

  /** Implements {@link Annotation#toString}. */
  private static String annotationToString(Class<? extends Annotation> type,
      Map<String, Object> members) throws Exception {
    StringBuilder sb = new StringBuilder().append("@").append(type.getName()).append("(");
    JOINER.appendTo(sb, Maps.transformValues(members, DEEP_TO_STRING_FN));
    return sb.append(")").toString();
  }

  /**
   * Returns true if the given annotation is retained at runtime.
   */
  public static boolean isRetainedAtRuntime(Class<? extends Annotation> annotationType) {
    Retention retention = annotationType.getAnnotation(Retention.class);
    return retention != null && retention.value() == RetentionPolicy.RUNTIME;
  }

  /** Returns the scope annotation on {@code type}, or null if none is specified. */
  public static Class<? extends Annotation> findScopeAnnotation(
      Errors errors, Class<?> implementation) {
    return findScopeAnnotation(errors, implementation.getAnnotations());
  }

  /** Returns the scoping annotation, or null if there isn't one. */
  public static Class<? extends Annotation> findScopeAnnotation(Errors errors, Annotation[] annotations) {
    Class<? extends Annotation> found = null;

    for (Annotation annotation : annotations) {
      Class<? extends Annotation> annotationType = annotation.annotationType();
      if (isScopeAnnotation(annotationType)) {
        if (found != null) {
          errors.duplicateScopeAnnotations(found, annotationType);
        } else {
          found = annotationType;
        }
      }
    }

    return found;
  }

  static boolean containsComponentAnnotation(Annotation[] annotations) {
    for (Annotation annotation : annotations) {
      // TODO(user): Should we scope this down to dagger.Component?
      if (annotation.annotationType().getSimpleName().equals("Component")) {
        return true;
      }
    }

    return false;
  }

  /**
   * Checks for the presence of annotations. Caches results because Android doesn't.
   */
  static class AnnotationChecker {
    private final Collection<Class annotationTypes;

    /** Returns true if the given class has one of the desired annotations. */
    private CacheLoader<Class hasAnnotations =
        new CacheLoader<Class() {
      public Boolean load(Class<? extends Annotation> annotationType) {
        for (Annotation annotation : annotationType.getAnnotations()) {
          if (annotationTypes.contains(annotation.annotationType())) {
            return true;
          }
        }
        return false;
      }
    };

    final LoadingCache<Class cache = CacheBuilder.newBuilder().weakKeys()
        .build(hasAnnotations);

    /**
     * Constructs a new checker that looks for annotations of the given types.
     */
    AnnotationChecker(Collection<Class annotationTypes) {
      this.annotationTypes = annotationTypes;
    }

    /**
     * Returns true if the given type has one of the desired annotations.
     */
    boolean hasAnnotations(Class<? extends Annotation> annotated) {
      return cache.getUnchecked(annotated);
    }
  }

  private static final AnnotationChecker scopeChecker = new AnnotationChecker(
      Arrays.asList(ScopeAnnotation.class, javax.inject.Scope.class));

  public static boolean isScopeAnnotation(Class<? extends Annotation> annotationType) {
    return scopeChecker.hasAnnotations(annotationType);
  }

  /**
   * Adds an error if there is a misplaced annotations on {@code type}. Scoping
   * annotations are not allowed on abstract classes or interfaces.
   */
  public static void checkForMisplacedScopeAnnotations(
      Class<?> type, Object source, Errors errors) {
    if (Classes.isConcrete(type)) {
      return;
    }

    Class<? extends Annotation> scopeAnnotation = findScopeAnnotation(errors, type);
    if (scopeAnnotation != null
        // We let Dagger Components through to aid migrations.
        && !containsComponentAnnotation(type.getAnnotations())) {
      errors.withSource(type).scopeAnnotationOnAbstractType(scopeAnnotation, type, source);
    }
  }

  /** Gets a key for the given type, member and annotations. */
  public static Key<?> getKey(TypeLiteral type, Member member, Annotation[] annotations,
      Errors errors) throws ErrorsException {
    int numErrorsBefore = errors.size();
    Annotation found = findBindingAnnotation(errors, member, annotations);
    errors.throwIfNewErrors(numErrorsBefore);
    return found == null ? Key.get(type) : Key.get(type, found);
  }

  /**
   * Returns the binding annotation on {@code member}, or null if there isn't one.
   */
  public static Annotation findBindingAnnotation(
      Errors errors, Member member, Annotation[] annotations) {
    Annotation found = null;

    for (Annotation annotation : annotations) {
      Class<? extends Annotation> annotationType = annotation.annotationType();
      if (isBindingAnnotation(annotationType)) {
        if (found != null) {
          errors.duplicateBindingAnnotations(member, found.annotationType(), annotationType);
        } else {
          found = annotation;
        }
      }
    }

    return found;
  }

  private static final AnnotationChecker bindingAnnotationChecker = new AnnotationChecker(
      Arrays.asList(BindingAnnotation.class, Qualifier.class));

  /**
   * Returns true if annotations of the specified type are binding annotations.
   */
  public static boolean isBindingAnnotation(Class<? extends Annotation> annotationType) {
    return bindingAnnotationChecker.hasAnnotations(annotationType);
  }

  /**
   * If the annotation is an instance of {@code javax.inject.Named}, canonicalizes to
   * com.google.guice.name.Named.  Returns the given annotation otherwise.
   */
  public static Annotation canonicalizeIfNamed(Annotation annotation) {
    if(annotation instanceof javax.inject.Named) {
      return Names.named(((javax.inject.Named)annotation).value());
    } else {
      return annotation;
    }
  }

  /**
   * If the annotation is the class {@code javax.inject.Named}, canonicalizes to
   * com.google.guice.name.Named. Returns the given annotation class otherwise.
   */
  public static Class<? extends Annotation> canonicalizeIfNamed(
      Class<? extends Annotation> annotationType) {
    if (annotationType == javax.inject.Named.class) {
      return Named.class;
    } else {
      return annotationType;
    }
  }
}

Other Java examples (source code examples)

Here is a short list of links related to this Java Annotations.java source code file:



my book on functional programming

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.