Why is PostConstruct not called?
Asked Answered
I

10

38

I am working on a simple Java EE application.

I have class like this:

import javax.annotation.PostConstruct;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

@Stateless
public class BlogEntryDao {

    EntityManager em;

    @PostConstruct
    public void initialize(){
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("Persistence");
        em = emf.createEntityManager();
    }

    public void addNewEntry(){
        Blogentry blogentry = new Blogentry();
        
        blogentry.setTitle("Test");
        blogentry.setContent("asdfasfas");

        em.persist(blogentry);

    }
}

So my managed bean calls this method. Until here no problems. But since the initialize method is not called, I am getting an NPE in em.persist.

Why is the initialize method not being called? I am running this on Glassfish server.

Ike answered 10/8, 2013 at 12:4 Comment(5)
For starters, you shouldn't be opening your EntityManager in a global scope; the EntityManager roughly corresponds to a session. If you really need to handle your own session management (injecting @PersistenceContext is better), you should be creating and closing an EntityManager in each call to addNewEntry.Lionfish
Have you confirmed that your container is treating the object as something requiring dependency injection? Not every object gets hooked into, and if you're just calling new BlogEntryDao() somewhere, the container may not know to initialize it as a bean.Lionfish
@chrylis Yeah thanks, I am calling new BlogEntryDao actually.Ike
@chrylis Thanks, changing it to EJB BlogEntryDao fixed it. Can you please proivde an answer so I can accept it?Ike
I think you can define init-method="initialize" in the bean configuration file.Revkah
L
29

The Java EE bean annotations such as @PostConstruct only apply to container-managed beans. If you are simply calling new BlogEntryDao yourself, the container isn't going to intercept the creation and call the @PostConstruct method.

(Furthermore, you'd be better off using @PersistenceContext or @PersistenceUnit instead of manually fetching the EntityManagerFactory in your initialize() method, and you should be creating an EntityManager for each call to addNewEntry(), since they're short-lived. Making these changes would eliminate the need for initialize() at all.)

Lionfish answered 10/8, 2013 at 12:18 Comment(0)
D
19

Since this question comes up first on Google for "postconstruct not called", another reason a @PostConstruct method might not be called besides using the new keyword instead of putting @PostConstruct in a Spring bean is if you have a circular dependency.

If this bean were to depend on another bean that depended on this bean, your other bean might call addNewEntry() before BlogEntryDao was initialized, even though BlogEntryDao is a dependency for that other bean.

This is because Spring didn't know which bean you wanted to load first due to the circular reference. In this case, one can remove the circular reference or use @AutoWired/@Value constructor parameters instead of member values or setters, or if using xml configuration, maybe you can swap the order in which the beans are defined.

Dithyramb answered 9/12, 2014 at 2:46 Comment(0)
H
19

I had the same problem in my application. You didn't post your bean context configuration xml file (so I'm not sure if it's the same issue) but in my case adding this line:

<context:annotation-config/>

Solved my problem. You need either <context:annotation-config/> or <context:component-scan/> to enable @PostConstruct annotation.

Hedy answered 30/10, 2015 at 17:8 Comment(1)
Note: this is correct for Spring applications but the question was about general JavaEE applications.Mommy
H
7

In my case @PostConstruct was not called because my initialize() method was static and was also throwing an exception. In either case the method is ignored. I hope it helps someone else who made the same mistake. This can be found in the console:

WARNING: JSF1044: Method '<XXX>' marked with the 'javax.annotation.PostConstruct' annotation cannot be static.  This method will be ignored.
WARNING: JSF1047: Method '<XXX>' marked with the 'javax.annotation.PostConstruct' annotation cannot declare any checked exceptions.  This method will be ignored.
Hanuman answered 12/12, 2016 at 16:49 Comment(0)
K
5

When using Spring make sure you are using the right PostConstruct annotation from the right package.

javax.annotation.PostConstruct

should be the one. Not for example:

jakarta.annotation.PostConstruct

It took me a little while to figure out why only one of my PostConstruct didn't work.

Kinnikinnick answered 6/2, 2021 at 15:22 Comment(1)
Both packages are valid, but it depends on the spring version. Refer baeldung.com/… for more details. Spring documentation reference docs.spring.io/spring-framework/reference/core/beans/…Undercarriage
F
2

In my case @PostConstruct method was not called because I was referencing to a public instance variable of the spring service bean directly in other service beans (ie myService.myProperty). When i made a public getter method for the property (ie getMyProperty()) and used that to get the property the @PostConstruct method was called again. Also I made myProperty private to prevent any accidental direct referencing in the future.

Also note that if you don't explicitly register the class with @Bean in a @Configuration annotated class and rely soley on @Autowired instead, the @PostConstruct method may not be executed immediately on startup. Only when one of the methods of the autowired class are referenced and called by another class will that class be loaded and only at that time will the @PostConstruct method be called. In other words, by only using @Autowired you are essentially lazy loading a class. If you want to load it at startup, register it with @Bean

Heres a good SO thread about the difference between @Bean and @Autowired Difference between @Bean and @Autowired

EDIT: One last remark. When you have a webapplication and decided to annotate your class with @RequestScope then the @Postconstruct annotated method will be called each time when a new request comes in. This is because @RequestScope instructs spring to create a new instance of the class every time a new request comes in. If you want all requests to use the same instance, then you could use @Bean as mentioned above, but you could also use the annotation @Singleton above your class. This will cause the class to be loaded eagerly upon startup.

Frustrated answered 13/8, 2020 at 14:53 Comment(0)
A
2

In my case I had two instances of javax.annotation.PostConstruct inside classpath. One was bundled with the war package and another was provided by tomcat. When Spring is scanning for the @PostConstruct annotation it compares these two different instances. Therefore the @PostConstruct annotated method was not picked while scanning.

Providing only one instance of javax.annotation-api library solved the issue.

Antonomasia answered 11/2, 2021 at 18:31 Comment(2)
How one can do that? How to provide only one instance of the library?Germen
for me, i had a multi-module project and the module containing the main function was scanning another module and the pom of both modules had this dependency, removing the dependency from pom containing the main function (since it was not using postconstruct) corrected the problemFayfayal
B
1

Make sure the class having @Postconstruct method lies within the same package. I moved class file to main package and it worked.

Bouncy answered 16/11, 2020 at 4:1 Comment(1)
Package of the class should not matter. My suspicion is that in your case the build scripts were instructed to pack classes from certain packages and exclude classes from some others which is why the exact package affected whether it worked or not. You might want to check for this and edit your answer.Contact
P
1

Since most of the ways are already mentioned. However one can also create a bean in the config file for the class

org.springframework.context.annotation.CommonAnnotationBeanPostProcessor

;

This will enable PostConstruct and PreDestroy annotations.

<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor"></bean>

Also for Predestroy one needs to call context.registerShutDownHook()

Prowel answered 27/8, 2021 at 21:29 Comment(0)
C
1

Adding my own case to the list of possible reasons: I had worked the code using Eclipse half-automatic refactoring tools and as a result my @PostConstruct method had become one that had a parameter and thus was never called.

The parameter list of the method must be compatible with @PostConstruct for it to work. Empty list is the one that works for certain.

Contact answered 19/7 at 16:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.