/* Software Name : AsmDex * Version : 1.0 * * Copyright © 2012 France Télécom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.ow2.asmdex.structureWriter; import java.util.Arrays; import java.util.PriorityQueue; import org.ow2.asmdex.Constants; import org.ow2.asmdex.Opcodes; /** * An Annotation Item (from the annotation_item structure). * * Consists in Encoded Values (annotation_elements actually), sorted by string_id, as well as * the visibility and the Type of the Annotation. * * An annotation_item is used to represent the various fields of an Annotation : * {@literal @}MyAnnotation(a=5, b=true) * myItem. * * Equals and HashCode are overridden so that they can be rightly stored into a HashSet. * Also overrides CompareTo in order to be sorted by type_id, as requested by annotation_set_item. * * CompareTo uses cached lists, as the PriorityQueue doesn't guarantee a traversal order, we have to sort them * and build an array, which is only build when and if necessary. * * @author Julien Névo * */ public class AnnotationItem implements Comparable<AnnotationItem> { /** * Visibility of the Annotation Item (see {@link Opcodes#VISIBILITY_BUILD}, * {@link Opcodes#VISIBILITY_RUNTIME}, {@link Opcodes#VISIBILITY_SYSTEM}). */ final private int visibility; // from annotation_item. /** * Type of the Annotation. */ final private String annotationType; // from encoded_annotation. /** * Set of the Annotation Elements, sorted by string_id. */ private PriorityQueue<AnnotationElement> annotationElements = new PriorityQueue<AnnotationElement>(); /** * Indicates if the list of elements has been modified. */ private boolean isListDirty = true; /** * Array of the Annotation Elements. This is useful for compareTo. This list is private and * is build when compareTo needs it, and only if it has changed to prevent overhead. */ private AnnotationElement[] annotationElementsArray; /** * The hashcode is cached. */ private int hashcode = Constants.HASHCODE_NOT_CALCULATED; /** * @param visibility visibility of the Annotation Item (see {@link Opcodes#VISIBILITY_BUILD}, * {@link Opcodes#VISIBILITY_RUNTIME}, {@link Opcodes#VISIBILITY_SYSTEM}). * @param annotationType type of the Annotation. */ public AnnotationItem(int visibility, String annotationType) { this.visibility = visibility; this.annotationType = annotationType; } /** * @param visible indicates whether the Annotation Item is visible at Run Time. * @param annotationType type of the Annotation. */ public AnnotationItem(boolean visible, String annotationType) { this(visible ? Opcodes.VISIBILITY_RUNTIME : Opcodes.VISIBILITY_BUILD, annotationType); } // ----------------------------------------------------- // Public methods. // ----------------------------------------------------- /** * Adds an Annotation Element to the sorted list. * @param annotationElement the Annotation Element to add. */ public void addAnnotationElement(AnnotationElement annotationElement) { annotationElements.add(annotationElement); hashcode = Constants.HASHCODE_NOT_CALCULATED; // Resets the hashcode. isListDirty = true; } // ----------------------------------------------------- // Getters and Setters. // ----------------------------------------------------- /** * Returns the item visibility (see {@link Opcodes#VISIBILITY_BUILD}, * {@link Opcodes#VISIBILITY_RUNTIME}, {@link Opcodes#VISIBILITY_SYSTEM}). * @return the item visibility. */ public int getVisibility() { return visibility; } /** * Returns the Annotation Type. * @return the Annotation Type. */ public String getAnnotationType() { return annotationType; } /** * Returns the Annotation Element, sorted by string_id. * @return the Annotation Element, sorted by string_id. */ public PriorityQueue<AnnotationElement> getAnnotationElements() { return annotationElements; } /** * Returns the number of Annotation elements currently hold by the Item. * @return the number of Annotation elements currently hold by the Item. */ public int getNbAnnotationElements() { return annotationElements.size(); } // ---------------------------------------------- // Private methods. // ---------------------------------------------- /** * Returns an array of Annotation Elements. It may be build if the list has changed. * @return an array of Annotation Elements. */ private AnnotationElement[] getAnnotationElementsArray() { if (!isListDirty) { return annotationElementsArray; } else { Object[] array = annotationElements.toArray(); Arrays.sort(array); int size = array.length; annotationElementsArray = new AnnotationElement[size]; for (int i = 0; i < size; i++) { annotationElementsArray[i] = (AnnotationElement)array[i]; } return annotationElementsArray; } } // ---------------------------------------------- // Overridden methods. // ---------------------------------------------- @Override public boolean equals(Object o) { if (this == o) { return true; } boolean result = false; if (o instanceof AnnotationItem) { AnnotationItem annotationItem = (AnnotationItem)o; result = ((visibility == annotationItem.visibility) && (annotationType.equals(annotationItem.annotationType))); if (result) { int size = annotationElements.size(); if (size == annotationItem.annotationElements.size()) { for (AnnotationElement element : annotationElements) { result = annotationItem.annotationElements.contains(element); if (!result) { break; } } } } } return result; } @Override public int hashCode() { if (hashcode != Constants.HASHCODE_NOT_CALCULATED) { return hashcode; } int res = visibility + annotationType.hashCode(); for (AnnotationElement element : annotationElements) { res += element.hashCode(); } hashcode = res; return res; } @Override public int compareTo(AnnotationItem ai) { if (this == ai) { return 0; } // Tests the type. int result = annotationType.compareTo(ai.annotationType); if (result == 0) { // Tests each element. The lists have been cached. AnnotationElement[] ae1 = getAnnotationElementsArray(); AnnotationElement[] ae2 = ai.getAnnotationElementsArray(); int size1 = ae1.length; int size2 = ae2.length; int i = 0; int size = (size1 < size2 ? size1 : size2); while ((result == 0) && (i < size)) { result = ae1[i].compareTo(ae2[i]); i++; } if (result == 0) { result = size1 == size2 ? 0 : (size1 < size2 ? -1 : 1); } } return result; } }