예제 #1
0
 @Override
 public Object asConstantPoolValue() {
   StringBuilder stringBuilder = new StringBuilder("(");
   for (TypeDescription parameterType : getParameterTypes()) {
     stringBuilder.append(parameterType.getDescriptor());
   }
   return Type.getMethodType(
       stringBuilder.append(")").append(getReturnType().getDescriptor()).toString());
 }
 @Override
 void write(MethodWriter writer, Globals globals) {
   writer.writeDebugInfo(location);
   if (defPointer != null) {
     // dynamic interface: push captured parameter on stack
     // TODO: don't do this: its just to cutover :)
     writer.push((String) null);
     writer.visitVarInsn(captured.type.type.getOpcode(Opcodes.ILOAD), captured.getSlot());
   } else if (ref == null) {
     // typed interface, dynamic implementation
     writer.visitVarInsn(captured.type.type.getOpcode(Opcodes.ILOAD), captured.getSlot());
     Type methodType = Type.getMethodType(expected.type, captured.type.type);
     writer.invokeDefCall(call, methodType, DefBootstrap.REFERENCE, expected.name);
   } else {
     // typed interface, typed implementation
     writer.visitVarInsn(captured.type.type.getOpcode(Opcodes.ILOAD), captured.getSlot());
     // convert MethodTypes to asm Type for the constant pool.
     String invokedType = ref.invokedType.toMethodDescriptorString();
     Type samMethodType = Type.getMethodType(ref.samMethodType.toMethodDescriptorString());
     Type interfaceType = Type.getMethodType(ref.interfaceMethodType.toMethodDescriptorString());
     if (ref.needsBridges()) {
       writer.invokeDynamic(
           ref.invokedName,
           invokedType,
           LAMBDA_BOOTSTRAP_HANDLE,
           samMethodType,
           ref.implMethodASM,
           samMethodType,
           LambdaMetafactory.FLAG_BRIDGES,
           1,
           interfaceType);
     } else {
       writer.invokeDynamic(
           ref.invokedName,
           invokedType,
           LAMBDA_BOOTSTRAP_HANDLE,
           samMethodType,
           ref.implMethodASM,
           samMethodType,
           0);
     }
   }
 }
예제 #3
0
 /**
  * Transforms the given method type into a stack manipulation that loads its type onto the operand
  * stack.
  *
  * @param methodType The method type that should be loaded onto the operand stack.
  * @return A stack manipulation that loads the given method type.
  */
 public static StackManipulation of(JavaInstance.MethodType methodType) {
   Type[] parameterType = new Type[methodType.getParameterTypes().size()];
   int index = 0;
   for (TypeDescription typeDescription : methodType.getParameterTypes()) {
     parameterType[index++] = Type.getType(typeDescription.getDescriptor());
   }
   return new MethodTypeConstant(
       Type.getMethodType(
           Type.getType(methodType.getReturnType().getDescriptor()), parameterType));
 }
  private GaMethod toMethod(
      ClassLoader loader, Class<?> clazz, String methodName, String methodDesc)
      throws ClassNotFoundException, NoSuchMethodException {
    final org.objectweb.asm.Type asmType = org.objectweb.asm.Type.getMethodType(methodDesc);

    // to arg types
    final Class<?>[] argsClasses = new Class<?>[asmType.getArgumentTypes().length];
    for (int index = 0; index < argsClasses.length; index++) {

      // asm class descriptor to jvm class
      final Class<?> argumentClass;
      final Type argumentAsmType = asmType.getArgumentTypes()[index];
      switch (argumentAsmType.getSort()) {
        case Type.BOOLEAN:
          {
            argumentClass = boolean.class;
            break;
          }
        case Type.CHAR:
          {
            argumentClass = char.class;
            break;
          }
        case Type.BYTE:
          {
            argumentClass = byte.class;
            break;
          }
        case Type.SHORT:
          {
            argumentClass = short.class;
            break;
          }
        case Type.INT:
          {
            argumentClass = int.class;
            break;
          }
        case Type.FLOAT:
          {
            argumentClass = float.class;
            break;
          }
        case Type.LONG:
          {
            argumentClass = long.class;
            break;
          }
        case Type.DOUBLE:
          {
            argumentClass = double.class;
            break;
          }
        case Type.ARRAY:
          {
            argumentClass = toClass(loader, argumentAsmType.getInternalName());
            break;
          }
        case Type.VOID:
          {
            argumentClass = void.class;
            break;
          }
        case Type.OBJECT:
        case Type.METHOD:
        default:
          {
            argumentClass = toClass(loader, argumentAsmType.getClassName());
            break;
          }
      }

      argsClasses[index] = argumentClass;
    }

    // to method or constructor
    if (GaCheckUtils.isEquals(methodName, "<init>")) {
      return GaMethod.newInit(toConstructor(clazz, argsClasses));
    } else {
      return GaMethod.newMethod(toMethod(clazz, methodName, argsClasses));
    }
  }
예제 #5
0
/**
 * Finds any class with a {@code public static main} method by performing a breadth first search.
 *
 * @author Phillip Webb
 */
public abstract class MainClassFinder {

  private static final String DOT_CLASS = ".class";

  private static final Type STRING_ARRAY_TYPE = Type.getType(String[].class);

  private static final Type MAIN_METHOD_TYPE =
      Type.getMethodType(Type.VOID_TYPE, STRING_ARRAY_TYPE);

  private static final String MAIN_METHOD_NAME = "main";

  private static final FileFilter CLASS_FILE_FILTER =
      new FileFilter() {
        @Override
        public boolean accept(File file) {
          return (file.isFile() && file.getName().endsWith(DOT_CLASS));
        }
      };

