Skip to main content

AutoWiring Spring Beans Into Classes Not Managed By Spring Like JPA Entity Listeners

In my previous article JPA Auditing: Persisting Audit Logs Automatically using EntityListeners, I have discussed how we can use Spring Data JPA automate Auditing and automatically create audit logs or history records and update CreatedBy, CreatedDate, LastModifiedBy, LastModifiedDate properties.

So in order to save history records for our File entity, we were trying to auto-wire EntityManager inside our FileEntityListener class and we have come to know that we can not do this.

We can not inject any Spring-managed bean in the EntityListener because EntityListeners are instantiated by JPA before Spring inject anything into it. EntityListeners are not managed Spring so Spring cannot inject any Spring-managed bean e.g. EntityManager in the EntityListeners.

And this case is not just with EntityListeners, you can not auto wire any Spring-managed bean into another class (i.e. utility classes) which is not managed by Spring.

Because it is a very common problem and can also arise with other classes so I tried to come out with a common solution which will not just solve this problem but will also help us getting Spring managed beans in other places.

AutoWiring-Spring-Beans-Into-Classes-Not-Managed-By-Spring-Like-JPA-Entity-Listeners

So I have created one utility class to fetch any bean according to our requirement.

@Service
public class BeanUtil implements ApplicationContextAware {

private static ApplicationContext context;

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}

public static <T> T getBean(Class<T> beanClass) {
return context.getBean(beanClass);
}

}

Now to get any a bean in class we will just need call the BeanUtil.getBean(YourClass.class) and pass the class type to it and we will get the bean.

For Example in our case, we were trying to get the EntityManager bean inside FileEntityListener, we can simply do it by writing BeanUtil.getBean(EntityManager.class).

public class FileEntityListener {

private void perform(File target, Action action) {
EntityManager entityManager = BeanUtil.getBean(EntityManager.class);
entityManager.persist(new FileHistory(target, action));
}

}

You can find complete code on this Github Repository and please feel free to provide your valuable feedback.

Comments

  1. hello, I've tried this and got an NullPointerException for the ApplicationContext object (the static one).

    ReplyDelete
    Replies
    1. Hi Agustinus, you should not get any problems in it.
      However you find the complete code on https://github.com/njnareshjoshi/articles/tree/master/spring-data-jpa-auditing

      Delete
  2. In class BeanUtil the context has to be set first otherwise the npe would be thrown when getBean method is invoked. I assume this is the problem that Agustinus has. In your repo I have not found the place where you provide this context to the utility class.

    ReplyDelete
    Replies
    1. `BeanUtil` class is implementing `ApplicationContextAware` and overriding `setApplicationContext` method which automatically get called and set the applicationContext in the `BeanUtil`. I have executed the repo's code and it working fine, please tell me if you are getting the problem while executing it.

      Delete
  3. For the Multi module spring boot projects where beanUtil class should be place?

    ReplyDelete
    Replies
    1. It depends on the project architecture and from where you want access this code. If you want to access it from multiple modules then BeanUtil class should be in a module which is visible from other modules. Some kind of core module which other module can access.

      Delete
    2. I am getting RuntimeException
      No EntityManager with actual transaction available for current thread
      do you have any idea why?

      Delete

Post a Comment

Popular posts from this blog

Java Cloning - Copy Constructor versus Cloning

In my previous article Java Cloning and Types of Cloning (Shallow and Deep) in Details with Example , I have discussed Java Cloning in details and answered questions about how we can use cloning to copy objects in Java, what are two different types of cloning (Shallow & Deep) and how we can implement both of them, if you haven’t read it please go ahead. In order to implement cloning, we need configure our classes to follow below steps Implement Cloneable interface in our class or its superclass or interface, Define clone() method which should handle CloneNotSupportedException (either throw or log), And in most cases from our clone() method we call the clone() method of the superclass. And super.clone() will call its super.clone() and chain will continue until call will reach to clone() method of the Object class which will create a field by field mem copy of our object and return it back. Like everything Cloning also comes with its advantages and disadvantages. However, Java c...

Creating objects through Reflection in Java with Example

In Java, we generally create objects using the new keyword or we use some DI framework e.g. Spring to create an object which internally use Java Reflection API to do so. In this Article, we are going to study the reflective ways to create objects. There are two methods present in Reflection API which we can use to create objects Class.newInstance() → Inside java.lang package Constructor.newInstance() → Inside java.lang.reflect package However there are total 5 ways create objects in Java, if you are not aware of them please go through this article 5 Different ways to create objects in Java with Example . Both Class.newInstance() and java.lang.reflect.Constructor.newInstance() are known as reflective methods because these two uses reflection API to create the object. Both are not static and we can call earlier one on a class level object while latter one needs constructor level object which we can get by using the class level object. Class.newInstance() The Class class is th...

Everything About Method Overloading Vs Method Overriding

In a previous article  Everything About ClassNotFoundException Vs NoClassDefFoundError , I have explained ClassNotFoundException and NoClassDefFoundError in details and also discussed their differences and how to avoid them. If you have not read it, please go ahead and give it a look. Similar to that here in this article, we will look into one more core concept of Java which is method overloading and overriding. As soon as we start learning Java we get introduced to them and their contracts which are pretty simple to understand but sometimes programmers get confused between them or they do not know either it is a correct overload/override because of the different rules. Here we will discuss What is method overloading and overriding, What contract one must follow to correctly overload or override a method, What are the different rules of method overloading and overriding and what are the differences between them. Method Overloading Method overloading means providing t...