2010-07-17 23 views
7

Para un diseño de dominio enriquecido Deseo usar Inyección de dependencia de Guice en beans de entidad JPA/Hibernate. Estoy buscando una solución similar a la anotación Spring @configurable para beans que no sean Spring.Guice dependency injection for entity beans?

¿Alguien sabe de una biblioteca? ¿Algún ejemplo de código?

Respuesta

5

Puede hacer esto con AspectJ.

Crear la anotación @Configurable:

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

Crear una @Aspect AspectJ similar a esto:

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

Crear (y uso) una clase de retención para su inyector:

public final class InjectorHolder { 

    private static Injector injector; 

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

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

Configurar 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> 

Comience su máquina virtual con aspectjweaver:

-javaagent:lib/aspectjweaver.jar 

anotar sus clases de 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

Como las entidades son creadas por el proveedor de JPA, no veo cuándo entrará en juego Guice. Sin embargo, tal vez eche un vistazo al enfoque del proyecto Salve.

+0

Gracias, una solución codeweaving como ungüento podría realmente hacer el truco. Intenté Salve, pero tiene documentación limitada y no puedo hacer que haga nada (ni siquiera un mensaje de error). Solo esperaba algún código de muestra simple, por ejemplo con AspectJ o incluso mejor AOP. – Kdeveloper

+0

@ Kdeveloper: No tengo ninguna experiencia con Salve, así que no puedo recomendarlo, pero podría darte algunas ideas para implementar algo similar y es por eso que lo mencioné –

3

He encontrado una solución sucia bits para este problema.

Suponiendo que sólo hay dos maneras de crear un objeto de entidad de tipo T:

  • la obtención de uno de un javax.inject.Provider<T>
  • quering desde el gestor de la entidad (que se llame @PostLoad métodos anotados).

Además, suponiendo que tenga una clase base infraestructural para todas sus entidades, puede agregar un agente de escucha de entidad a esta entidad. En este ejemplo, uso inyección estática, tal vez haya una manera más agradable.

@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 ... 
} 

En la configuración de su módulo sólo tiene que llamar requestStaticInjection(PersistentDomainObject.class);

Ahora simplemente puede crear clases de entidad como

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

    @Inject 
    private transient MyDomainService myDomainService; 

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

Lo malo en ello, usted tiene que confiar en que nadie va a crear un MyDomainEntity por su cuenta, pero le pedirá un Provider<MyDomainEntity> para ello. Esto podría proporcionarse ocultando el constructor.

Saludos cordiales,

avi

+0

Aunque la inyección estática de alguna manera desalentó, agregando una dependencia como AspectJ en este momento no es asequible para mi proyecto. Además, la solución se ajusta a mi problema y está bastante limpia. – Iacopo

Cuestiones relacionadas