Home | History | Annotate | Download | only in annotation
      1 /*
      2  * Copyright (C) 2007 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.dexgen.rop.annotation;
     18 
     19 import com.android.dexgen.rop.cst.Constant;
     20 import com.android.dexgen.rop.cst.CstAnnotation;
     21 import com.android.dexgen.rop.cst.CstFieldRef;
     22 import com.android.dexgen.rop.cst.CstLiteralBits;
     23 import com.android.dexgen.rop.cst.CstMethodRef;
     24 import com.android.dexgen.rop.cst.CstNat;
     25 import com.android.dexgen.rop.cst.CstType;
     26 import com.android.dexgen.rop.cst.CstUtf8;
     27 import com.android.dexgen.rop.cst.TypedConstant;
     28 import com.android.dexgen.util.Hex;
     29 import com.android.dexgen.util.MutabilityControl;
     30 import com.android.dexgen.util.ToHuman;
     31 
     32 import java.util.Collection;
     33 import java.util.Collections;
     34 import java.util.Iterator;
     35 import java.util.TreeMap;
     36 
     37 /**
     38  * An annotation on an element of a class. Annotations have an
     39  * associated type and additionally consist of a set of (name, value)
     40  * pairs, where the names are unique.
     41  */
     42 public final class Annotation extends MutabilityControl
     43         implements Comparable<Annotation>, ToHuman {
     44     /** {@code non-null;} type of the annotation */
     45     private final CstType type;
     46 
     47     /** {@code non-null;} the visibility of the annotation */
     48     private final AnnotationVisibility visibility;
     49 
     50     /** {@code non-null;} map from names to {@link NameValuePair} instances */
     51     private final TreeMap<CstUtf8, NameValuePair> elements;
     52 
     53     /**
     54      * Construct an instance. It initially contains no elements.
     55      *
     56      * @param type {@code non-null;} type of the annotation
     57      * @param visibility {@code non-null;} the visibility of the annotation
     58      */
     59     public Annotation(CstType type, AnnotationVisibility visibility) {
     60         if (type == null) {
     61             throw new NullPointerException("type == null");
     62         }
     63 
     64         if (visibility == null) {
     65             throw new NullPointerException("visibility == null");
     66         }
     67 
     68         this.type = type;
     69         this.visibility = visibility;
     70         this.elements = new TreeMap<CstUtf8, NameValuePair>();
     71     }
     72 
     73     /** {@inheritDoc} */
     74     @Override
     75     public boolean equals(Object other) {
     76         if (! (other instanceof Annotation)) {
     77             return false;
     78         }
     79 
     80         Annotation otherAnnotation = (Annotation) other;
     81 
     82         if (! (type.equals(otherAnnotation.type)
     83                         && (visibility == otherAnnotation.visibility))) {
     84             return false;
     85         }
     86 
     87         return elements.equals(otherAnnotation.elements);
     88     }
     89 
     90     /** {@inheritDoc} */
     91     public int hashCode() {
     92         int hash = type.hashCode();
     93         hash = (hash * 31) + elements.hashCode();
     94         hash = (hash * 31) + visibility.hashCode();
     95         return hash;
     96     }
     97 
     98     /** {@inheritDoc} */
     99     public int compareTo(Annotation other) {
    100         int result = type.compareTo(other.type);
    101 
    102         if (result != 0) {
    103             return result;
    104         }
    105 
    106         result = visibility.compareTo(other.visibility);
    107 
    108         if (result != 0) {
    109             return result;
    110         }
    111 
    112         Iterator<NameValuePair> thisIter = elements.values().iterator();
    113         Iterator<NameValuePair> otherIter = other.elements.values().iterator();
    114 
    115         while (thisIter.hasNext() && otherIter.hasNext()) {
    116             NameValuePair thisOne = thisIter.next();
    117             NameValuePair otherOne = otherIter.next();
    118 
    119             result = thisOne.compareTo(otherOne);
    120             if (result != 0) {
    121                 return result;
    122             }
    123         }
    124 
    125         if (thisIter.hasNext()) {
    126             return 1;
    127         } else if (otherIter.hasNext()) {
    128             return -1;
    129         }
    130 
    131         return 0;
    132     }
    133 
    134     /** {@inheritDoc} */
    135     @Override
    136     public String toString() {
    137         return toHuman();
    138     }
    139 
    140     /** {@inheritDoc} */
    141     public String toHuman() {
    142         StringBuilder sb = new StringBuilder();
    143 
    144         sb.append(visibility.toHuman());
    145         sb.append("-annotation ");
    146         sb.append(type.toHuman());
    147         sb.append(" {");
    148 
    149         boolean first = true;
    150         for (NameValuePair pair : elements.values()) {
    151             if (first) {
    152                 first = false;
    153             } else {
    154                 sb.append(", ");
    155             }
    156             sb.append(pair.getName().toHuman());
    157             sb.append(": ");
    158             sb.append(pair.getValue().toHuman());
    159         }
    160 
    161         sb.append("}");
    162         return sb.toString();
    163     }
    164 
    165     /**
    166      * Gets the type of this instance.
    167      *
    168      * @return {@code non-null;} the type
    169      */
    170     public CstType getType() {
    171         return type;
    172     }
    173 
    174     /**
    175      * Gets the visibility of this instance.
    176      *
    177      * @return {@code non-null;} the visibility
    178      */
    179     public AnnotationVisibility getVisibility() {
    180         return visibility;
    181     }
    182 
    183     /**
    184      * Put an element into the set of (name, value) pairs for this instance.
    185      * If there is a preexisting element with the same name, it will be
    186      * replaced by this method.
    187      *
    188      * @param pair {@code non-null;} the (name, value) pair to place into this instance
    189      */
    190     public void put(NameValuePair pair) {
    191         throwIfImmutable();
    192 
    193         if (pair == null) {
    194             throw new NullPointerException("pair == null");
    195         }
    196 
    197         elements.put(pair.getName(), pair);
    198     }
    199 
    200     /**
    201      * Add an element to the set of (name, value) pairs for this instance.
    202      * It is an error to call this method if there is a preexisting element
    203      * with the same name.
    204      *
    205      * @param pair {@code non-null;} the (name, value) pair to add to this instance
    206      */
    207     public void add(NameValuePair pair) {
    208         throwIfImmutable();
    209 
    210         if (pair == null) {
    211             throw new NullPointerException("pair == null");
    212         }
    213 
    214         CstUtf8 name = pair.getName();
    215 
    216         if (elements.get(name) != null) {
    217             throw new IllegalArgumentException("name already added: " + name);
    218         }
    219 
    220         elements.put(name, pair);
    221     }
    222 
    223     /**
    224      * Gets the set of name-value pairs contained in this instance. The
    225      * result is always unmodifiable.
    226      *
    227      * @return {@code non-null;} the set of name-value pairs
    228      */
    229     public Collection<NameValuePair> getNameValuePairs() {
    230         return Collections.unmodifiableCollection(elements.values());
    231     }
    232 }
    233