Announcement Announcement Module
Collapse
No announcement yet.
No transaction in transactional service called from @PostConstruct Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • #16
    PostInitialize in Web environment

    when using the PostInitialize in spring-enabled web environment, an error occurs where a call is made to:
    Code:
    Map beans = applicationContext.getBeansOfType(Object.class);
    due to the existence of beans annotated with @Scope("request")

    the error says that the bean cannot be created outside the context of a request. same behavior should be expected with session-bound beans. Therefore, the solution, although restricting the PostInitialize to singletons only, is change the line above to:

    Code:
    Map beans = applicationContext.getBeansOfType(Object.class, false, true);
    (attached updated patch)

    Comment


    • #17
      Yep, we are talking about pre-created singletons only. Any non-singletons are not created on bootstrap so for them the problem @PostInitialize solving does not exist. That's the correct behavior.

      What do say about posting some Jira with the patch? I want our code in Spring codebase :-)

      Comment


      • #18
        sure,
        I'll need some time to get to it, though.

        Comment


        • #19
          Done. http://jira.springframework.org/browse/SPR-5966

          Comment


          • #20
            good of you!

            Comment


            • #21
              Hi

              I came across this thread after battling with the same problem of trying to run a transaction in a @PostConstruct method. I managed to get a transaction to run if I annotated the Interface method of the service I am calling from within the PostConstruct method instead of the concrete class.

              Jon

              Comment


              • #22
                Probably it depends on your bean, because as you saw, there is no guarantee the annotations processing beans are already loaded when your @PostConstruct method is called. I still think you'd better still use the @PostInitialzer.
                Last edited by jbaruch; Oct 15th, 2009, 10:39 AM.

                Comment


                • #23
                  I don't know if you support your code from 2008, or maybe someone else has a better solution for spring 3.x ? I successfully used the @PostConstruct annotation but now, it doen't work anymore. I debugged the code and noticed, that the annotation finder iterates over the current class which is a Proxy instance and all superclasses (which is the Proxy superclass). So it will never ever see the actual annotation in the service class.

                  I thought about moving the @PostConstruct to the interface and change the Annotation scanner accordingly. But maybe someone else comes up with a much better Solution?

                  Thanks,

                  Jan

                  Comment


                  • #24
                    You mean you used the @PostInitialize and it doesn't work in Spring 3.x?

                    Comment


                    • #25
                      Yes I used it already in 3.0.x and it worked but iin the last days I tried to update to 3.0.1 and back to 3.0.0 and now I doesn't work any more. And I don't know why it worked before. It couldn't. I think spring beans have always been instances of Proxy, correct? So scanning the subclasses, only cannot work.


                      I did the following fix in order to scan Interfaces, too:
                      Code:
                          private <T extends Annotation> T getAnnotation(final Method method, Class<T> annotationClass) {
                          	Method classmethod = method;
                          	do {
                      	    	if(classmethod.isAnnotationPresent(annotationClass)) {
                      	    		return classmethod.getAnnotation(annotationClass);
                      	    	}
                          	}
                          	while ((classmethod = getSuperMethod(classmethod)) != null);
                          	
                          	/* scan interfaces */
                          	Class<?>[] interfaces = method.getDeclaringClass().getInterfaces();
                          	for (Class<?> class1 : interfaces) {
                          		try {
                          			Method interfacemethod = class1.getMethod(method.getName(), method.getParameterTypes());
                          			if(interfacemethod.isAnnotationPresent(annotationClass)) {
                          	    		return interfacemethod.getAnnotation(annotationClass);
                          	    	}
                          		} catch (NoSuchMethodException e) {
                          			
                          		}
                      		}
                          	return null;
                      	}
                      Cheers,

                      Jan

                      Comment


                      • #26
                        The instances aren't always proxies, it depends on their scope and the declared aspects (transaction annotations, custom AspectJ aspects, etc).
                        The scanning of interfaces is correct, but org.springframework.util.ClassUtils.getAllInterfac esForClass(Class<?> clazz) should be used to include ones implemented by superclasses.

                        Cheers,
                        Baruch.

                        Comment


                        • #27
                          Originally posted by jbaruch View Post
                          The instances aren't always proxies, it depends on their scope and the declared aspects (transaction annotations, custom AspectJ aspects, etc).
                          The scanning of interfaces is correct, but org.springframework.util.ClassUtils.getAllInterfac esForClass(Class<?> clazz) should be used to include ones implemented by superclasses.
                          We seem to have a similar issue and although it was great to happen to come across the @PostInitialize solution it doesn't work for us... Spring 2.5.6-SEC01, GlassFish v3 Final, Java 1.6.0... .

                          The odd thing is that in an earlier more constrained example it seemed to work. This is the code we have and all beans are getting constructed fine its just that the initService is not getting called...

                          Any ideas???? Thanks You!


                          @Service("modalityService")
                          public class ModalityServiceImpl implements ModalityService {

                          @Autowired
                          private ModalityDao modalityDao;

                          private ModalityCache modalityCache;

                          @PostInitialize
                          public void initService() {
                          List<Modality> modalityList = this.modalityDao.findAll();
                          this.modalityCache = new ModalityCache();
                          this.modalityCache.init(modalityList);
                          }
                          }

                          Comment


                          • #28
                            I decided to try the following code and clearly the @PostConstruct gets executed while the @PostInitialize does not... which at least implies that there are no issues in the code outside the @PostInitialize (for some reason).

                            However we can't use the @PostConstruct as the modalityDao bean is not fully available for executing a JPA call on it... hence why we REALLY need @PostInitialize... (very similar reasons to @Transactional not working).

                            I can't imagine that the issue would be difficult to solve???

                            Thanks in Advance!

                            @Service("modalityService")
                            public class ModalityServiceImpl implements ModalityService {

                            @Autowired
                            private ModalityDao modalityDao;

                            private ModalityCache modalityCache;

                            @PostConstruct
                            public void initService2() {
                            System.out.println("****************************** ************************************************") ;
                            }

                            @PostInitialize
                            public void initService() {
                            System.out.println("//////////////////////////////////////////////////////////////////////////////");
                            List<Modality> modalityList = this.modalityDao.findAll();
                            this.modalityCache = new ModalityCache();
                            this.modalityCache.init(modalityList);
                            }

                            Comment


                            • #29
                              Once I added the following to ApplicationContext.xml it worked :-)

                              <!-- Following registers PostInitializerRunner so that @PostInitialize will work -->
                              <bean id="postInitializer" class="org.lightagents.ws.annotation.PostInitializ erRunner" />

                              Comment


                              • #30
                                Yap, the runner is annotated with @Component, so it should be picked automatically if you use <context:component-scan/>, but if you don't use it, you must declare the runner in your beans xml.

                                Comment

                                Working...
                                X