Is it possible to inject beans to a JPA @Entity
using Spring's dependency injection?
I attempted to @Autowire ServletContext but, while the server did start successfully, I received a NullPointerException when trying to access the bean property.
@Autowired
@Transient
ServletContext servletContext;
After a long time I stumbled across this SO answer that made me think of an elegant solution:
@Autowired private AutowireCapableBeanFactory autowirer;
String beanName = fetchedEntity.getClass().getSimpleName(); autowirer.autowireBean(fetchedEntity); fetchedEntity = (FetchedEntity) autowirer.initializeBean(fetchedEntity, beanName);
Your entity will then be able to access the autowired fields as any @Component can.
You can inject dependencies into objects not managed by the Spring container using
@Configurable
as explained here: http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/aop.html#aop-atconfigurable.As you've realized by now, unless using the
@Configurable
and appropriate AspectJ weaving configuration, Spring does not inject dependencies into objects created using thenew
operator. In fact, it doesn't inject dependencies into objects unless you've retrieved them from theApplicationContext
, for the simple reason that it simply doesn't know about their existence. Even if you annotate your entity with@Component
, instantiation of that entity will still be performed by anew
operation, either by you or a framework such as Hibernate. Remember, annotations are just metadata: if no one interprets that metadata, it does not add any behaviour or have any impact on a running program.All that being said, I strongly advise against injecting a
ServletContext
into an entity. Entities are part of your domain model and should be decoupled from any delivery mechanism, such as a Servlet-based web delivery layer. How will you use that entity when it's accessed by a command-line client or something else not involving a ServletContext? You should extract the necessary data from that ServletContext and pass it through traditional method arguments to your entity. You will achieve a much better design through this approach.Yes, of course you can. You just need to make sure the entity is also registered as a Spring managed bean either declaratively using
<bean>
tags (in some spring-context.xml) or through annotations as shown below.Using annotations, you can either mark your entities with
@Component
(or a more specific stereotype@Repository
which enables automatic exception translation for DAOs and may or may not interfere with JPA).Once you've done that for your entities you need to configure their package (or some ancestor package) for being scanned by Spring so that the entities get picked up as beans and their dependencies get auto wired.
EDIT : (what finally worked and why)
Making the
ServletContext
static. (remove @Autowired)Since, JPA is creating a separate entity instance i.e. not using the Spring managed bean, it's required for the context to be shared.
Adding a @PostConstruct
init()
method.This fires
init()
once the Entity has been instantiated and by referencingServletContext
inside, it forces the injection on the static property if not injected already.Moving
@Autowired
to an instance method but setting the static field inside.Quoting my last comment below to answer why do we have to employ these shenanigans: