7

Esempio di utilizzo:
Voglio mettere sui campi classe un'annotazione personalizzata @MyContainer e quindi aggiungere automaticamente su tutti i campi le annotazioni Hibernate pertinenti (a seconda del tipo di campo e delle proprietà).
In aggiunta, ho bisogno di aggiungere l'annotazione JAXB XmlType alla classe e basare il nome del tipo sul nome della classe.
Vorrei aggiungere anche annotazioni ai campi in base ai tipi, ecc. Tutte le annotazioni aggiunte dovrebbero essere disponibili in fase di esecuzione (quindi Hibernate/JAXB può trovarle).
Sono consapevole delle seguenti opzioni:Aggiunta di annotazioni programmatiche a una classe Java

  1. pre-elaborazione sorgente della classe (opzione male)
  2. di lavorazione durante la compilazione con le API javax.annotation.processing
  3. Messaggio manipolazione compilation con strumenti come Java Assist
  4. manipolazione in fase di carico di classe con le API java.lang.instrument
  5. farlo con AspectJ (non abbastanza potente)

I miei obiettivi primari sono:

  1. mantenere la sincronia tra classe e la fonte per il debug
  2. Supporto di lavoro sia da Maven e IDE (Eclipse/IntelliJ)

Io apprezzo se le persone che già fatto tali cose può raccomandare l'approccio migliore per tale compito (e forse potenziali insidie).

+0

Che dire di non generare annotazioni, ma invece di generare file di mapping Hibernate XML (hbm.xml) che possono essere caricati dalla configurazione di ibernazione? – Strelok

+0

Grazie, è una buona idea ma preferisco l'opzione di annotazione nel mio caso poiché ho bisogno di generare anche annotazioni JAXB (e forse altre in futuro). –

risposta

0

Penso che le fonti di classe di pre-elaborazione dovrebbero essere il tuo modo preferito. Ciò ti consente di sincronizzare le tue fonti con le classi compilate, il che è positivo per il debug come hai menzionato. Ma è anche utile per il controllo della versione, dal momento che è possibile controllare le annotazioni generate. È anche molto più difficile rintracciare i problemi nel tuo strumento, se è eseguito durante la compilazione. Anche il supporto IDE non dovrebbe costituire un problema quando si esegue la generazione del codice nella fase generate-sources.

Edit: ricerca rapida ha prodotto alcuni dettagli sulla modifica fonte programmatica java using the eclipse jdt o some thing in netbeans. Ma questo potrebbe valere qualche ricerca in più o una domanda a parte.

+0

Grazie per la risposta. Potete fornire maggiori informazioni sulla soluzione, ad esempio quale strumento può essere utilizzato per analizzare il codice sorgente e manipolarlo? Il lato negativo è che il codice sorgente viene riempito con annotazioni di basso livello ed è meno chiaro (ho pensato di aggiungere l'annotazione solo per il runtime). –

+0

Se si teme che ciò possa portare a codice non pulito, si dovrebbe prendere in considerazione l'utilizzo di un'interfaccia della classe corrente e nascondere l'implementazione con annotazioni il più possibile. – SpaceTrucker

0

Voglio suggerire un altro approccio al riguardo. Poiché il mio first answer potrebbe comportare la codifica di un proprio strumento, potresti anche provare una soluzione molto più semplice. Come spero tu stia testando le tue classi, potresti implementare una classe base per ogni unit test di tale classe. In questa classe base esiste un metodo di test, che verifica che ogni campo annotato con @MyContainer contenga anche le annotazioni di ibernazione richieste.

Fondamentalmente abbiamo fatto la stessa cosa, non per le annotazioni ma per la serializzabilità dei campi e abbiamo funzionato abbastanza bene con questo approccio.

0

Per farlo funzionare in modo più trasparente in IDE, la configurazione della riga di comando e in fase di esecuzione, l'opzione 1 (utilizzando APT) e l'opzione 5 (utilizzando AspectJ) ti daranno la soluzione migliore.

Per l'opzione 1 è necessario implementare il proprio processore di annotazione che inietterà annotazioni aggiuntive in base alla presenza della propria annotazione @MyContainer.Ecco un esempio di questo approccio utilizzato per something similar.

Per l'opzione 5 è sufficiente utilizzare annotation declaration. Qualcosa di simile a questo:

declare @field : * ((@*..MyContainer *)).*(..) : @OtherAnnotation(); 

strumento Roo Primavera è ampiamente utilizzato l'opzione 5 e certamente non può dire che non è abbastanza potente.

+0

È possibile basare i parametri di annotazioni e annotazioni sulla classe/metodo/informazioni sui membri? Ad esempio, devo esaminare il tipo di dati del contenitore e selezionare tra alcune possibili annotazioni di ibernazione. In aggiunta ho bisogno di generare i nomi delle colonne per l'annotazione di ibernazione in base ai nomi dei campi, ecc ... –

0

Ci sono poche alternative come menzionato sopra e ciascuna ha i suoi lati positivi e negativi. Ecco perché non penso ci sia una vera risposta "giusta" per la domanda di cui sopra. Il mio scopo era ottenere input dalla comunità e da persone che avevano fatto cose del genere in passato e hanno esperienza. Personalmente ho scelto di usare lo Instrument API con Javassist. In questo modo le classi vengono estese in fase di esecuzione (sebbene lo stesso strumento possa essere utilizzato per l'elaborazione post-compilazione). La cosa bella è che l'agente può essere caricato dall'interno della JVM che evita di gestire tutte le linee di comando. Sarà bello ascoltare altre alternative.
Grazie,
Avner

0

Ecco un esempio di codice per la definizione di annotazione personalizzate. Questo @TesterInfo viene applicato a livello di classe, memorizza i dettagli del tester. Questo mostra il diverso uso dei tipi di ritorno: enum, array e stringa.

package com.mkyong.test.core; 

import java.lang.annotation.ElementType; 
import java.lang.annotation.Retention; 
import java.lang.annotation.RetentionPolicy; 
import java.lang.annotation.Target; 

@Retention(RetentionPolicy.RUNTIME) 
@Target(ElementType.TYPE) //on class level 
public @interface TesterInfo { 

    public enum Priority { 
     LOW, MEDIUM, HIGH 
    } 

    Priority priority() default Priority.MEDIUM; 

    String[] tags() default ""; 

    String createdBy() default "Mkyong"; 

    String lastModified() default "03/01/2014"; 

} 
Problemi correlati