| /* |
| * Copyright 2007 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.gwt.dev.javac.typemodel; |
| |
| import com.google.gwt.core.ext.typeinfo.HasAnnotations; |
| import com.google.gwt.dev.util.collect.HashMap; |
| import com.google.gwt.dev.util.collect.Maps; |
| |
| import java.lang.annotation.Annotation; |
| import java.lang.annotation.Inherited; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| |
| /** |
| * An implementation of the {@link HasAnnotations} interface that supports inheritance |
| * of annotations. This is a mutable type, but it's an error to change it after doing |
| * a query that looks at inherited annotations. |
| */ |
| class Annotations implements HasAnnotations { |
| |
| static final Comparator<Annotation> ANNOTATION_COMPARATOR = new Comparator<Annotation>() { |
| /** |
| * An element can only be annotated with one annotation of a particular |
| * type. So we only need to sort by annotation type name, since there won't |
| * be any duplicates. |
| */ |
| @Override |
| public int compare(Annotation o1, Annotation o2) { |
| return o1.annotationType().getName().compareTo( |
| o2.annotationType().getName()); |
| } |
| }; |
| |
| /** |
| * All annotations declared on the annotated element. |
| */ |
| private Map<Class<? extends Annotation>, Annotation> declaredAnnotations; |
| |
| /** |
| * Lazily initialized collection of annotations declared on or inherited by |
| * the annotated element. |
| */ |
| private Map<Class<? extends Annotation>, Annotation> lazyAnnotations = null; |
| |
| /** |
| * If not <code>null</code> the parent to inherit annotations from. |
| */ |
| private Annotations parent; |
| |
| Annotations() { |
| this.declaredAnnotations = Maps.create(); |
| } |
| |
| Annotations(Map<Class<? extends Annotation>, Annotation> declaredAnnotations) { |
| this.declaredAnnotations = Maps.normalize(declaredAnnotations); |
| } |
| |
| /** |
| * Adds annotations to the set. It's an error to call this after calling |
| * {@link #getAnnotation}, {@link #getAnnotations}, or |
| * {@link #isAnnotationPresent}. |
| */ |
| public void addAnnotations( |
| Map<Class<? extends Annotation>, Annotation> additions) { |
| assert lazyAnnotations == null; |
| if (additions != null) { |
| assert (!additions.containsValue(null)); |
| declaredAnnotations = Maps.putAll(declaredAnnotations, additions); |
| } |
| } |
| |
| @Override |
| public <T extends Annotation> T getAnnotation(Class<T> annotationClass) { |
| initializeAnnotations(); |
| return annotationClass.cast(lazyAnnotations.get(annotationClass)); |
| } |
| |
| @Override |
| public Annotation[] getAnnotations() { |
| initializeAnnotations(); |
| List<Annotation> values = new ArrayList<Annotation>(lazyAnnotations.values()); |
| Collections.sort(values, ANNOTATION_COMPARATOR); |
| return values.toArray(new Annotation[values.size()]); |
| } |
| |
| @Override |
| public Annotation[] getDeclaredAnnotations() { |
| List<Annotation> values = new ArrayList<Annotation>( |
| declaredAnnotations.values()); |
| Collections.sort(values, ANNOTATION_COMPARATOR); |
| return values.toArray(new Annotation[values.size()]); |
| } |
| |
| @Override |
| public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) { |
| return getAnnotation(annotationClass) != null; |
| } |
| |
| /** |
| * Sets a parent to inherit annotations from, or null to clear. It's an error to call |
| * this after calling {@link #getAnnotation}, {@link #getAnnotations}, or |
| * {@link #isAnnotationPresent}. |
| */ |
| void setParent(Annotations parent) { |
| assert lazyAnnotations == null; |
| this.parent = parent; |
| } |
| |
| private void initializeAnnotations() { |
| if (lazyAnnotations != null) { |
| return; |
| } |
| |
| if (parent != null) { |
| lazyAnnotations = new HashMap<Class<? extends Annotation>, Annotation>(); |
| parent.initializeAnnotations(); |
| for (Entry<Class<? extends Annotation>, Annotation> entry : parent.lazyAnnotations.entrySet()) { |
| if (entry.getValue().annotationType().isAnnotationPresent( |
| Inherited.class)) { |
| lazyAnnotations.put(entry.getKey(), entry.getValue()); |
| } |
| } |
| |
| lazyAnnotations.putAll(declaredAnnotations); |
| lazyAnnotations = Maps.normalize(lazyAnnotations); |
| } else { |
| lazyAnnotations = declaredAnnotations; |
| } |
| } |
| } |