All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.snapscript.dx.dex.file.AnnotationsDirectoryItem Maven / Gradle / Ivy

/*
 * Copyright (C) 2008 The Android Open Source Project
 *
 * 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 org.snapscript.dx.dex.file;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;

import org.snapscript.dx.rop.annotation.Annotations;
import org.snapscript.dx.rop.annotation.AnnotationsList;
import org.snapscript.dx.rop.cst.CstFieldRef;
import org.snapscript.dx.rop.cst.CstMethodRef;
import org.snapscript.dx.util.AnnotatedOutput;
import org.snapscript.dx.util.Hex;

/**
 * Per-class directory of annotations.
 */
public final class AnnotationsDirectoryItem extends OffsettedItem {
    /** the required alignment for instances of this class */
    private static final int ALIGNMENT = 4;

    /** write size of this class's header, in bytes */
    private static final int HEADER_SIZE = 16;

    /** write size of a list element, in bytes */
    private static final int ELEMENT_SIZE = 8;

    /** {@code null-ok;} the class-level annotations, if any */
    private AnnotationSetItem classAnnotations;

    /** {@code null-ok;} the annotated fields, if any */
    private ArrayList fieldAnnotations;

    /** {@code null-ok;} the annotated methods, if any */
    private ArrayList methodAnnotations;

    /** {@code null-ok;} the annotated parameters, if any */
    private ArrayList parameterAnnotations;

    /**
     * Constructs an empty instance.
     */
    public AnnotationsDirectoryItem() {
        super(ALIGNMENT, -1);

        classAnnotations = null;
        fieldAnnotations = null;
        methodAnnotations = null;
        parameterAnnotations = null;
    }

    /** {@inheritDoc} */
    @Override
    public ItemType itemType() {
        return ItemType.TYPE_ANNOTATIONS_DIRECTORY_ITEM;
    }

    /**
     * Returns whether this item is empty (has no contents).
     *
     * @return {@code true} if this item is empty, or {@code false}
     * if not
     */
    public boolean isEmpty() {
        return (classAnnotations == null) &&
            (fieldAnnotations == null) &&
            (methodAnnotations == null) &&
            (parameterAnnotations == null);
    }

    /**
     * Returns whether this item is a candidate for interning. The only
     * interning candidates are ones that only have a non-null
     * set of class annotations, with no other lists.
     *
     * @return {@code true} if this is an interning candidate, or
     * {@code false} if not
     */
    public boolean isInternable() {
        return (classAnnotations != null) &&
            (fieldAnnotations == null) &&
            (methodAnnotations == null) &&
            (parameterAnnotations == null);
    }

    /** {@inheritDoc} */
    @Override
    public int hashCode() {
        if (classAnnotations == null) {
            return 0;
        }

        return classAnnotations.hashCode();
    }

    /**
     * {@inheritDoc}
     *
     * 

Note:: This throws an exception if this item is not * internable.

* * @see #isInternable */ @Override public int compareTo0(OffsettedItem other) { if (! isInternable()) { throw new UnsupportedOperationException("uninternable instance"); } AnnotationsDirectoryItem otherDirectory = (AnnotationsDirectoryItem) other; return classAnnotations.compareTo(otherDirectory.classAnnotations); } /** * Sets the direct annotations on this instance. These are annotations * made on the class, per se, as opposed to on one of its members. * It is only valid to call this method at most once per instance. * * @param annotations {@code non-null;} annotations to set for this class */ public void setClassAnnotations(Annotations annotations) { if (annotations == null) { throw new NullPointerException("annotations == null"); } if (classAnnotations != null) { throw new UnsupportedOperationException( "class annotations already set"); } classAnnotations = new AnnotationSetItem(annotations); } /** * Adds a field annotations item to this instance. * * @param field {@code non-null;} field in question * @param annotations {@code non-null;} associated annotations to add */ public void addFieldAnnotations(CstFieldRef field, Annotations annotations) { if (fieldAnnotations == null) { fieldAnnotations = new ArrayList(); } fieldAnnotations.add(new FieldAnnotationStruct(field, new AnnotationSetItem(annotations))); } /** * Adds a method annotations item to this instance. * * @param method {@code non-null;} method in question * @param annotations {@code non-null;} associated annotations to add */ public void addMethodAnnotations(CstMethodRef method, Annotations annotations) { if (methodAnnotations == null) { methodAnnotations = new ArrayList(); } methodAnnotations.add(new MethodAnnotationStruct(method, new AnnotationSetItem(annotations))); } /** * Adds a parameter annotations item to this instance. * * @param method {@code non-null;} method in question * @param list {@code non-null;} associated list of annotation sets to add */ public void addParameterAnnotations(CstMethodRef method, AnnotationsList list) { if (parameterAnnotations == null) { parameterAnnotations = new ArrayList(); } parameterAnnotations.add(new ParameterAnnotationStruct(method, list)); } /** * Gets the method annotations for a given method, if any. This is * meant for use by debugging / dumping code. * * @param method {@code non-null;} the method * @return {@code null-ok;} the method annotations, if any */ public Annotations getMethodAnnotations(CstMethodRef method) { if (methodAnnotations == null) { return null; } for (MethodAnnotationStruct item : methodAnnotations) { if (item.getMethod().equals(method)) { return item.getAnnotations(); } } return null; } /** * Gets the parameter annotations for a given method, if any. This is * meant for use by debugging / dumping code. * * @param method {@code non-null;} the method * @return {@code null-ok;} the parameter annotations, if any */ public AnnotationsList getParameterAnnotations(CstMethodRef method) { if (parameterAnnotations == null) { return null; } for (ParameterAnnotationStruct item : parameterAnnotations) { if (item.getMethod().equals(method)) { return item.getAnnotationsList(); } } return null; } /** {@inheritDoc} */ public void addContents(DexFile file) { MixedItemSection wordData = file.getWordData(); if (classAnnotations != null) { classAnnotations = wordData.intern(classAnnotations); } if (fieldAnnotations != null) { for (FieldAnnotationStruct item : fieldAnnotations) { item.addContents(file); } } if (methodAnnotations != null) { for (MethodAnnotationStruct item : methodAnnotations) { item.addContents(file); } } if (parameterAnnotations != null) { for (ParameterAnnotationStruct item : parameterAnnotations) { item.addContents(file); } } } /** {@inheritDoc} */ @Override public String toHuman() { throw new RuntimeException("unsupported"); } /** {@inheritDoc} */ @Override protected void place0(Section addedTo, int offset) { // We just need to set the write size here. int elementCount = listSize(fieldAnnotations) + listSize(methodAnnotations) + listSize(parameterAnnotations); setWriteSize(HEADER_SIZE + (elementCount * ELEMENT_SIZE)); } /** {@inheritDoc} */ @Override protected void writeTo0(DexFile file, AnnotatedOutput out) { boolean annotates = out.annotates(); int classOff = OffsettedItem.getAbsoluteOffsetOr0(classAnnotations); int fieldsSize = listSize(fieldAnnotations); int methodsSize = listSize(methodAnnotations); int parametersSize = listSize(parameterAnnotations); if (annotates) { out.annotate(0, offsetString() + " annotations directory"); out.annotate(4, " class_annotations_off: " + Hex.u4(classOff)); out.annotate(4, " fields_size: " + Hex.u4(fieldsSize)); out.annotate(4, " methods_size: " + Hex.u4(methodsSize)); out.annotate(4, " parameters_size: " + Hex.u4(parametersSize)); } out.writeInt(classOff); out.writeInt(fieldsSize); out.writeInt(methodsSize); out.writeInt(parametersSize); if (fieldsSize != 0) { Collections.sort(fieldAnnotations); if (annotates) { out.annotate(0, " fields:"); } for (FieldAnnotationStruct item : fieldAnnotations) { item.writeTo(file, out); } } if (methodsSize != 0) { Collections.sort(methodAnnotations); if (annotates) { out.annotate(0, " methods:"); } for (MethodAnnotationStruct item : methodAnnotations) { item.writeTo(file, out); } } if (parametersSize != 0) { Collections.sort(parameterAnnotations); if (annotates) { out.annotate(0, " parameters:"); } for (ParameterAnnotationStruct item : parameterAnnotations) { item.writeTo(file, out); } } } /** * Gets the list size of the given list, or {@code 0} if given * {@code null}. * * @param list {@code null-ok;} the list in question * @return {@code >= 0;} its size */ private static int listSize(ArrayList list) { if (list == null) { return 0; } return list.size(); } /** * Prints out the contents of this instance, in a debugging-friendly * way. This is meant to be called from {@link ClassDefItem#debugPrint}. * * @param out {@code non-null;} where to output to */ /*package*/ void debugPrint(PrintWriter out) { if (classAnnotations != null) { out.println(" class annotations: " + classAnnotations); } if (fieldAnnotations != null) { out.println(" field annotations:"); for (FieldAnnotationStruct item : fieldAnnotations) { out.println(" " + item.toHuman()); } } if (methodAnnotations != null) { out.println(" method annotations:"); for (MethodAnnotationStruct item : methodAnnotations) { out.println(" " + item.toHuman()); } } if (parameterAnnotations != null) { out.println(" parameter annotations:"); for (ParameterAnnotationStruct item : parameterAnnotations) { out.println(" " + item.toHuman()); } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy