Geek-dependent injection for beans entity?

For a project with a rich domain, I want to use Guice dependency injection in the JPA / Hibernate beans entity . I am looking for a similar solution like Spring @configurable annotation for non Spring beans.

Does anyone know a library? Any code examples?

+7
aop hibernate jpa guice domain-driven-design
source share
3 answers

You can do this with AspectJ.

Create an @Configurable annotation:

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

Create an AspectJ @Aspect similar to this:

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

Create (and use) a hold class for your injector:

 public final class InjectorHolder { private static Injector injector; static void setInjector(Injector injector) { InjectorHolder.injector = injector; } public static Injector getInjector() { return injector; } } 

Set up 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> 

Start your virtual machine with aspectjweaver:

 -javaagent:lib/aspectjweaver.jar 

Annotate your domain classes:

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

I found a slightly dirty solution to this problem.

Assuming that there are only two ways to create an entity object of type T :

  • Getting one of javax.inject.Provider<T>
  • Request it from the entity manager (which will call the annotated @PostLoad methods).

Assuming you have an infrastructure base class for all of your objects, you can simply add an entity listener to this object. In this example, I am using static injection - there may be a better way.

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

In module configuration, you just need to call requestStaticInjection(PersistentDomainObject.class);

Now you can create entity classes such as

 @Entity public class MyDomainEntity extends PersistentDomainObject<SomeEmbeddableIdType> implements HatLegacyId { @Inject private transient MyDomainService myDomainService; private String name; // ... common stuff } 

Not a bad thing, you must believe that no one will create MyDomainEntity their own, but ask Provider<MyDomainEntity> for this. This can be achieved by hiding the constructor.

Yours faithfully,

Avi

+3
source share

Since entities are created by the JPA provider, I don’t see when Guice comes into play. Perhaps look at Salve's approach though.

+1
source share

All Articles