2013-06-23 12 views
10

Vorrei creare una sottoclasse in modo programmatico. Credo di avere poche opzioni - Javassist, CGLib, BCEL o ASM.Java - creazione dinamica di una sottoclasse

Il caso d'uso è che gli interni di una app sono orientati alla classe e le estensioni sono basate sulla classe. Pertanto non posso avere una singola classe come base per più estensioni guidate da script esterni.

Ora, come potrei farlo? Ho trovato esempi con l'intercettazione di chiamate di metodo, accesso al campo, inizializzazione ecc. Ma nulla sulla sottoclasse.

mi piacerebbe finire con una classe che:

  • ha un nome che voglio.
  • è una (diretta, nella migliore delle ipotesi) sottoclasse di una data classe
  • copie del costruttore (s) dalla classe genitore (o chiamate super(...))
  • alla fine, mi piacerebbe dargli alcune annotazioni.

So che è possibile perché varie integrazioni di linguaggi dinamici, come GroovyClassLoader, possono farlo.

risposta

5

E 'abbastanza facile con Javassist:

import javassist.CannotCompileException; 
import javassist.ClassPool; 
import javassist.CtClass; 
import javassist.NotFoundException; 

static Class<? extends DefinitionBasedMigrator> createClass(String fullName) 
     throws NotFoundException, CannotCompileException 
{ 
    ClassPool pool = ClassPool.getDefault(); 

    // Create the class. 
    CtClass subClass = pool.makeClass(fullName); 
    final CtClass superClass = pool.get(DefinitionBasedMigrator.class.getName()); 
    subClass.setSuperclass(superClass); 
    subClass.setModifiers(Modifier.PUBLIC); 

    // Add a constructor which will call super(...); 
    CtClass[] params = new CtClass[]{ 
     pool.get(MigratorDefinition.class.getName()), 
     pool.get(GlobalConfiguration.class.getName()) 
    }; 
    final CtConstructor ctor = CtNewConstructor.make(params, null, CtNewConstructor.PASS_PARAMS, null, null, subClass); 
    subClass.addConstructor(ctor); 

    return subClass.toClass(); 
} 

Maven dipendenza:

<!-- https://mvnrepository.com/artifact/org.javassist/javassist --> 
<dependency> 
    <groupId>org.javassist</groupId> 
    <artifactId>javassist</artifactId> 
    <version>3.22.0-GA</version> 
</dependency> 
2

Java La delega può essere in grado di fare ciò che si richiede - che essenzialmente consentono allo strato dinamicamente la funzionalità in cima ad un oggetto, in quanto è possibile intercettare qualsiasi chiamata di metodo a quell'oggetto e gestirli autonomamente o inviare le chiamate al metodo alla classe sottostante. A seconda di ciò che si sta cercando di fare, è possibile ottenere lo stesso risultato creando una sottoclasse dinamicamente

Oracle ha un decent introduction sul proprio sito Web (l'URL fa riferimento alla versione 1.4.2 di Java, ma non credo che il comportamento di questo sia cambiato nelle versioni più recenti). Ecco un more concise example che dà un buon sapore per il codice del proxy.

È anche possibile eseguire operazioni utilizzando la manipolazione diretta dei byte di codice (come supportato dallo ASM framework) tuttavia, immagino che l'utilizzo dei proxy sia un approccio più semplice.

+0

In realtà ho guardato prima i proxy ma l'ho lasciato a causa della complessità. Javassist è così facile. Inoltre, i proxy necessitano di un'interfaccia e non possono essere ulteriormente sostituiti dalle normali classi ... comunque, +1 –

7

Una libreria a cui sono particolarmente affezionato può essere utilizzata qui; Bytebuddy.

esempio tratto direttamente dalla pagina di destinazione:

Class<?> dynamicType = new ByteBuddy() 
    .subclass(Object.class) 
    .method(ElementMatchers.named("toString")) 
    .intercept(FixedValue.value("Hello World!")) 
    .make() 
    .load(getClass().getClassLoader(), ClassLoadingStrategy.Default.WRAPPER) 
    .getLoaded(); 

E 'incredibilmente flessibile e sicuramente la pena di verificare se si desidera mantenere i capelli, io personalmente trovo un utilizzo intenso di javassist può diventare piuttosto brutto e a volte incasinato, bytebuddy si sente come una ventata di aria fresca!

Rafael Winterhalter è anche attivo su StackOverflow che consente di scoprire qualsiasi cosa di cui non si è sicuri.

Modifica: le mie scuse per la necropostazione.Atterrato qui quando un amico ha collegato la domanda e si è dimenticato di controllare la data.