Announcement Announcement Module
Collapse
No announcement yet.
ClassCastException with getBean() object after re-deploy Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • ClassCastException with getBean() object after re-deploy

    I'm utilizing the Business Methods Interface pattern and Spring for implementing EJBs in my project. I built an example application that utilizes the pattern and have an interesting problem.

    I'm running JBOSS 3.2.6 with Spring 1.1.1 and have my ear in the deploy directory and start JBOSS. The application executes correctly. Whenever I re-deploy (even without making code changes), I start getting a java.lang.ClassCastException in my onEjbCreate() method of my EJB. The offending line is:

    Code:
     _businessMethods = (BusinessMethods) getBeanFactory().getBean("businessMethodsImpl");
    Here's my EJB:

    Code:
    
    package com.mantechwva.examplej2ee.statelessejb;
    
    
    import javax.ejb.EJBException;
    
    import javax.ejb.CreateException;
    import javax.ejb.SessionContext;
    import org.springframework.ejb.support.*;
    import org.springframework.context.access.*;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    
    /**
     * @ejb.bean name="BusinessMethods"
     *           display-name="Name for Session Bean"
     *           description="Description for Session Bean"
     * 			 local-business-interface="BusinessMethods"
     *           jndi-name="BusinessMethodsSLSB"
     *           type="Stateless"
     *           view-type="both"
     * @ejb.home extends="javax.ejb.EJBHome"
     *           local-extends="javax.ejb.EJBLocalHome"
     * @ejb.interface extends="javax.ejb.EJBObject"
     *           local-extends="javax.ejb.EJBLocalObject"
     *           remote-class = "com.mantechwva.examplej2ee.statelessejb.BusinessMethodsRemote"
     */
    
    public class BusinessMethodsBean extends AbstractStatelessSessionBean implements BusinessMethods { 
    
    	BusinessMethods _businessMethods;
    	
    	/** Logger for this class and subclasses */
        protected final Log logger = LogFactory.getLog(getClass());
    	
    	public BusinessMethodsBean() {
    		super();
    		
    	}
    	
    	
    	
    	/**
    	 * Business method
    	 * @ejb.interface-method  view-type = "both"
    	 */
    	public String helloWorld() {
    		
    		return _businessMethods.helloWorld();
    		
    	}
    
    	/**
    	 * Business method
    	 * @ejb.interface-method  view-type = "both"
    	 */
    	public String goodbyeWorld() {
    		return _businessMethods.goodbyeWorld();
    		
    
    	}
    	
    
    	/* (non-Javadoc)
    	 * @see javax.ejb.SessionBean#setSessionContext(javax.ejb.SessionContext)
    	 */
    	public void setSessionContext(SessionContext sessionContext)
    		throws EJBException {
    		
    		super.setSessionContext(sessionContext);
    		setBeanFactoryLocator(ContextSingletonBeanFactoryLocator.getInstance());
    		setBeanFactoryLocatorKey("ejbAC");	
    		
    
    
    	}
    
    	/* (non-Javadoc)
    	 * @see javax.ejb.SessionBean#ejbRemove()
    	 */
    	public void ejbRemove() throws EJBException {
    		// TODO : what if anything goes here?
    	}
    	
    	/*
    	 * Must have the following method because XDoclet is stupid in some ways 
    	 * and will create its own, causing the application context to not be loaded.
    	 */
    	public void ejbCreate() throws CreateException {
    		super.ejbCreate();
    	}
    	
    	
    	
    	/* (non-Javadoc)
    	 * @see org.springframework.ejb.support.AbstractStatelessSessionBean#onEjbCreate()
    	 */
    	protected void onEjbCreate() throws CreateException {
    		
    		_businessMethods = (BusinessMethods) getBeanFactory().getBean("businessMethodsImpl");
    					
    	}
    
    }
    My beanRefContext.xml is:

    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http&#58;//www.springframework.org/dtd/spring-beans.dtd">
    
    <!--
      - Application context definition for EJBs.
      -->
    
    <beans>
      
    <bean id="ejbAC" 
    	class="org.springframework.context.support.ClassPathXmlApplicationContext">
    <constructor-arg>
    <list>
    <value>com/mantechwva/examplej2ee/statelessejb/config/ejbApplicationContext.xml</value>
    </list>
    </constructor-arg>
    </bean>
    
    </beans>
    My ejbApplicationContext.xml is:

    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http&#58;//www.springframework.org/dtd/spring-beans.dtd">
    
    <!--
      - Application context definition for EJBs.
      -->
    
    <beans>
    <!--  Link to EJB Implementation -->
    
    	
    <bean id="businessMethodsImpl" class="com.mantechwva.examplej2ee.statelessejb.BusinessMethodsImpl">
           
             </bean> 
     
    </beans>
    As far as I can see, it looks like I have everything set up correctly. And, the fact that it works correctly until I redeploy makes me think that it is some kind of bug in spring or have something to do with spring caching the class and it's surviving over redeploys.

    Has anyone seen this before or see that I have something incorrect?

    thanks,

    -Darell

  • #2
    For sure this is a ClassLoader issue. JBoss is apparently holding on to something when you redeploy.

    JBoss's universal classloader is somewhat of an unpredictable beast. It will behave differently as you start moving things around (EJBs, jars loaded via the application manifest, etc.). I successfully used a spring-based j2ee app (EAR) with JBoss 3.2.3-3.25. This app used a shared service layer application context, which was a parent to 3 different web-app applicaiton contexts. The EJBs eventually all went away, but before they did, they were in the shared service layer context. In this app, almost all dependencies were loaded at the j2ee app. The ear's application.xml file refered to one jar which was there to force loading of all the other libs, via entries in its manifest file.

    This worked fine, although I had about a one month period when at work (but not at home, even with the same config), I was getting some errors fairly similar to yours on redepoyment, then it started working again.

    You need to look at how you are doing classloading for the whole EAR file, and why JBoss could possibly be holding onto classes. This is in no way a Spring issue, given that Spring should be completely unloaded and reloaded with the ear. But JBoss is holding on the some of the EJB classes in your case...

    Comment


    • #3
      BTW, is there a trick to avoid writing the business interface twice? In your example, what are the relationships between BusinessMethods and BusinessMethodsRemote?

      I consider adding RemoteException to all methods in my business interfaces. I don't want to have to maintain two interfaces for a single functionality.

      Thanks for any answer,
      Baptiste

      Comment


      • #4
        Originally posted by baptiste
        BTW, is there a trick to avoid writing the business interface twice? In your example, what are the relationships between BusinessMethods and BusinessMethodsRemote?

        I consider adding RemoteException to all methods in my business interfaces. I don't want to have to maintain two interfaces for a single functionality.

        Thanks for any answer,
        Baptiste
        If you're using the Spring session bean proxies to access local or remote session beans, you can get by with just having a business interface which doesn't throw RemoteException. That is because if the remote stub doesn't implement the business interface, Spring will automatically try to call a similarly named and argumented method on the stub anyways, via reflection. Very convenient.

        Colin

        Comment


        • #5
          Thanks for your answer. The remaining problem is that all methods of a Session Bean remote interface must throw RemoteException. So you still have to write XXXInterface AND XXXInterfaceRemote, whose methods are the same but throw RemoteException in the second case. That's what I'd like to avoid.

          Something else: I have tried using XDoclet with a SLSB similar to the one above and ejbdoclet doesn't detect my bean correctly if I derive it from AbstractStatelessSessionBean. If I classically write it as implementing the SessionBean interface, it works fine. My build.xml is as follows:

          Code:
          <ejbdoclet ejbSpec="2.0" excludedTags="@version,@author,@todo" destDir="$&#123;src.java.dir&#125;" verbose="true" ddedTags="@xdoclet-generated at $&#123;TODAY&#125;">
          	<fileset dir="$&#123;src.java.dir&#125;">
          		<include name="**/*.java" />
          	</fileset>
          	<remoteinterface/>
          	<localinterface/>
          	<homeInterface/>
          	<session/>
          	<dao/>
          	<deploymentdescriptor validateXML="true" destDir="$&#123;src.xml.dir&#125;" />
          </ejbdoclet>
          Any clues?

          Baptiste

          Comment


          • #6
            XDoclet is brain dead. Take a look at the comments in this ejb impl class. It doesn't actually use XDoclet, but is written such that it will work with XDoclet:

            http://cvs.sourceforge.net/viewcvs.p...va?view=markup

            As for the remote int, yes, you're going to have to have it with the same methods throwing RemoteException (and itobviously can not derive from the businss interface because of that, if the biz int is not going to throw them).

            But at least your actual business interface and your clients don't have to know anything about RemoteException.

            Comment


            • #7
              OK fine, I just found out by myself that my bean needs to implement SessionBean interface even if it derives from the Spring abstract class.

              I'm gonna start from the CVS example and work it out.

              Thanks for your precious help in setting me on the right track.

              Baptiste

              Comment

              Working...
              X