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

mockit.external.asm.AnnotationReader Maven / Gradle / Ivy

Go to download

JMockit is a Java toolkit for automated developer testing. It contains APIs for the creation of the objects to be tested, for mocking dependencies, and for faking external APIs; JUnit (4 & 5) and TestNG test runners are supported. It also contains an advanced code coverage tool.

There is a newer version: 1.49
Show newest version
package mockit.external.asm;

import java.lang.reflect.*;
import javax.annotation.*;

final class AnnotationReader extends BytecodeReader
{
   AnnotationReader(@Nonnull BytecodeReader br) { super(br); }

   /**
    * Reads the values of an annotation and makes the given visitor visit them.
    *
    * @param v     the start offset in {@link #b b} of the values to be read
    *              (including the unsigned short that gives the number of values).
    * @param buf   buffer to be used to call {@link #readUTF8 readUTF8},
    *              {@link #readClass(int, char[]) readClass} or {@link #readConst readConst}.
    * @param named if the annotation values are named or not.
    * @param av    the visitor that must visit the values.
    * @return the end offset of the annotation values.
    */
   @Nonnegative
   int readAnnotationValues(@Nonnegative int v, @Nonnull char[] buf, boolean named, @Nullable AnnotationVisitor av) {
      int i = readUnsignedShort(v);
      v += 2;

      if (named) {
         for (; i > 0; i--) {
            String name = readUTF8(v, buf);
            v = readAnnotationValue(v + 2, buf, name, av);
         }
      }
      else {
         for (; i > 0; i--) {
            v = readAnnotationValue(v, buf, null, av);
         }
      }

      if (av != null) {
         av.visitEnd();
      }

      return v;
   }

   /**
    * Reads a value of an annotation and makes the given visitor visit it.
    *
    * @param v    the start offset in {@link #b} of the value to be read
    *             (not including the value name constant pool index).
    * @param buf  buffer to be used to call {@link #readUTF8 readUTF8},
    *             {@link #readClass(int, char[]) readClass} or {@link #readConst readConst}.
    * @param name the name of the value to be read.
    * @param av   the visitor that must visit the value.
    * @return the end offset of the annotation value.
    */
   @Nonnegative
   int readAnnotationValue(
      @Nonnegative int v, @Nonnull char[] buf, @Nullable String name, @Nullable AnnotationVisitor av
   ) {
      if (av == null) {
         return readAnnotationValue(v, buf);
      }

      int typeCode = b[v++] & 0xFF;
      Object value;

      switch (typeCode) {
         case 'I': // pointer to CONSTANT_Integer
         case 'J': // pointer to CONSTANT_Long
         case 'F': // pointer to CONSTANT_Float
         case 'D': // pointer to CONSTANT_Double
            value = readConst(readUnsignedShort(v), buf);
            av.visit(name, value);
            v += 2;
            break;
         case 'B': // pointer to CONSTANT_Byte
            value = (byte) readInt(items[readUnsignedShort(v)]);
            av.visit(name, value);
            v += 2;
            break;
         case 'Z': // pointer to CONSTANT_Boolean
            value = readInt(items[readUnsignedShort(v)]) == 0 ? Boolean.FALSE : Boolean.TRUE;
            av.visit(name, value);
            v += 2;
            break;
         case 'S': // pointer to CONSTANT_Short
            value = (short) readInt(items[readUnsignedShort(v)]);
            av.visit(name, value);
            v += 2;
            break;
         case 'C': // pointer to CONSTANT_Char
            value = (char) readInt(items[readUnsignedShort(v)]);
            av.visit(name, value);
            v += 2;
            break;
         case 's': // pointer to CONSTANT_Utf8
            value = readUTF8(v, buf);
            //noinspection ConstantConditions
            av.visit(name, value);
            v += 2;
            break;
         case 'e': // enum_const_value
            String enumDesc = readUTF8(v, buf);
            String enumValue = readUTF8(v + 2, buf);
            //noinspection ConstantConditions
            av.visitEnum(name, enumDesc, enumValue);
            v += 4;
            break;
         case 'c': // class_info
            String typeDesc = readUTF8(v, buf);
            //noinspection ConstantConditions
            value = JavaType.getType(typeDesc);
            av.visit(name, value);
            v += 2;
            break;
         case '@': // annotation_value
            String desc = readUTF8(v, buf);
            //noinspection ConstantConditions
            AnnotationVisitor nestedVisitor = av.visitAnnotation(name, desc);
            v = readAnnotationValues(v + 2, buf, true, nestedVisitor);
            break;
         case '[': // array_value
            int size = readUnsignedShort(v);
            v += 2;

            if (size == 0) {
               AnnotationVisitor arrayVisitor = av.visitArray(name);
               return readAnnotationValues(v - 2, buf, false, arrayVisitor);
            }

            v = readAnnotationArrayValue(v, buf, name, av, size);
      }

      return v;
   }

   @Nonnegative
   private int readAnnotationValue(@Nonnegative int v, @Nonnull char[] buf) {
      int typeCode = b[v] & 0xFF;

      switch (typeCode) {
         case 'e': // enum_const_value
            return v + 5;
         case '@': // annotation_value
            return readAnnotationValues(v + 3, buf, true, null);
         case '[': // array_value
            return readAnnotationValues(v + 1, buf, false, null);
         default:
            return v + 3;
      }
   }

   @Nonnegative
   private int readAnnotationArrayValue(
      @Nonnegative int v, @Nonnull char[] buf, @Nullable String name, @Nonnull AnnotationVisitor av,
      @Nonnegative int size
   ) {
      int typeCode = b[v++] & 0xFF;

      if ("BZSCIJFD".indexOf(typeCode) < 0) {
         AnnotationVisitor arrayVisitor = av.visitArray(name);
         return readAnnotationValues(v - 3, buf, false, arrayVisitor);
      }

      Class elementType = PrimitiveType.getType(typeCode);
      Object array = Array.newInstance(elementType, size);

      for (int i = 0; i < size; i++) {
         int index = items[readUnsignedShort(v)];
         Object value;

         switch (typeCode) {
            case 'B':
               value = (byte) readInt(index);
               break;
            case 'Z':
               value = readInt(index) != 0;
               break;
            case 'S':
               value = (short) readInt(index);
               break;
            case 'C':
               value = (char) readInt(index);
               break;
            case 'I':
               value = readInt(index);
               break;
            case 'J':
               value = readLong(index);
               break;
            case 'F':
               int floatBits = readInt(index);
               value = Float.intBitsToFloat(floatBits);
               break;
            default: // 'D'
               long doubleBits = readLong(index);
               value = Double.longBitsToDouble(doubleBits);
         }

         Array.set(array, i, value);
         v += 3;
      }

      av.visit(name, array);
      v--;
      return v;
   }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy