2011-12-02 8 views
5

Tengo lo que parece una tarea difícil de la biblioteca Java.Escribir una biblioteca Java para manejar condicionalmente una clase de entrada sin causar dependencia en el tiempo de ejecución incondicional en esa clase

Tengo que escribir una clase/ayudante adaptador para trabajar con JTable s que tiene algunas funciones adicionales si el JTable es una JXTable. Pero yo no quiero agregar una dependencia de tiempo de ejecución en SwingX-core-1.6.2.jar menos que mi aplicación utiliza realmente JXTable (en cuyo caso se requiere ya que tiene el archivo jar SwingX en la ruta de clase)

Cómo ¿Puedo desacoplar mi código para lograr esto? Ni siquiera sé cómo puedo probar JXTable; si trato de usar instanceof JXTable como una prueba, eso significa que mi código ya tiene una dependencia de tiempo de ejecución incondicional en JXTable.

He escrito bibliotecas de Java antes de que se han "opcionales" dependencias de enlace en tiempo de ejecución: si tengo esto en mi biblioteca:

package com.foobar.foolib; 

// import from whizbang.jar 
import com.whizbang.BloatwareThingy; 

public class SuperObject 
{ 
    /* ... uses a BloatwareThingy ... */ 
} 

y SuperObject es la única clase que utiliza whizbang.jar, a continuación, siempre y cuando mi aplicación final no usa SuperObject, entonces no hay dependencia de tiempo de ejecución en whizbang.jar; si mi aplicación final desea usar SuperObject, entonces debe incluir whizbang.jar en classpath. Opcional desde el punto de vista de la aplicación. Funciona genial.

¿Cómo puedo escribir un método para probar que una JTable determinada sea una instancia de JXTable, sin requerir una dependencia en el archivo jar SwingX si la aplicación solo utiliza JTable?

Respuesta

2

Esto requiere reflexión. Use Class.forName(...) para obtener el objeto Class para la clase JXTable. Si no está presente, lanzará ClassNotFoundException.

Si está presente, puede usar ese objeto Clase para buscar los métodos que necesita y luego aplicarlos al objeto JTable.

0

En primer lugar, es una dependencia de tiempo de compilación que está tratando de eliminar, no en tiempo de ejecución.

Puede comprobar el tipo de la clase a través de

if (table.getClass().getName().equals("path.to.JXTable") 
{ 
// Do something using reflection. 
} 
else // proceed as normal 
+0

No es un tiempo de compilación dependencia que estoy tratando de eliminar; Tengo la intención de que mi biblioteca tenga una dependencia en tiempo de compilación en SwingX. Simplemente no quiero una dependencia de * runtime * en SwingX a menos que mi aplicación también lo haga. –

5

Puede probar con:

Class cls = null; 
try { 
    cls = Class.forName("org.jdesktop.swingx.JXTable"); 
} catch(Throwable ex) {} 

if(cls != null) 
    // have JXTable 

Después de que usted tendría que utilizar la reflexión exclusivamente para todos los accesos a clases, métodos, constructores y campos de esa biblioteca externa.

ya que esto puede llegar a ser muy torpe si necesita acceder a una gran API de esta manera se podría escribir clases de ayuda que pueden utilizar JXTable directamente, sino que se crean a través de la reflexión y la invocada a través de interfaces o clases abstractas:

public interface MyTableHandler 
{ 
    void doSomethingWithTable(JTable table); 
} 

public class JXTableHandler implements MyTableHandler 
{ 
    void doSomethingWithTable(JTable table) 
    { 
     JXTable jxt = (JXTable) table; 
     // use JXTable API directly ... 
    } 
} 

public class StdTableHandler implements MyTableHandler 
{ 
    void doSomethingWithTable(JTable table) 
    { 
     // do without JXTable 
    } 
} 

public class MyIndependentClass 
{ 
    static final MyTableHandler handler; 

    static { 
     try { 
      Class.forName("org.jdesktop.swingx.JXTable"); // force exception 
      handler = (MyTableHandler) Class.forName("my.pkg.JXTableHelper") 
              .newInstance(); 
     } catch(Throwable ex) { 
      handler = new StdTableHandler(); 
     } 
    } 
    public void treatTable(JTable table) 
    { 
     handler.doSomethingWithTable(table); 
    } 
} 

La máquina virtual Java no tiene problemas con el uso de la API no existente en las clases que no se utilizan, pero solo están presentes en los archivos jar. Con este enfoque, usaría JXTableHandler solo si org.jdesktop.swingx.JXTable está disponible y StdTableHandler de lo contrario.

+0

+1 para algunos pensamientos útiles. –

0

Aha, tengo algo para trabajar: Clase

ayudante en mi biblioteca:

static private class JXTableHandler 
{ 
    public JXTableHandler() {} 

    boolean testJXTable(JTable table) 
    { 
     try 
     { 
      if (table instanceof JXTable) 
       return true; 
     } 
     catch (java.lang.NoClassDefFoundError e) { /*gulp*/ } 
     return false; 
    } 
    boolean handleTable(JTable table) 
    { 
     if (!testJXTable(table)) 
      return false; 

     JXTable xtable = (JXTable) table; 
     // here's where we do stuff, this is just something basic 
     System.out.println("columnControlVisible: " 
      +xtable.isColumnControlVisible()); 
     return true; 
    } 
} 

uso en mi biblioteca en otra parte:

JComponent c = ... 

    if (c instanceof JTable) 
    { 
     JTable table = (JTable) c; 
     boolean isJXTable = new JXTableHandler().handleTable(table); 
     System.out.println("jtable "+ 
      (isJXTable ? "is" : "is not")+" a jxtable"); 
    } 

me encontré con una aplicación con la que una vez usando solo JTables, sin swingx en mi classpath, y funciona, porque atrapa el NoClassDefFoundError, y en ese caso nunca intenta acceder a la clase JXTable. Si uso JXTable en mi aplicación con swingx en mi classpath, también funciona. (y también "funciona" si uso JXTable en mi aplicación sin swingx en mi classpath, porque la aplicación no puede crear una instancia de JXTable, que es el comportamiento esperado de que mi biblioteca no cambie).

+0

No se garantiza que JXTableHandler cargue sin NoClassDefFoundErrors en 'new JXTableHandler(). HandleTable (table); '. Debería funcionar siempre que no tenga variables o clases internas que dependan de clases externas no existentes. Pero prefiero evitar cargar tal clase de ayuda si la API requerida no está disponible para asegurarme de no recibir Excepciones de repente cuando la clase evolucione. – x4u

Cuestiones relacionadas