Example #1
0
  private void addNewClassLoader() {
    for (ClassDescriptorSourceUnit sourceFile : sourceRegistry.getClassDescriptorSourceFileColl()) {
      sourceFile.resetLastLoadedClass(); // resetea también las innerclasses
    }

    this.customClassLoader = new JProxyClassLoader(this);
  }
Example #2
0
  private void reloadSource(
      @NotNull ClassDescriptorSourceUnit sourceFile, boolean detectInnerClasses) {
    Class clasz = customClassLoader.loadClass(sourceFile, true);

    LinkedList<ClassDescriptorInner> innerClassDescList = sourceFile.getInnerClassDescriptors();
    if (innerClassDescList != null && !innerClassDescList.isEmpty()) {
      for (ClassDescriptorInner innerClassDesc : innerClassDescList) {
        customClassLoader.loadClass(innerClassDesc, true);
      }
    } else if (detectInnerClasses) {
      // Aprovechando la carga de la clase, hacemos el esfuerzo de cargar todas las clases
      // dependientes lo más
      // posible
      clasz
          .getDeclaredClasses(); // Provoca que las inner clases miembro indirectamente se procesen
                                 // y carguen
      // a través del JProxyClassLoader de la clase padre clasz

      // Ahora bien, lo anterior NO sirve para las anonymous inner classes, afortunadamente en ese
      // caso podemos
      // conocer y cargar por fuerza bruta
      // http://stackoverflow.com/questions/1654889/java-reflection-how-can-i-retrieve-anonymous-inner-classes
      // ?rq=1

      for (int i = 1; i < Integer.MAX_VALUE; i++) {
        String anonClassName = sourceFile.getClassName() + "$" + i;
        Class innerClasz = customClassLoader.loadInnerClass(sourceFile, anonClassName);
        if (innerClasz == null) {
          break; // No hay más o no hay ninguna (si i es 1)
        }
      }

      // ¿Qué es lo que queda por cargar pero que no podemos hacer explícitamente?
      // 1) Las clases privadas autónomas que fueron definidas en el mismo archivo que la clase
      // principal: no
      // las soportamos pues no podemos identificar en el ClassLoader que es una clase "hot
      // reloadable", no son
      // inner classes en el sentido estricto
      // 2) Las clases privadas "inner" locales, es decir no anónimas declaradas dentro de un
      // método, se
      // cargarán la primera vez que se usen, no podemos conocerlas a priori
      //    porque siguen la notación className$NclassName  ej.
      // JReloadExampleDocument$1AuxMemberInMethod. No
      // hay problema con que se carguen con un class loader antiguo pues
      //    el ClassLoader de la clase padre contenedora será el encargado de cargarla en cuanto se
      // pase por el
      // método que la declara.
    }
  }
Example #3
0
  private void deleteClasses(@NotNull ClassDescriptorSourceUnit sourceFile) {
    // Puede ocurrir que esta clase nunca se haya cargado y se ha modificado el código fuente y
    // queramos limpiar
    // los .class correspondientes pues se van a recrear
    // como no conocemos qué inner clases están asociadas para saber que .class hay que eliminar,
    // pues lo que
    // hacemos es directamente obtener los .class que hay
    // en el directorio con el fin de eliminar todos .class que tengan el patrón de ser inner
    // classes del source
    // file de acuerdo a su nombre
    // así conseguimos por ejemplo también eliminar las local classes (inner clases con nombre
    // declaradas dentro
    // de un método) que no hay manera de conocer
    // a través de la carga de la clase

    // Hay un caso en el que puede haber .class que ya no están en el código fuente y es cuando
    // tocamos el código
    // fuente ANTES de cargar y eliminamos algún .java,
    // al cargar como no existe el archivo no lo relacionamos con los .class
    // La solución sería en tiempo de carga forzar una carga de todas las clases y de ahí deducir
    // todos los
    // .class que deben existir (excepto las clases locales
    // que no podríamos detectarlas), pero el que haya .class sobrantes antiguos no es gran
    // problema.

    File classFilePath =
        ClassDescriptor.getAbsoluteClassFilePathFromClassNameAndClassPath(
            sourceFile.getClassName(), folderClasses);
    File parentDir = JProxyUtil.getParentDir(classFilePath);
    String[] fileNameList =
        parentDir.list(); // Es más ligero que listFiles() que crea File por cada resultado
    if (fileNameList != null) // Si es null es que el directorio no está creado
    {
      for (String fileName : fileNameList) {
        int pos = fileName.lastIndexOf(".class");
        if (pos == -1) {
          continue;
        }
        String simpleClassName = fileName.substring(0, pos);
        if (sourceFile.getSimpleClassName().equals(simpleClassName)
            || sourceFile.isInnerClass(sourceFile.getPackageName() + simpleClassName)) {
          new File(parentDir, fileName).delete();
        }
      }
    }
  }
Example #4
0
  private void compile(
      @NotNull ClassDescriptorSourceUnit sourceFile, @NotNull JProxyCompilerContext context) {
    if (sourceFile.getClassBytes() != null) {
      return; // Ya ha sido compilado seguramente por dependencia de un archivo compilado
              // inmediatamente antes,
    }
    // recuerda que el atributo classBytes se pone a null antes de compilar los archivos
    // cambiados/nuevos

    compiler.compileSourceFile(sourceFile, context, customClassLoader, sourceRegistry);
  }
Example #5
0
  private void cleanBeforeCompile(@NotNull ClassDescriptorSourceUnit sourceFile) {
    if (isSaveClassesMode()) {
      deleteClasses(
          sourceFile); // Antes de que nos las carguemos en memoria la clase principal y las inner
                       // tras
    }
    // recompilar

    sourceFile
        .cleanOnSourceCodeChanged(); // El código fuente nuevo puede haber cambiado totalmente las
    // innerclasses antiguas (añadido, eliminado) y por supuesto el bytecode necesita olvidarse
  }
Example #6
0
  private void saveClasses(@NotNull ClassDescriptorSourceUnit sourceFile) {
    // Salvamos la clase principal
    {
      File classFilePath =
          ClassDescriptor.getAbsoluteClassFilePathFromClassNameAndClassPath(
              sourceFile.getClassName(), folderClasses);
      JProxyUtil.saveFile(classFilePath, sourceFile.getClassBytes());
    }

    // Salvamos las innerclasses si hay, no hay problema de clases inner no detectadas pues lo están
    // todas pues
    // sólo se salva tras una compilación
    LinkedList<ClassDescriptorInner> innerClassDescList = sourceFile.getInnerClassDescriptors();
    if (innerClassDescList != null && !innerClassDescList.isEmpty()) {
      for (ClassDescriptorInner innerClassDesc : innerClassDescList) {
        File classFilePath =
            ClassDescriptor.getAbsoluteClassFilePathFromClassNameAndClassPath(
                innerClassDesc.getClassName(), folderClasses);
        JProxyUtil.saveFile(classFilePath, innerClassDesc.getClassBytes());
      }
    }
  }