alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (TypeAnnotation.java)

This example Java source code file (TypeAnnotation.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

assertionerror, instanceof, invalid, list, method_reference_type_argument, method_type_parameter_bound, new, override, position, targettype, typeannotation, typepathentry, typepathentrykind, unknown, util

The TypeAnnotation.java Java example source code

/*
 * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package com.sun.tools.classfile;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import com.sun.tools.classfile.TypeAnnotation.Position.TypePathEntry;

/**
 * See JSR 308 specification, Section 3.
 *
 *  <p>This is NOT part of any supported API.
 *  If you write code that depends on this, you do so at your own risk.
 *  This code and its internal interfaces are subject to change or
 *  deletion without notice.</b>
 */
public class TypeAnnotation {
    TypeAnnotation(ClassReader cr) throws IOException, Annotation.InvalidAnnotation {
        constant_pool = cr.getConstantPool();
        position = read_position(cr);
        annotation = new Annotation(cr);
    }

    public TypeAnnotation(ConstantPool constant_pool,
            Annotation annotation, Position position) {
        this.constant_pool = constant_pool;
        this.position = position;
        this.annotation = annotation;
    }

    public int length() {
        int n = annotation.length();
        n += position_length(position);
        return n;
    }

    @Override
    public String toString() {
        try {
            return "@" + constant_pool.getUTF8Value(annotation.type_index).toString().substring(1) +
                    " pos: " + position.toString();
        } catch (Exception e) {
            e.printStackTrace();
            return e.toString();
        }
    }

    public final ConstantPool constant_pool;
    public final Position position;
    public final Annotation annotation;

    private static Position read_position(ClassReader cr) throws IOException, Annotation.InvalidAnnotation {
        // Copied from ClassReader
        int tag = cr.readUnsignedByte(); // TargetType tag is a byte
        if (!TargetType.isValidTargetTypeValue(tag))
            throw new Annotation.InvalidAnnotation("TypeAnnotation: Invalid type annotation target type value: " + String.format("0x%02X", tag));

        TargetType type = TargetType.fromTargetTypeValue(tag);

        Position position = new Position();
        position.type = type;

        switch (type) {
        // instanceof
        case INSTANCEOF:
        // new expression
        case NEW:
        // constructor/method reference receiver
        case CONSTRUCTOR_REFERENCE:
        case METHOD_REFERENCE:
            position.offset = cr.readUnsignedShort();
            break;
        // local variable
        case LOCAL_VARIABLE:
        // resource variable
        case RESOURCE_VARIABLE:
            int table_length = cr.readUnsignedShort();
            position.lvarOffset = new int[table_length];
            position.lvarLength = new int[table_length];
            position.lvarIndex = new int[table_length];
            for (int i = 0; i < table_length; ++i) {
                position.lvarOffset[i] = cr.readUnsignedShort();
                position.lvarLength[i] = cr.readUnsignedShort();
                position.lvarIndex[i] = cr.readUnsignedShort();
            }
            break;
        // exception parameter
        case EXCEPTION_PARAMETER:
            position.exception_index = cr.readUnsignedShort();
            break;
        // method receiver
        case METHOD_RECEIVER:
            // Do nothing
            break;
        // type parameter
        case CLASS_TYPE_PARAMETER:
        case METHOD_TYPE_PARAMETER:
            position.parameter_index = cr.readUnsignedByte();
            break;
        // type parameter bound
        case CLASS_TYPE_PARAMETER_BOUND:
        case METHOD_TYPE_PARAMETER_BOUND:
            position.parameter_index = cr.readUnsignedByte();
            position.bound_index = cr.readUnsignedByte();
            break;
        // class extends or implements clause
        case CLASS_EXTENDS:
            int in = cr.readUnsignedShort();
            if (in == 0xFFFF)
                in = -1;
            position.type_index = in;
            break;
        // throws
        case THROWS:
            position.type_index = cr.readUnsignedShort();
            break;
        // method parameter
        case METHOD_FORMAL_PARAMETER:
            position.parameter_index = cr.readUnsignedByte();
            break;
        // type cast
        case CAST:
        // method/constructor/reference type argument
        case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
        case METHOD_INVOCATION_TYPE_ARGUMENT:
        case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
        case METHOD_REFERENCE_TYPE_ARGUMENT:
            position.offset = cr.readUnsignedShort();
            position.type_index = cr.readUnsignedByte();
            break;
        // We don't need to worry about these
        case METHOD_RETURN:
        case FIELD:
            break;
        case UNKNOWN:
            throw new AssertionError("TypeAnnotation: UNKNOWN target type should never occur!");
        default:
            throw new AssertionError("TypeAnnotation: Unknown target type: " + type);
        }

        { // Write type path
            int len = cr.readUnsignedByte();
            List<Integer> loc = new ArrayList(len);
            for (int i = 0; i < len * TypePathEntry.bytesPerEntry; ++i)
                loc.add(cr.readUnsignedByte());
            position.location = Position.getTypePathFromBinary(loc);
        }
        return position;
    }

    private static int position_length(Position pos) {
        int n = 0;
        n += 1; // TargetType tag is a byte
        switch (pos.type) {
        // instanceof
        case INSTANCEOF:
        // new expression
        case NEW:
        // constructor/method reference receiver
        case CONSTRUCTOR_REFERENCE:
        case METHOD_REFERENCE:
            n += 2; // offset
            break;
        // local variable
        case LOCAL_VARIABLE:
        // resource variable
        case RESOURCE_VARIABLE:
            n += 2; // table_length;
            int table_length = pos.lvarOffset.length;
            n += 2 * table_length; // offset
            n += 2 * table_length; // length
            n += 2 * table_length; // index
            break;
        // exception parameter
        case EXCEPTION_PARAMETER:
            n += 2; // exception_index
            break;
        // method receiver
        case METHOD_RECEIVER:
            // Do nothing
            break;
        // type parameter
        case CLASS_TYPE_PARAMETER:
        case METHOD_TYPE_PARAMETER:
            n += 1; // parameter_index
            break;
        // type parameter bound
        case CLASS_TYPE_PARAMETER_BOUND:
        case METHOD_TYPE_PARAMETER_BOUND:
            n += 1; // parameter_index
            n += 1; // bound_index
            break;
        // class extends or implements clause
        case CLASS_EXTENDS:
            n += 2; // type_index
            break;
        // throws
        case THROWS:
            n += 2; // type_index
            break;
        // method parameter
        case METHOD_FORMAL_PARAMETER:
            n += 1; // parameter_index
            break;
        // type cast
        case CAST:
        // method/constructor/reference type argument
        case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
        case METHOD_INVOCATION_TYPE_ARGUMENT:
        case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
        case METHOD_REFERENCE_TYPE_ARGUMENT:
            n += 2; // offset
            n += 1; // type index
            break;
        // We don't need to worry about these
        case METHOD_RETURN:
        case FIELD:
            break;
        case UNKNOWN:
            throw new AssertionError("TypeAnnotation: UNKNOWN target type should never occur!");
        default:
            throw new AssertionError("TypeAnnotation: Unknown target type: " + pos.type);
        }

        {
            n += 1; // length
            n += TypePathEntry.bytesPerEntry * pos.location.size(); // bytes for actual array
        }

        return n;
    }

    // Code duplicated from com.sun.tools.javac.code.TypeAnnotationPosition
    public static class Position {
        public enum TypePathEntryKind {
            ARRAY(0),
            INNER_TYPE(1),
            WILDCARD(2),
            TYPE_ARGUMENT(3);

            public final int tag;

            private TypePathEntryKind(int tag) {
                this.tag = tag;
            }
        }

        public static class TypePathEntry {
            /** The fixed number of bytes per TypePathEntry. */
            public static final int bytesPerEntry = 2;

            public final TypePathEntryKind tag;
            public final int arg;

            public static final TypePathEntry ARRAY = new TypePathEntry(TypePathEntryKind.ARRAY);
            public static final TypePathEntry INNER_TYPE = new TypePathEntry(TypePathEntryKind.INNER_TYPE);
            public static final TypePathEntry WILDCARD = new TypePathEntry(TypePathEntryKind.WILDCARD);

            private TypePathEntry(TypePathEntryKind tag) {
                if (!(tag == TypePathEntryKind.ARRAY ||
                        tag == TypePathEntryKind.INNER_TYPE ||
                        tag == TypePathEntryKind.WILDCARD)) {
                    throw new AssertionError("Invalid TypePathEntryKind: " + tag);
                }
                this.tag = tag;
                this.arg = 0;
            }

            public TypePathEntry(TypePathEntryKind tag, int arg) {
                if (tag != TypePathEntryKind.TYPE_ARGUMENT) {
                    throw new AssertionError("Invalid TypePathEntryKind: " + tag);
                }
                this.tag = tag;
                this.arg = arg;
            }

            public static TypePathEntry fromBinary(int tag, int arg) {
                if (arg != 0 && tag != TypePathEntryKind.TYPE_ARGUMENT.tag) {
                    throw new AssertionError("Invalid TypePathEntry tag/arg: " + tag + "/" + arg);
                }
                switch (tag) {
                case 0:
                    return ARRAY;
                case 1:
                    return INNER_TYPE;
                case 2:
                    return WILDCARD;
                case 3:
                    return new TypePathEntry(TypePathEntryKind.TYPE_ARGUMENT, arg);
                default:
                    throw new AssertionError("Invalid TypePathEntryKind tag: " + tag);
                }
            }

            @Override
            public String toString() {
                return tag.toString() +
                        (tag == TypePathEntryKind.TYPE_ARGUMENT ? ("(" + arg + ")") : "");
            }

            @Override
            public boolean equals(Object other) {
                if (! (other instanceof TypePathEntry)) {
                    return false;
                }
                TypePathEntry tpe = (TypePathEntry) other;
                return this.tag == tpe.tag && this.arg == tpe.arg;
            }

            @Override
            public int hashCode() {
                return this.tag.hashCode() * 17 + this.arg;
            }
        }

        public TargetType type = TargetType.UNKNOWN;

        // For generic/array types.
        // TODO: or should we use null? Noone will use this object.
        public List<TypePathEntry> location = new ArrayList(0);

        // Tree position.
        public int pos = -1;

        // For typecasts, type tests, new (and locals, as start_pc).
        public boolean isValidOffset = false;
        public int offset = -1;

        // For locals. arrays same length
        public int[] lvarOffset = null;
        public int[] lvarLength = null;
        public int[] lvarIndex = null;

        // For type parameter bound
        public int bound_index = Integer.MIN_VALUE;

        // For type parameter and method parameter
        public int parameter_index = Integer.MIN_VALUE;

        // For class extends, implements, and throws clauses
        public int type_index = Integer.MIN_VALUE;

        // For exception parameters, index into exception table
        public int exception_index = Integer.MIN_VALUE;

        public Position() {}

        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder();
            sb.append('[');
            sb.append(type);

            switch (type) {
            // instanceof
            case INSTANCEOF:
            // new expression
            case NEW:
            // constructor/method reference receiver
            case CONSTRUCTOR_REFERENCE:
            case METHOD_REFERENCE:
                sb.append(", offset = ");
                sb.append(offset);
                break;
            // local variable
            case LOCAL_VARIABLE:
            // resource variable
            case RESOURCE_VARIABLE:
                if (lvarOffset == null) {
                    sb.append(", lvarOffset is null!");
                    break;
                }
                sb.append(", {");
                for (int i = 0; i < lvarOffset.length; ++i) {
                    if (i != 0) sb.append("; ");
                    sb.append("start_pc = ");
                    sb.append(lvarOffset[i]);
                    sb.append(", length = ");
                    sb.append(lvarLength[i]);
                    sb.append(", index = ");
                    sb.append(lvarIndex[i]);
                }
                sb.append("}");
                break;
            // method receiver
            case METHOD_RECEIVER:
                // Do nothing
                break;
            // type parameter
            case CLASS_TYPE_PARAMETER:
            case METHOD_TYPE_PARAMETER:
                sb.append(", param_index = ");
                sb.append(parameter_index);
                break;
            // type parameter bound
            case CLASS_TYPE_PARAMETER_BOUND:
            case METHOD_TYPE_PARAMETER_BOUND:
                sb.append(", param_index = ");
                sb.append(parameter_index);
                sb.append(", bound_index = ");
                sb.append(bound_index);
                break;
            // class extends or implements clause
            case CLASS_EXTENDS:
                sb.append(", type_index = ");
                sb.append(type_index);
                break;
            // throws
            case THROWS:
                sb.append(", type_index = ");
                sb.append(type_index);
                break;
            // exception parameter
            case EXCEPTION_PARAMETER:
                sb.append(", exception_index = ");
                sb.append(exception_index);
                break;
            // method parameter
            case METHOD_FORMAL_PARAMETER:
                sb.append(", param_index = ");
                sb.append(parameter_index);
                break;
            // type cast
            case CAST:
            // method/constructor/reference type argument
            case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
            case METHOD_INVOCATION_TYPE_ARGUMENT:
            case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
            case METHOD_REFERENCE_TYPE_ARGUMENT:
                sb.append(", offset = ");
                sb.append(offset);
                sb.append(", type_index = ");
                sb.append(type_index);
                break;
            // We don't need to worry about these
            case METHOD_RETURN:
            case FIELD:
                break;
            case UNKNOWN:
                sb.append(", position UNKNOWN!");
                break;
            default:
                throw new AssertionError("Unknown target type: " + type);
            }

            // Append location data for generics/arrays.
            if (!location.isEmpty()) {
                sb.append(", location = (");
                sb.append(location);
                sb.append(")");
            }

            sb.append(", pos = ");
            sb.append(pos);

            sb.append(']');
            return sb.toString();
        }

        /**
         * Indicates whether the target tree of the annotation has been optimized
         * away from classfile or not.
         * @return true if the target has not been optimized away
         */
        public boolean emitToClassfile() {
            return !type.isLocal() || isValidOffset;
        }

        /**
         * Decode the binary representation for a type path and set
         * the {@code location} field.
         *
         * @param list The bytecode representation of the type path.
         */
        public static List<TypePathEntry> getTypePathFromBinary(List list) {
            List<TypePathEntry> loc = new ArrayList(list.size() / TypePathEntry.bytesPerEntry);
            int idx = 0;
            while (idx < list.size()) {
                if (idx + 1 == list.size()) {
                    throw new AssertionError("Could not decode type path: " + list);
                }
                loc.add(TypePathEntry.fromBinary(list.get(idx), list.get(idx + 1)));
                idx += 2;
            }
            return loc;
        }

        public static List<Integer> getBinaryFromTypePath(List locs) {
            List<Integer> loc = new ArrayList(locs.size() * TypePathEntry.bytesPerEntry);
            for (TypePathEntry tpe : locs) {
                loc.add(tpe.tag.tag);
                loc.add(tpe.arg);
            }
            return loc;
        }
    }

    // Code duplicated from com.sun.tools.javac.code.TargetType
    // The IsLocal flag could be removed here.
    public enum TargetType {
        /** For annotations on a class type parameter declaration. */
        CLASS_TYPE_PARAMETER(0x00),

        /** For annotations on a method type parameter declaration. */
        METHOD_TYPE_PARAMETER(0x01),

        /** For annotations on the type of an "extends" or "implements" clause. */
        CLASS_EXTENDS(0x10),

        /** For annotations on a bound of a type parameter of a class. */
        CLASS_TYPE_PARAMETER_BOUND(0x11),

        /** For annotations on a bound of a type parameter of a method. */
        METHOD_TYPE_PARAMETER_BOUND(0x12),

        /** For annotations on a field. */
        FIELD(0x13),

        /** For annotations on a method return type. */
        METHOD_RETURN(0x14),

        /** For annotations on the method receiver. */
        METHOD_RECEIVER(0x15),

        /** For annotations on a method parameter. */
        METHOD_FORMAL_PARAMETER(0x16),

        /** For annotations on a throws clause in a method declaration. */
        THROWS(0x17),

        /** For annotations on a local variable. */
        LOCAL_VARIABLE(0x40, true),

        /** For annotations on a resource variable. */
        RESOURCE_VARIABLE(0x41, true),

        /** For annotations on an exception parameter. */
        EXCEPTION_PARAMETER(0x42, true),

        /** For annotations on a type test. */
        INSTANCEOF(0x43, true),

        /** For annotations on an object creation expression. */
        NEW(0x44, true),

        /** For annotations on a constructor reference receiver. */
        CONSTRUCTOR_REFERENCE(0x45, true),

        /** For annotations on a method reference receiver. */
        METHOD_REFERENCE(0x46, true),

        /** For annotations on a typecast. */
        CAST(0x47, true),

        /** For annotations on a type argument of an object creation expression. */
        CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT(0x48, true),

        /** For annotations on a type argument of a method call. */
        METHOD_INVOCATION_TYPE_ARGUMENT(0x49, true),

        /** For annotations on a type argument of a constructor reference. */
        CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT(0x4A, true),

        /** For annotations on a type argument of a method reference. */
        METHOD_REFERENCE_TYPE_ARGUMENT(0x4B, true),

        /** For annotations with an unknown target. */
        UNKNOWN(0xFF);

        private static final int MAXIMUM_TARGET_TYPE_VALUE = 0x4B;

        private final int targetTypeValue;
        private final boolean isLocal;

        private TargetType(int targetTypeValue) {
            this(targetTypeValue, false);
        }

        private TargetType(int targetTypeValue, boolean isLocal) {
            if (targetTypeValue < 0
                    || targetTypeValue > 255)
                    throw new AssertionError("Attribute type value needs to be an unsigned byte: " + String.format("0x%02X", targetTypeValue));
            this.targetTypeValue = targetTypeValue;
            this.isLocal = isLocal;
        }

        /**
         * Returns whether or not this TargetType represents an annotation whose
         * target is exclusively a tree in a method body
         *
         * Note: wildcard bound targets could target a local tree and a class
         * member declaration signature tree
         */
        public boolean isLocal() {
            return isLocal;
        }

        public int targetTypeValue() {
            return this.targetTypeValue;
        }

        private static final TargetType[] targets;

        static {
            targets = new TargetType[MAXIMUM_TARGET_TYPE_VALUE + 1];
            TargetType[] alltargets = values();
            for (TargetType target : alltargets) {
                if (target.targetTypeValue != UNKNOWN.targetTypeValue)
                    targets[target.targetTypeValue] = target;
            }
            for (int i = 0; i <= MAXIMUM_TARGET_TYPE_VALUE; ++i) {
                if (targets[i] == null)
                    targets[i] = UNKNOWN;
            }
        }

        public static boolean isValidTargetTypeValue(int tag) {
            if (tag == UNKNOWN.targetTypeValue)
                return true;
            return (tag >= 0 && tag < targets.length);
        }

        public static TargetType fromTargetTypeValue(int tag) {
            if (tag == UNKNOWN.targetTypeValue)
                return UNKNOWN;

            if (tag < 0 || tag >= targets.length)
                throw new AssertionError("Unknown TargetType: " + tag);
            return targets[tag];
        }
    }
}

Other Java examples (source code examples)

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

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

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.