1 2 Previous Next 27 Replies Latest reply on Sep 16, 2009 3:34 AM by timfox

    Failed to deserialize object error

    rnicholson10

      Now that I have HornetQ up and running straight away I have come to my first error!

      2009-09-11 18:11:56,357 ERROR [com.paddypower.phase.handler.bean.mdb.HandlerMDB] (Thread-4 (group:HornetQ-client-global-threads-1200672197)) javax.jms.JMSException: Failed to deserialize object
      


      Apart from the configuration changes I made in the HornetQ setup the codebase is the same as the old version that run's on JBM 1.4 (Which I can still run without errors).

      Any idea why I get this error when running with HornetQ?

      The code I use to send a message did not change at all between messaging providers.

      ...
       initialContext = new InitialContext();
       connectionFactory = (ConnectionFactory) initialContext.lookup(CONNECTION_FACTORY);
       outQueue = (Queue)initialContext.lookup(QUEUE_TO_ENGINE);
       connection = connectionFactory.createConnection();
       connection.start();
       Session session = connection.createSession(false,
       Session.AUTO_ACKNOWLEDGE);
       producer = session.createProducer(outQueue);
      
       ObjectMessage message = session.createObjectMessage();
       message.setObject(ack);
       producer.send(message);
      
      ...
      
      //close ressources
      


      Is object serialization treated differently in HornetQ?

        • 1. Re: Failed to deserialize object error
          clebert.suconic

          No.. it's not any different.

          You're using ObjectMessages... perhaps there is some classpath issue regarding classLoaders on the JCA.


          Maybe you could (as a test) add your POJO to the main classpath on JBAS.

          • 2. Re: Failed to deserialize object error
            timfox

            Yuck. What is it with everyone using ObjectMessages today? ;)

            catch (Exception e)
             {
             JMSException je = new JMSException("Failed to deserialize object");
             je.setLinkedException(e);
             throw je;
             }
            


            If you catch the exception and log out the linked exception it will tell you why it couldn't deserialize it.

            Maybe you don't have your user "Ack" class on your classpath of your receiver?

            • 3. Re: Failed to deserialize object error
              timfox

              If you can avoid ObjectMessage, it's much better.

              • 4. Re: Failed to deserialize object error
                clebert.suconic

                Anyway, there seems to be a small issue in our code.


                I just compared our activation code to the JBAS activation code.


                JBAS will call endpoint.beforeDelivery and afterDelivery when a call is being made:

                endpoint.beforeDelivery(JmsActivation.ONMESSAGE);
                
                 try
                 {
                 if (dlqHandler == null || dlqHandler.handleRedeliveredMessage(message) == false)
                 {
                 MessageListener listener = (MessageListener) endpoint;
                 listener.onMessage(message);
                 }
                 }
                 finally
                 {
                 endpoint.afterDelivery();
                
                 if (dlqHandler != null)
                 dlqHandler.messageDelivered(message);
                 }
                 }
                



                While our JCA's code will just do a plain call to onMessage:


                public void onMessage(final ClientMessage message)
                 {
                 if (trace)
                 {
                 log.trace("onMessage(" + message + ")");
                 }
                
                 TransactionDemarcationStrategy txnStrategy = strategyFactory.getStrategy();
                 try
                 {
                 txnStrategy.start();
                 }
                 catch (Throwable throwable)
                 {
                 log.warn("Unable to create transaction: " + throwable.getMessage());
                 txnStrategy = new NoTXTransactionDemarcationStrategy();
                 }
                
                 HornetQMessage msg = HornetQMessage.createMessage(message, session);
                
                 try
                 {
                 msg.doBeforeReceive();
                 message.acknowledge();
                 }
                 catch (Exception e)
                 {
                 log.error("Failed to prepare message for receipt", e);
                
                 return;
                 }
                
                 try
                 {
                 ((MessageListener) endpoint).onMessage(msg);
                 }
                 catch (Throwable t)
                 {
                 log.error("Unexpected error delivering message " + message, t);
                 txnStrategy.error();
                 }
                 finally
                 {
                 txnStrategy.end();
                 }
                 }
                



                I also looked further, and EJB3 will use that hook to set the classpath:


                protected void before(Object proxy, MessagingContainer container, Method method, Object[] args) throws Throwable
                 {
                 // Called out of sequence
                 if (oldClassLoader != null)
                 throw new IllegalStateException("Missing afterDelivery from the previous beforeDelivery for message endpoint " + getProxyString(proxy));
                
                 if (trace)
                 log.trace("MessageEndpoint " + getProxyString(proxy) + " released");
                
                 // Set the classloader
                 oldClassLoader = GetTCLAction.getContextClassLoader(inUseThread);
                 SetTCLAction.setContextClassLoader(inUseThread, container.getClassloader());
                



                This will be a problem with any other classloading operations... not just Object Serialization. So I'm opening a JIRA:

                https://jira.jboss.org/jira/browse/HORNETQ-134

                @rnicholson10: As a workaround, you could add your JAR to the main classpath. or set the context classLoader manually (as I specified on the JIRA above)




                • 5. Re: Failed to deserialize object error
                  timfox

                  I don't follow.

                  Can you explain in more detail why this is an issue?

                  • 6. Re: Failed to deserialize object error
                    clebert.suconic

                    It's simple: We are supposed to call endpoint.beforeDelivery and afterDelivery. That's part of the contract (I bet this will be on the JCA spec), and we are not doing it.

                    EJB3 needs to setup the classLoader at the client's application, and the above hook is the where this was supposed to happen.


                    We used to make that call:

                    http://viewvc.jboss.org/cgi-bin/viewvc.cgi/hornetq/trunk/src/main/org/hornetq/ra/inflow/HornetQMessageHandler.java?r1=7466&r2=7604


                    After we removed the beforeDelivery call, onMessage will have a different classLoader set on the ContextClassLoader. Any classLoader operation done at the client level could happen on a wrong classLoader.

                    • 7. Re: Failed to deserialize object error
                      clebert.suconic

                      BTW: the fix would be pretty simple... I just want to hear from Andy first (if he had any reason behind it or if he removed it by a mistake).

                      • 8. Re: Failed to deserialize object error
                        timfox

                        I remember discussing this in detail with Andy when we were working out where we had to manage transactions in the JCA adaptor.

                        Andy consulted the spec and said that calling before and end endpoint were optional - apparently we are allowed to omit the calls.

                        Now, what you're saying is that is not true. We need to consult the JCA spec to make sure.

                        • 9. Re: Failed to deserialize object error
                          clebert.suconic

                           

                          Now, what you're saying is that is not true. We need to consult the JCA spec to make sure.


                          Well... I don't know about the spec yet. All I know is what I briefly read on the EJB3 code, that the ClassLoader is set/unset through those calls.

                          I tried to look at the spec but couldn't find anything. Maybe I was looking at the wrong doc.

                          I will take a look again over the weekend.

                          • 10. Re: Failed to deserialize object error
                            timfox

                             

                            "clebert.suconic@jboss.com" wrote:

                            I tried to look at the spec but couldn't find anything. Maybe I was looking at the wrong doc.



                            I'm surprised you couldn't find anything.

                            It's the JCA 1.5 spec, easily downloadable from java.sun.com.

                            Chapter 12 goes into great detail about message inflow, and the various contracts.

                            At first glance it looks like our impl is wrong.

                            I've said this before, but *the spec needs to be studied* before writing an implementation!!

                            • 11. Re: Failed to deserialize object error
                              clebert.suconic

                              I didn't implement it... so I never read the spec.


                              On Friday, I did a very quick search, and I was looking for the wrong names... that' s why I couldn't find anything.


                              As I said I would look over the weekend, the chapter 12 states that the application server must set and reset the classloader on the before and afterDelivery, and that before and afterDelivery are considered part of a single message delivery. So it is part of the spec indeed.

                              • 12. Re: Failed to deserialize object error
                                clebert.suconic

                                Actually, I did read it before.. but JCA is something that I could never digest before.

                                But now after I read Jesper's and Andy's implementation it's easier to digest it.

                                • 13. Re: Failed to deserialize object error
                                  rnicholson10

                                  Clebert, thanks for the workaround.

                                  It has already let me test performance on HQ with our current system and I have to say I'm, hugely impressed. Configuration is a easy compared to JBM 1.4, the documentation is well written and easy to follow and the examples invaluable.

                                  Well done to everyone involved!

                                  • 14. Re: Failed to deserialize object error
                                    timfox

                                     

                                    "clebert.suconic@jboss.com" wrote:
                                    Actually, I did read it before.. but JCA is something that I could never digest before.


                                    Yes, it's not fun reading the JCA spec ;)

                                    1 2 Previous Next