2010-07-17 14 views
7

Per un progetto basato su domini avanzati, desidero utilizzare l'iniezione di dipendenza di Guice su bean di entità JPA/Hibernate. Sto cercando una soluzione simile all'annotazione di Spring @configurable per i bean non Spring.Iniezione di dipendenza di Guice per bean di entità?

Qualcuno sa di una biblioteca? Qualche esempio di codice?

risposta

5

È possibile farlo con AspectJ.

Creare l'annotazione @Configurable:

@Retention(RetentionPolicy.RUNTIME) 
@Target({ElementType.TYPE}) 
public @interface Configurable { 
} 

Crea un AspectJ @Aspect simile a questo:

@Aspect 
public class ConfigurableInjectionAspect { 
    private Logger log = Logger.getLogger(getClass().getName()); 

    @Pointcut("@within(Configurable) && execution(*.new(..)) && target(instantiated)") 
    public void classToBeInjectedOnInstantiation(Object instantiated) {} 

    @After(value = "classToBeInjectedOnInstantiation(instantiated)", 
      argNames = "instantiated") 
    public void onInstantiation(Object instantiated) { 
     Injector injector = InjectorHolder.getInjector(); 
     if (injector == null) { 
      log.log(Level.WARNING, "Injector not available at this time"); 
     } else { 
      injector.injectMembers(instantiated); 
     } 
    } 
} 

Crea (e l'uso) una classe di tenuta per il vostro iniettore:

public final class InjectorHolder { 

    private static Injector injector; 

    static void setInjector(Injector injector) { 
     InjectorHolder.injector = injector; 
    } 

    public static Injector getInjector() { 
     return injector; 
    } 
} 

Configure META-INF/aop.xml:

<aspectj> 
    <weaver options="-verbose"> 
     <include within="baz.domain..*"/> 
     <include within="foo.bar.*"/> 
    </weaver> 
    <aspects> 
     <aspect name="foo.bar.ConfigurableInjectionAspect"/> 
    </aspects> 
</aspectj> 

Avviare il VM con aspectjweaver:

-javaagent:lib/aspectjweaver.jar 

annotare le classi di dominio:

@Entity 
@Table(name = "Users") 
@Configurable 
public class User { 
    private String username; 
    private String nickname; 
    private String emailAddress; 
    @Inject 
    private transient UserRepository userRepository 

    public User() {} 
} 
1

Poiché le entità sono create dal provider JPA, non riesco a vedere quando Guice entrerà in gioco. Forse date un'occhiata all'approccio del progetto Salve.

+0

Grazie, una soluzione codeweaving come Salve potrebbe davvero fare il trucco. Ho provato Salve, ma ha una documentazione limitata e non riesco a farlo fare nulla (nemmeno un messaggio di errore). Ho solo sperato in qualche semplice codice di esempio, ad esempio con AspectJ o ancora meglio AOP. – Kdeveloper

+0

@Kdeveloper: Non ho alcuna esperienza con Salve quindi non posso raccomandarlo ma potrebbe darti qualche idea per implementare qualcosa di simile, motivo per cui l'ho menzionato –

3

ho trovato una soluzione sporca po 'per questo problema.

Supponendo che non ci sono solo due modi per creare un oggetto entità di tipo T:

  • Ottenere uno da un javax.inject.Provider<T>
  • quering dal gestore di entità (che chiamerà @PostLoad metodi annotati).

Supponendo inoltre di disporre di una base di riferimento infrastrutturale per tutte le entità, è sufficiente aggiungere un listener di entità a questa entità. In questo esempio io uso l'iniezione statica - forse c'è un modo più carino.

@MappedSuperclass 
public abstract class PersistentDomainObject<K extends Serializable & Comparable<K>> 
    implements Comparable<PersistentDomainObject<K>>, Serializable { 

    private static transient Injector injector; 

    @PostLoad 
    private final void onAfterLoaded() { 
     injector.injectMembers(this); 
    } 

    @EmbeddedId 
    private K id; 

    public K getId() { return id; } 

    // ... compareTo(), equals(), hashCode(), maybe a @Version member ... 
} 

nella configurazione del modulo si solo bisogno di chiamare requestStaticInjection(PersistentDomainObject.class);

Ora si può semplicemente creare classi di entità come

@Entity 
public class MyDomainEntity extends PersistentDomainObject<SomeEmbeddableIdType> 
    implements HatLegacyId { 

    @Inject 
    private transient MyDomainService myDomainService; 

    private String name; 
    // ... common stuff 
} 

cosa negativa, devi avere fiducia in che nessuno creerà un MyDomainEntity da solo, ma chiederà un Provider<MyDomainEntity> per questo. Questo potrebbe essere fornito nascondendo il costruttore.

Cordiali saluti,

avi

+0

Anche se l'iniezione statica in qualche modo scoraggiava, aggiungendo una dipendenza come AspectJ al momento non è conveniente per il mio progetto. Inoltre, la soluzione è adatta al mio problema e abbastanza pulita. – Iacopo

Problemi correlati