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

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

Go to download

JMockit is a Java toolkit for automated developer testing. It contains mocking/faking APIs and a code coverage tool, supporting both JUnit and TestNG. The mocking APIs allow all kinds of Java code, without testability restrictions, to be tested in isolation from selected dependencies.

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

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

import mockit.asm.types.*;
import mockit.asm.util.*;

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

   /**
    * Reads the values of a named annotation and makes the given visitor visit them.
    *
    * @param startingCodeIndex the start offset in {@link #code} of the values to be read (including the unsigned short that gives the
    *                          number of values)
    * @param av the visitor that must visit the values
    * @return the end offset of the annotation values
    */
   @Nonnegative
   public int readNamedAnnotationValues(@Nonnegative int startingCodeIndex, @Nullable AnnotationVisitor av) {
      codeIndex = startingCodeIndex;
      readAnnotationValues(true, av);
      return codeIndex;
   }

   private void readAnnotationValues(boolean named, @Nullable AnnotationVisitor av) {
      int valueCount = readUnsignedShort();
      readAnnotationValues(valueCount, named, av);
   }

   private void readAnnotationValues(@Nonnegative int valueCount, boolean named, @Nullable AnnotationVisitor av) {
      while (valueCount > 0) {
         String name = named ? readNonnullUTF8() : null;
         readAnnotationValue(name, av);
         valueCount--;
      }

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

   private void readAnnotationValue(@Nullable String name, @Nullable AnnotationVisitor av) {
      int typeCode = readUnsignedByte();

      if (av == null) {
         readAnnotationValue(typeCode);
      }
      else {
         Object value = readAnnotationValueIfPrimitiveOrString(typeCode);

         if (value != null) {
            av.visit(name, value);
         }
         else {
            //noinspection SwitchStatementWithoutDefaultBranch
            switch (typeCode) {
               case 'e': readEnumConstValue(name, av);   break; // enum_const_value
               case 'c': readClassInfo(name, av);        break; // class_info
               case '@': readNestedAnnotation(name, av); break; // annotation_value
               case '[': readArrayValue(name, av);              // array_value
            }
         }
      }
   }

   private void readAnnotationValue(@Nonnegative int typeCode) {
      switch (typeCode) {
         case 'e': codeIndex += 4; break; // enum_const_value
         case '@': codeIndex += 2; readAnnotationValues(true, null); break; // annotation_value
         case '[': readAnnotationValues(false, null); break;
         default:  codeIndex += 2;
      }
   }

   @Nullable @SuppressWarnings({"NumericCastThatLosesPrecision", "SwitchStatementWithoutDefaultBranch"})
   private Object readAnnotationValueIfPrimitiveOrString(@Nonnegative int typeCode) {
      switch (typeCode) {
         case 'I': case 'J': case 'F': case 'D': return readConstItem(); // CONSTANT_Integer/Long/Float/Double
         case 'B': return (byte) readValueOfOneOrTwoBytes();             // CONSTANT_Byte
         case 'Z': return readValueOfOneOrTwoBytes() != 0;               // CONSTANT_Boolean
         case 'S': return (short) readValueOfOneOrTwoBytes();            // CONSTANT_Short
         case 'C': return (char)  readValueOfOneOrTwoBytes();            // CONSTANT_Char
         case 's': return readNonnullUTF8();                             // CONSTANT_Utf8
      }

      return null;
   }

   private int readValueOfOneOrTwoBytes() {
      int itemIndex = readUnsignedShort();
      int valueCodeIndex = items[itemIndex];
      return readInt(valueCodeIndex);
   }

   private void readEnumConstValue(@Nullable String name, @Nonnull AnnotationVisitor av) {
      String enumDesc = readNonnullUTF8();
      String enumValue = readNonnullUTF8();
      av.visitEnum(name, enumDesc, enumValue);
   }

   private void readClassInfo(@Nullable String name, @Nonnull AnnotationVisitor av) {
      String typeDesc = readNonnullUTF8();
      JavaType value = JavaType.getType(typeDesc);
      av.visit(name, value);
   }

   private void readNestedAnnotation(@Nullable String name, @Nonnull AnnotationVisitor av) {
      String desc = readNonnullUTF8();
      AnnotationVisitor nestedVisitor = av.visitAnnotation(name, desc);
      readAnnotationValues(true, nestedVisitor);
   }

   private void readArrayValue(@Nullable String name, @Nonnull AnnotationVisitor av) {
      int valueCount = readUnsignedShort();

      if (valueCount == 0) {
         AnnotationVisitor arrayVisitor = av.visitArray(name);
         arrayVisitor.visitEnd();
         return;
      }

      int typeCode = readUnsignedByte();
      PrimitiveType primitiveElementType = PrimitiveType.getPrimitiveType(typeCode);

      if (primitiveElementType == null) {
         AnnotationVisitor arrayVisitor = av.visitArray(name);
         codeIndex--;
         readAnnotationValues(valueCount, false, arrayVisitor);
         return;
      }

      Class elementType = primitiveElementType.getType();
      Object array = Array.newInstance(elementType, valueCount);
      fillArrayElements(valueCount, typeCode, array);
      av.visit(name, array);
      codeIndex--;
   }

   private void fillArrayElements(@Nonnegative int length, @Nonnegative int typeCode, @Nonnull Object array) {
      for (int i = 0; i < length; i++) {
         int itemIndex = readUnsignedShort();
         int index = items[itemIndex];
         Object value = getArrayElementValue(typeCode, index);
         Array.set(array, i, value);
         codeIndex++;
      }
   }

   @Nonnull
   private Object getArrayElementValue(@Nonnegative int typeCode, @Nonnegative int valueCodeIndex) {
      switch (typeCode) {
         case 'Z': return readBoolean(valueCodeIndex);
         case 'C': return readChar(valueCodeIndex);
         case 'B': return readUnsignedByte(valueCodeIndex);
         case 'S': return readShort(valueCodeIndex);
         case 'F': return readFloat(valueCodeIndex);
         case 'D': return readDouble(valueCodeIndex);
         case 'J': return readLong(valueCodeIndex);
         default:  return readInt(valueCodeIndex);
      }
   }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy