开发者

Guice dependency injection for entity beans?

开发者 https://www.devze.com 2023-01-07 13:47 出处:网络
For a rich domain driven design I want to use Guice dependency injection on JPA/Hibernate entity beans. I am looking for a similar solution as the Spring @configurable annotation for non-Spring beans.

For a rich domain driven design I want to use Guice dependency injection on JPA/Hibernate entity beans. I am looking for a similar solution as the Spring @configurable annotation for non-Spring beans.

Does anybody know of a library? Any code examples?开发者_JAVA技巧


You can do this with AspectJ.

Create the @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 holding 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;
    }
}

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>

Start your VM 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() {}
}


I found a bit dirty workaround for this problem.

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

  • Obtaining one from a javax.inject.Provider<T>
  • Quering it from the entity manager (which will call @PostLoad annotated methods).

Further assuming you have a infrastructural baseclass for all of your entities, you can just add an entity listener to this entity. In this example I use static injection - maybe there is a nicer 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 your module setup you just need to call requestStaticInjection(PersistentDomainObject.class);

Now you simply can create entity classes like

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

    @Inject
    private transient MyDomainService myDomainService;

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

Bad thing about it, you have to trust in that noone will create a MyDomainEntity on his own but will ask a Provider<MyDomainEntity>for it. This could be provided by hiding the constructor.

Kind regards,

avi


Since entities are created by the JPA provider, I fail to see when Guice will come in play. Maybe have a look at the approach of the Salve project though.

0

精彩评论

暂无评论...
验证码 换一张
取 消