Evaluar si .java de un directorio sn parte d el proyecto y acceder a metodos

Iniciado por danirebollo, 17 Noviembre 2012, 18:37 PM

0 Miembros y 1 Visitante están viendo este tema.

danirebollo

Hola! estoy haciendo una aplicacion que sea cliente de una base de datos la filtre y mas cosas...

Cada categoria o subcatecoria pone en una posicion de un combobox una palabra (el combobox es para seleccionar que lo que voy a crear forma parte de esa clase), por esto, y alguna cosa mas, querria evitar tener que modificar el codigo cada vez que añado una clase, en este caso tendria que modificar el metodo que rellene el combobox para decirle que tambien incluya la clase nueva.

La solucion que he encontrado y estoy desarrollando poco a poco para poder hacer esto de forma facil (facil para mantener la base de datos, no para crear el codigo de esta aplicacion, que me parece que con esto la estoy complicando mucho e incluso va a ser lenta, por lo menos al cargar al principio...) es la siguiente:
-obtengo los nombres de los ficheros de un directorio (parto del package principal donde estan los componentes (todas las clases que almacenan componentes de la base de datos) y si hay mas packages subo a ellos para leerlos tambien) y filtro los '.java' quitandoles la extension.

File fichero; //=new File("Readfile.java");
       fichero=new File(directory);
       
       String[] listaArchivos=fichero.list(); //crea un array cn los nombres de los ficheros en el directorio.      

       listaArchivos=fichero.list(new Filtro(".java")); //filtra los archivos dejando solo los que tienen extension '.java'

for(int i=0; i<listaArchivos.length; i++) //elimina la extension de el nombre del archivo
       {
           //System.out.println(listaArchivos[i]);
           listaArchivos[i]=listaArchivos[i].substring(listaArchivos[i].lastIndexOf('/') + 1, listaArchivos[i].lastIndexOf('.'));
           //System.out.println(listaArchivos[i].substring(listaArchivos[i].lastIndexOf('/') + 1, listaArchivos[i].lastIndexOf('.')));
       }
       

-
-creo una clase equivalente a la clase que tiene el mismo nombre del archivo

ClassLoader classLoader = Componente.class.getClassLoader();
       Class aClass = null;
       try {
       aClass= classLoader.loadClass("componentespkg.cat2."+classnamber);
}
 

-Instancio esa clase cast-andola (xd) con la clase que quiero comparar y ejecuto el metodo que me interesa, que es, por ejemplo el String que esa clase mandara al combobox.

El programa de momento lee los archivos en un directorio, los filtra y compara con instanceof con la clase padre o con las subclases, pero todavia tengo que darle yo demasiados datos...
Funciona, pero yo no quiero tener que saber la clase de antemano para hacer cast.
Probando si en cada metodo pongo static{}
solo, sin modificador ni nada (que no se para que sirve), podria obtener variables escribiendo que llame a una funcion de la clase principal y le de como parametro algo, pero el problema de eso es que solo es una funcion/metodo(?), entonces si quisiera obtener informacion ordenada de esa clase tendria que enviarla toda de golpe a la clase principal y alli ordenarla... vamos, que no ganaria mucho teniendo que crear un indice de quien me envia cada cosa y que cosa es...

Otro modo de hacer algo parecido seria con reflexion (bueno, lo tro tambien se vale de ella xd), seria leer las clases de un directorio y cargarlas en tiempo de ejecucion, el problema es que no se como podria acceder a sus metodos (si es que se puede).
Es decir: yo leo un directorio y cargo una de las clases, la clase 'abc' (el archivo se llama 'abc.java' y tiene los metodos a, b y c), que ahora esta e una clase generica Class x, por ejemplo. Como puedo acceder a los metodos 'a', 'b', 'c'? Yo se que la clase, en cuanto que se cargue (en tiempo de ejecucion) sera 'abc' y tendra el metodo 'a' al que podre llamar, pero el compilador no lo sabe.

En resumen, yo tengo una carpeta con las clases que sé, porque heredan de una clase principal que lo tiene, que tienen un metodo determinado 'metodo1', lo demas no lo se, pero ese si.
¿Como voy llamando a todos los metodos 'metodo1' de las clases que desconozco cuales son?

¿Como podria hacerlo?

Perdonar por la extension, pero no sabia como explicarlo brevemente xd.
Un saludo.

danirebollo

En main:

String str = "HELLO";
        Diodo dod;
        dod=new Diodo("","",0,"","");

    try {
     
      Method method = str.getClass().getMethod("toString"); //getMethod("toString", null);
      Object retVal = method.invoke(str); //invoke(str, null);
      System.out.println(retVal);
     
    } catch ...............(a lot of catchs xd)

Este codigo, sea con  'str.getClass()...' y 'method.invoke(str)'  tratando de obtener el toString de un String, o con  'dod.getClass()...' y 'method.invoke(dod)' tratando de obtener uno de los metodos de la clase Diodo, funcionan bien, pero cuando trato de obtener un metodo de 'aClass', declarado como Class aClass = null;, e instanciado con: aClass= classLoader.loadClass("componentespkg.cat2.Diodo"); , que deberia ser en este caso la clase Diodo, no funciona y me devuelve la excepcion

java.lang.NoSuchMethodException: java.lang.Class.toCB2CB()
at java.lang.Class.getMethod(Class.java:1622)
at inventarionb.InventarionbTEST.main(InventarionbTEST.java:83)

