Estos días me he estado peleando con Java para conseguir una cosa. Resulta que en JavaVis (una herramienta para procesamiento de visión artificial desarrollada por nuestro grupo de investigación) tenemos una opción que nos pareció muy buena: si quieres añadir un algoritmo a la librería, simplemente dicho algoritmo se escribe en una clase que hereda de una clase abstracta y se deja en un determinado directorio. Dicho directorio se encuentra dentro de la estructura de paquetes de la librería. Por ejemplo, si el paquete es javavis.jip2d.functions todos los algoritmos forman parte de este paquete.
Esto que tiene de ventaja: podemos cargar de manera dinámica los algoritmos, no es necesario que el usuario especifique en ningún sitio que hay una nueva función o que alguna existente ha cambiado de nombre. Esto simplifica mucho la tarea para el usuario. Pero claro, ¿cómo cargar de manera dinámica esas clases? Muy sencillo, usando reflection Con el método Class.forName(), pasándole un String con el nombre de la clase, carga de manera dinámica dicha clase. Lo que hacíamos hasta ahora era buscar dentro del directorio del paquete, por ejemplo, en javavis//jip2d//functions todos los ficheros con extensión .class y luego cargábamos con el Class.forName() la clase. Sencillo y eficaz, aunque un poco lento al tener que leer del sistema de ficheros.
Pero esto tiene un problema insalvable: si quieres que tu aplicación se distribuya como un único fichero jar, ya no vas a tener los directorios y entonces ya no vas a poder acceder a esas clases. La solución es seguir usando reflection, pero obteniendo las clases de un determinado paquete. La clase estándar de Java para reflection no permite hacer esto, por lo que tenemos que descargar una librería con nombre, tachán!, reflections http://code.google.com/p/reflections/ Añadimos esta librería a nuestro proyecto o lo incluimos en el classpath y a funcionar. Dejo aquí un trozo de código explicado para poder acceder a las clases dentro de un paquete.
Reflections reflections = new Reflections(“javavis.jip2d.functions”); // Por reflection obtenemos la lista de clases que se encuentran dentro de ese paquete.
Class<? extends JIPFunction> func; // Todas esas clases heredan de JIPFunction
Object[] funcList = ((HashSet)reflections.getSubTypesOf(JIPFunction.class)).toArray(); // Se obtiene un array con las clases.
for (int cont=0; cont<funcList.length; cont++) {
func = (Class<? extends JIPFunction>)funcList[cont]; // Se convierte la clase JIPFunction
JIPFunction jf = func.newInstance(); // Se obtiene una nueva instancia de la clase.
System.out.println(func.getName()); // Muestra el nombre de la clase (entero, con todos los paquetes)
}