3

I want to write my own JPA entity listener which will perform some actions before an entity will be created/updated/deleted:

public class MyEntityListener {

    @PrePersist
    public void beforeCreate(Object entity) {
        ...
    }

    @PreUpdate
    public void beforeUpdate(Object entity) {
        ...
    }

    @PreRemove
    public void beforeDelete(Object entity) {
        ...
    }

}

But I also need a Spring-managed bean instance to perform such actions:

public class MyEntityListener {

    @PrePersist
    public void beforeCreate(Object entity) {
        someSpringManagedBean.doSomething("Creating an entity: " + entity);
    }

    ...

}

I know that there are problems with injecting Spring-managed beans into JPA entity listeners (Injecting a Spring dependency into a JPA EntityListener), so this code will not work:

@Component
public class MyEntityListener {

    @Autowired
    private SomeSpringManagedBean someSpringManagedBean;

    ....

}

But I have found that Spring's AuditingEntityListener uses a plain setter (but also @Configurable and ObjectFactory) for the same purpose:

@Configurable
public class AuditingEntityListener {

    private ObjectFactory<AuditingHandler> handler;

    public void setAuditingHandler(ObjectFactory<AuditingHandler> auditingHandler) {
        ...
        this.handler = auditingHandler;
    }

    @PrePersist
    public void touchForCreate(Object target) {
        if (handler != null) {
            handler.getObject().markCreated(target);
        }
    }

    @PreUpdate
    public void touchForUpdate(Object target) {
        if (handler != null) {
            handler.getObject().markModified(target);
        }
    }

    ...

}

AuditingHandler is a Spring-managed bean (I have tried to inject it in my own Spring-managed bean and it works fine). Looks like Spring is able to provide it to its own JPA entity listener somehow.
I want to do the same, but with my own JPA entity listener and a Spring-managed bean.
I know that it is possible to store a reference to an ApplicationContext in a static variable so I can use it to obtain the required Spring-managed bean:

@Component
public class SomeClass implements ApplicationContextAware {

    public static ApplicationContext applicationContext;

    public void setApplicationContext(ApplicationContext applicationContext) {
        SomeClass.applicationContext = applicationContext;
    }

}

public class MyEntityListener {

    @PrePersist
    public void beforeCreate(Object entity) {
        SomeClass.applicationContext.getBean(SomeSpringManagedBean.class)
                .doSomething("Creating an entity: " + entity);
    }

    ...

}

But this solution looks very ugly for me. I think there is a better solution for this.

Community
  • 1
  • 1
Viktor
  • 1,298
  • 15
  • 28
  • Dang, I've done this about 5-6 years ago as a POC, but I don't have the code on this computer. If my memory serves me right, You need to use spring+AOP to rewrite classes at compilation time, so every time you or Hibernate do a `new` of the class, spring automatically autowires the dependencies. As I mentioned, it was a POC, as in the end, it looked quite hacky and it's something that could have been easily bastardized and miss used. – Augusto Aug 03 '16 at 15:41

0 Answers0