Hay una cosa, no se si tiene algo que ver con el error, cuando pone java.lang.Class.toCB2CB() en la excepcion. ¿Esa ruta es correcta? No creo que el metodo de mi clase derive del metodo Class, pero no sabria que poner... en el caso de que la clase se encuentre dentro de la clase principal, donde esta el main, no hay que poner mas cosas, pero lo mismo al estar fuera hay que poner algo en la ruta... no he conseguido que me funcione poniendo la sucesion de packages (separada por '.')

danirebollo

(acabo de ver que no dejaba responder porque el nombre de el titulo era muy largo y no podia poner 'Re: ' an el mensaje de respuesta, he acortado el titulo)

danirebollo

Creo que lo he resuelto (de momento me funciona, no se si luego mientras desarrolle el codigo tendre algun problema).
Hay que cambiar el package por defecto en el que busca las clases el classloader:

http://www.javablogging.com/java-classloader-2-write-your-own-classloader/

Este seria el classloader que estoy utilizando:

package pruebas;

import java.io.DataInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;

/**
* Our custom implementation of the ClassLoader.
* For any of classes from "javablogging" package
* it will use its {@link CustomClassLoader#getClass()}
* method to load it from the specific .class file. For any
* other class it will use the super.loadClass() method
* from ClassLoader, which will eventually pass the
* request to the parent.
*
*/
public class CustomClassLoader2 extends ClassLoader {

    /**
     * Parent ClassLoader passed to this constructor
     * will be used if this ClassLoader can not resolve a
     * particular class.
     *
     * @param parent Parent ClassLoader
     *              (may be from getClass().getClassLoader())
     */
    public CustomClassLoader2(ClassLoader parent) {
        super(parent);
    }
   
   
    /**
     * Loads a given class from .class file just like
     * the default ClassLoader. This method could be
     * changed to load the class over network from some
     * other server or from the database.
     *
     * @param name Full class name
     */
    private Class<?> getClass(String name)
        throws ClassNotFoundException {
        // We are getting a name that looks like
        // javablogging.package.ClassToLoad
        // and we have to convert it into the .class file name
        // like javablogging/package/ClassToLoad.class
        String file = name.replace('.', File.separatorChar)
            + ".class";
//       System.out.println("NAME: "+file);
        byte[] b = null;
        try {
            // This loads the byte code data from the file
            b = loadClassData(file);
            // defineClass is inherited from the ClassLoader class
            // and converts the byte array into a Class
            Class<?> c = defineClass(name, b, 0, b.length);
            resolveClass(c);
            return c;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * Every request for a class passes through this method.
     * If the requested class is in "javablogging" package,
     * it will load it using the
     * {@link CustomClassLoader#getClass()} method.
     * If not, it will use the super.loadClass() method
     * which in turn will pass the request to the parent.
     *
     * @param name
     *            Full class name
     */
    @Override
    public Class<?> loadClass(String name)
        throws ClassNotFoundException {
//       System.out.println("loading class '" + name + "'");
        if (name.startsWith("inventarionb.")) {
            return getClass(name);
        }
        else if (name.startsWith("componentespkg")) {
            return getClass(name);
        }     
        return super.loadClass(name);
    }

    /**
     * Loads a given file (presumably .class) into a byte array.
     * The file should be accessible as a resource, for example
     * it could be located on the classpath.
     *
     * @param name File name to load
     * @return Byte array read from the file
     * @throws IOException Is thrown when there
     *               was some problem reading the file
     */
    private byte[] loadClassData(String name) throws IOException {
        // Opening the file
        InputStream stream = getClass().getClassLoader()
            .getResourceAsStream(name);
        int size = stream.available();
        byte buff[] = new byte[size];
        DataInputStream in = new DataInputStream(stream);
        // Reading the binary data
        in.readFully(buff);
        in.close();
        return buff;
    }
}


y este el main:
package inventarionb;

import pruebas.*;

public class IntegerPrinterTest {
    /**
     * This main method shows a use of our CustomClassLoader for
     * loading some class and running it. All the objects referenced
     * from the IntegerPrinter class will be loaded with
     * our CustomClassLoader.
     */
    public static void main(String[] args) throws Exception
    {
        System.out.println(stringtoclassmethod("componentespkg.cat3.DiodoSchottky","toCB"));
        String[] a=(String[])stringtoclassmethod("componentespkg.cat3.DiodoSchottky","toCol");
        for(int i=0;i<a.length;i++)
        {
        System.out.print(a[i]+", ");
        }
        System.out.print("\n");
        System.out.println(stringtoclassmethod("componentespkg.cat2.Diodo","toCB"));
        a=(String[])stringtoclassmethod("componentespkg.cat2.Diodo","toCol");
        for(int i=0;i<a.length;i++)
        {
        System.out.print(a[i]+", ");
        }
    }
    public static Object stringtoclassmethod (String dir, String method) throws Exception
    {
       // dir="componentespkg.cat3.DiodoSchottky";
       // method="toCB";
       
        CustomClassLoader2 loader = new CustomClassLoader2(IntegerPrinterTest.class.getClassLoader()); //(StaticAccessorTest.class.getClassLoader());
        Class<?> clazz =
        loader.loadClass(dir); //inventarionb.IntegerPrinter //componentespkg.cat2.Diodo
        Object instance = clazz.newInstance();
        Object aas=clazz.getMethod(method).invoke(instance);//runMe // toCB2CB
        //System.out.println(aas);
        return aas;
    }
}


Esta un poco desordenado, hay anotaciones por el codigo y codigo omitido... pero como referencia sirve. Ire adaptandolo a mi otro programa.