2011-12-02 6 views
5

Ho ciò che sembra un'attività di una libreria Java ingannevole.Scrittura di una libreria Java per gestire in modo condizionale una classe di input senza causare una dipendenza di runtime incondizionata su tale classe

Ho bisogno di scrivere una classe adattatore/helper per lavorare con JTable s che ha alcune funzionalità aggiuntive se il JTable è un JXTable. Ma io non voglio aggiungere una dipendenza runtime su swingx-core-1.6.2.jar meno la mia applicazione utilizza in realtà JXTable (nel qual caso si richiede già avere il file jar SwingX sul classpath)

Come posso disaccoppiare il mio codice per realizzare questo? Non so nemmeno come posso testare per JXTable; se provo a usare instanceof JXTable come test, significa che il mio codice ha già una dipendenza di runtime incondizionata su JXTable.

ho scritto prima di librerie Java che hanno dipendenze linkage runtime "opzionali": se ho questo nella mia biblioteca:

package com.foobar.foolib; 

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

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

e SuperObject è l'unica classe che utilizza whizbang.jar, quindi fintanto la mia applicazione finale non utilizza SuperObject, quindi non esiste alcuna dipendenza di runtime su whizbang.jar; se la mia applicazione finale desidera utilizzare SuperObject, è necessario includere whizbang.jar sul classpath. Opzionale dal punto di vista dell'applicazione. Funziona alla grande.

Come posso scrivere un metodo per verificare che una determinata tabella J sia un'istanza di JXTable, senza richiedere una dipendenza dal file jar SwingX se l'applicazione utilizza solo JTable?

risposta

2

Ciò richiede una riflessione. Utilizzare Class.forName(...) per recuperare l'oggetto Class per la classe JXTable. Se non è presente, genererà ClassNotFoundException.

Se è presente, è possibile utilizzare quell'oggetto Class per recuperare i metodi necessari e quindi applicarli all'oggetto JTable.

0

Prima di tutto, è una dipendenza di tempo di compilazione che si sta tentando di eliminare, non di runtime.

È possibile controllare il tipo della classe tramite

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

Non è un tempo di compilazione dipendenza che sto cercando di eliminare; Intendo che la mia libreria abbia una dipendenza in fase di compilazione su SwingX. Non voglio solo una dipendenza * runtime * su SwingX a meno che anche la mia applicazione non funzioni. –

5

È possibile verificare con:

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

if(cls != null) 
    // have JXTable 

Dopo di che si dovrebbe utilizzare la riflessione esclusivamente per tutti gli accessi alle classi, metodi, costruttori e campi da quella libreria esterna.

come questo può diventare molto goffo se è necessario accedere a una grande API in questo modo si potrebbe scrivere classi di supporto che possono utilizzare direttamente JXTable ma vengono creati tramite la riflessione e invocato tramite interfacce o classi astratte:

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 Java VM non ha problemi con l'utilizzo dell'API inesistente in classi che non sono utilizzate da sole ma sono presenti solo nei file jar. Con questo approccio useresti JXTableHandler solo se org.jdesktop.swingx.JXTable è disponibile e StdTableHandler in caso contrario.

+0

+1 per alcuni pensieri utili. –

0

Aha, ho avuto qualcosa su cui lavorare: classe

Helper nella mia 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 altrove nella mia biblioteca:

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"); 
    } 

mi sono imbattuto di un'applicazione con esso una volta usando solo JTables, senza swingx sul mio classpath, e funziona, perché intercetta NoClassDefFoundError, e in tal caso non tenta mai di accedere alla classe JXTable. Se uso JXTable nella mia applicazione con swingx sul mio classpath, funziona anche. (e funziona anche se uso JXTable nella mia applicazione senza swingx sul mio classpath, perché l'applicazione non può creare un'istanza di una JXTable che è un comportamento previsto che la mia libreria non cambia.)

+0

JXTableHandler in questa appraoch non è garantito il caricamento senza NoClassDefFoundErrors in 'new JXTableHandler(). HandleTable (table); '. Dovrebbe funzionare fintanto che non ha variabili o classi interne che dipendono da classi esterne non esistenti. Ma preferisco evitare di caricare una classe di helper del genere se l'API richiesta non è disponibile per essere sicuro di non ottenere improvvisamente Exceptions quando la classe evolve. – x4u

Problemi correlati