  private static final FileFilter PACKAGE_FOLDER_FILTER =
      new FileFilter() {
        @Override
        public boolean accept(File file) {
          return file.isDirectory() && !file.getName().startsWith(".");
        }
      };

  /**
   * Find the main class from a given folder.
   *
   * @param rootFolder the root folder to search
   * @return the main class or {@code null}
   * @throws IOException
   */
  public static String findMainClass(File rootFolder) throws IOException {
    if (!rootFolder.isDirectory()) {
      throw new IllegalArgumentException("Inavlid root folder '" + rootFolder + "'");
    }
    File mainClassFile = findMainClassFile(rootFolder);
    if (mainClassFile == null) {
      return null;
    }
    String mainClass = mainClassFile.getAbsolutePath();
    return convertToClassName(mainClass, rootFolder.getAbsolutePath() + "/");
  }

  private static File findMainClassFile(File root) throws IOException {
    Deque<File> stack = new ArrayDeque<File>();
    stack.push(root);
    while (!stack.isEmpty()) {
      File file = stack.pop();
      if (file.isFile()) {
        InputStream inputStream = new FileInputStream(file);
        try {
          if (isMainClass(inputStream)) {
            return file;
          }
        } finally {
          inputStream.close();
        }
      }
      if (file.isDirectory()) {
        pushAllSorted(stack, file.listFiles(PACKAGE_FOLDER_FILTER));
        pushAllSorted(stack, file.listFiles(CLASS_FILE_FILTER));
      }
    }
    return null;
  }

  private static void pushAllSorted(Deque<File> stack, File[] files) {
    Arrays.sort(
        files,
        new Comparator<File>() {
          @Override
          public int compare(File o1, File o2) {
            return o1.getName().compareTo(o2.getName());
          }
        });
    for (File file : files) {
      stack.push(file);
    }
  }

  /**
   * Find the main class in a given jar file.
   *
   * @param jarFile the jar file to search
   * @param classesLocation the location within the jar containing classes
   * @return the main class or {@code null}
   * @throws IOException
   */
  public static String findMainClass(JarFile jarFile, String classesLocation) throws IOException {
    List<JarEntry> classEntries = getClassEntries(jarFile, classesLocation);
    Collections.sort(classEntries, new ClassEntryComparator());
    for (JarEntry entry : classEntries) {
      InputStream inputStream = new BufferedInputStream(jarFile.getInputStream(entry));
      try {
        if (isMainClass(inputStream)) {
          String name = entry.getName();
          name = convertToClassName(name, classesLocation);
          return name;
        }
      } finally {
        inputStream.close();
      }
    }
    return null;
  }

  private static String convertToClassName(String name, String prefix) {
    name = name.replace("/", ".");
    name = name.replace('\\', '.');
    name = name.substring(0, name.length() - DOT_CLASS.length());
    if (prefix != null) {
      name = name.substring(prefix.length());
    }
    return name;
  }

  private static List<JarEntry> getClassEntries(JarFile source, String classesLocation) {
    classesLocation = (classesLocation != null ? classesLocation : "");
    Enumeration<JarEntry> sourceEntries = source.entries();
    List<JarEntry> classEntries = new ArrayList<JarEntry>();
    while (sourceEntries.hasMoreElements()) {
      JarEntry entry = sourceEntries.nextElement();
      if (entry.getName().startsWith(classesLocation) && entry.getName().endsWith(DOT_CLASS)) {
        classEntries.add(entry);
      }
    }
    return classEntries;
  }

  private static boolean isMainClass(InputStream inputStream) {
    try {
      ClassReader classReader = new ClassReader(inputStream);
      MainMethodFinder mainMethodFinder = new MainMethodFinder();
      classReader.accept(mainMethodFinder, ClassReader.SKIP_CODE);
      return mainMethodFinder.isFound();
    } catch (IOException ex) {
      return false;
    }
  }

  private static class ClassEntryComparator implements Comparator<JarEntry> {

    @Override
    public int compare(JarEntry o1, JarEntry o2) {
      Integer d1 = getDepth(o1);
      Integer d2 = getDepth(o2);
      int depthCompare = d1.compareTo(d2);
      if (depthCompare != 0) {
        return depthCompare;
      }
      return o1.getName().compareTo(o2.getName());
    }

    private int getDepth(JarEntry entry) {
      return entry.getName().split("/").length;
    }
  }

  private static class MainMethodFinder extends ClassVisitor {

    private boolean found;

    public MainMethodFinder() {
      super(Opcodes.ASM4);
    }

    @Override
    public MethodVisitor visitMethod(
        int access, String name, String desc, String signature, String[] exceptions) {
      if (isAccess(access, Opcodes.ACC_PUBLIC, Opcodes.ACC_STATIC)
          && MAIN_METHOD_NAME.equals(name)
          && MAIN_METHOD_TYPE.getDescriptor().equals(desc)) {
        this.found = true;
      }
      return null;
    }

    private boolean isAccess(int access, int... requiredOpsCodes) {
      for (int requiredOpsCode : requiredOpsCodes) {
        if ((access & requiredOpsCode) == 0) {
          return false;
        }
      }
      return true;
    }

    public boolean isFound() {
      return this.found;
    }
  }
}
예제 #6
0
 /**
  * Transforms the given method into a stack manipulation that loads its type onto the operand
  * stack.
  *
  * @param methodDescription The method of which the method type should be loaded onto the operand
  *     stack.
  * @return A stack manipulation that loads the method type of the given method onto the operand
  *     stack.
  */
 public static StackManipulation of(MethodDescription methodDescription) {
   return new MethodTypeConstant(Type.getMethodType(methodDescription.getDescriptor()));
 }