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

io.ebean.enhance.asm.ClassWriterWithoutClassLoading Maven / Gradle / Ivy

There is a newer version: 15.10.0
Show newest version
package io.ebean.enhance.asm;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import io.ebean.enhance.common.CommonSuperUnresolved;

/**
 * ClassWriter without class loading. Fixes problems on dynamic enhancement metioned here:
 * https://github.com/ebean-orm/ebean-agent/issues/59
 *
 * Idea taken from here:
 *
 * https://github.com/zygote1984/AspectualAdapters/blob/master/ALIA4J-NOIRIn-all/src/org/alia4j/noirin/transform/ClassWriterWithoutClassLoading.java
 *
 * @author praml
 */
public class ClassWriterWithoutClassLoading extends ClassWriter {

  private final Map> type2instanceOfs = new HashMap<>();

  private final Map type2superclass = new HashMap<>();

  private final Map type2isInterface = new HashMap<>();

  public ClassWriterWithoutClassLoading(ClassReader classReader, int flags, ClassLoader classLoader) {
    super(classReader, flags, classLoader);
  }

  public ClassWriterWithoutClassLoading(int flags, ClassLoader classLoader) {
    super(flags, classLoader);
  }

  @Override
  protected Class classForName(String type) throws ClassNotFoundException {
    throw new UnsupportedOperationException("This classloader does not support class loading.");
  }

  /**
   * Returns the common super type of the two given types.
   *
   * @param type1 the internal name of a class.
   * @param type2 the internal name of another class.
   * @return the internal name of the common super class of the two given classes.
   */
  @Override
  protected synchronized String getCommonSuperClass(final String type1, final String type2) {
    try {
      if (getInstanceOfs(type2).contains(type1)) {
        return type1;
      }
      if (getInstanceOfs(type1).contains(type2)) {
        return type2;
      }
      if (isInterface(type1) || isInterface(type2)) {
        return "java/lang/Object";
      } else {
        String type = type1;
        do {
          type = getSuperclass(type);
        } while (!getInstanceOfs(type2).contains(type));
        return type;
      }
    } catch (Exception e) {
      unresolved.add(new CommonSuperUnresolved(type1, type2, e.toString()));
      return "java/lang/Object";
    }
  }

  private String getSuperclass(String type) {
    if (!type2superclass.containsKey(type)) {
      initializeTypeHierarchyFor(type);
    }
    return type2superclass.get(type);
  }

  private boolean isInterface(String type) {
    if (!type2isInterface.containsKey(type)) {
      initializeTypeHierarchyFor(type);
    }
    return type2isInterface.get(type);
  }

  private Set getInstanceOfs(String type) {
    if (!type2instanceOfs.containsKey(type)) {
      initializeTypeHierarchyFor(type);
    }
    return type2instanceOfs.get(type);
  }

  /**
   * Here we read the class at bytecode-level.
   */
  private void initializeTypeHierarchyFor(final String internalTypeName) {
    try (InputStream classBytes = classLoader.getResourceAsStream(internalTypeName + ".class")){
      ClassReader classReader = new ClassReader(classBytes);
      classReader.accept(new ClassVisitor(Opcodes.ASM5) {

        @Override
        public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
          super.visit(version, access, name, signature, superName, interfaces);
          type2superclass.put(internalTypeName, superName);
          type2isInterface.put(internalTypeName, (access & Opcodes.ACC_INTERFACE) > 0);

          Set instanceOfs = new HashSet<>();
          instanceOfs.add(internalTypeName); // we are instance of ourself
          if (superName != null) {
            instanceOfs.add(superName);
            instanceOfs.addAll(getInstanceOfs(superName));
          }
          for (String superInterface : interfaces) {
            instanceOfs.add(superInterface);
            instanceOfs.addAll(getInstanceOfs(superInterface));
          }
          type2instanceOfs.put(internalTypeName, instanceOfs);
        }
      }, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
    } catch (IOException e) {
      throw new IllegalArgumentException(e);
    }
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy