jBoss deployment of message-driven bean spec violation
I have an java EE application which has one message-driven bean and it runs fine on JBoss 4, however when I configure the project for JBoss 6 and deploy on it, I get this error;
WARN [org.jboss.ejb.deployers.EjbDeployer.verifier] EJB spec violation:
...
The message driven bean must declare one onMessage() method.
...
org.jboss.deployers.spi.DeploymentException: Verification of Enterprise Beans failed, see above for error messages.
But my bean HAS the onMessage method! It would not have worked on jboss 4 either then.
Why do I get this error!?
Edit:
The class in question looks like this
package ...
imports ...
public class MyMDB implements MessageDrivenBean, MessageListener {
AnotherSessionBean a;
OneMoreSessionBean b;
public MyMDB() {}
public void onMessage(Message message) {
if (message instanceof TextMessage) {
try {
//Lookup sessionBeans by jndi, create them
lookupABean();
// check message-type, then invokie
a.handle(message);
// else
b.handle(message);
} catch (SomeException e) {
//handling it
}
}
}
public void lookupABean() {
try {
// code to lookup session beans and create.
} catch (CreateException e) { // handling it and catching NamingException too }
}
}
Edit 2: And this is the jboss.xml relevant parts
<message-driven>
<ejb-name>MyMDB</ejb-name>
<destination-jndi-name>topic/A_Topic</destination-jndi-name>
<local-jndi-name>A_Topic</local-jndi-name>
<mdb-user>user</mdb-user>
<开发者_运维知识库mdb-passwd>pass</mdb-passwd>
<mdb-client-id>MyMessageBean</mdb-client-id>
<mdb-subscription-id>subid</mdb-subscription-id>
<resource-ref>
<res-ref-name>jms/TopicFactory</res-ref-name>
<jndi-name>jms/TopicFactory</jndi-name>
</resource-ref>
</message-driven>
Edit 3:
I just removed all my jars from the project, and only re-added relevant ones (from new versions also) to put out NoClassDefFound errors. Still the problem remains.
Edit: Any directions, what area should I look at? My project, or jboss-configration, or the deployment settings??
org.jboss.ejb.deployers.EjbDeployer.verifier
looks for
public void onMessage(javax.jms.Message)
via some code like this (this is from JBoss5):
/**
* Check if the given message is the onMessage() method
*/
public boolean isOnMessageMethod(Method m)
{
if ("onMessage".equals(m.getName()))
{
Class[] paramTypes = m.getParameterTypes();
if (paramTypes.length == 1)
{
if (Message.class.equals(paramTypes[0]))
return true;
}
}
return false;
}
It is important that the parameter type is javax.jms.Message
and nothing else, for example some subclass or superclass or some implementing class.
Your signature is public void onMessage(Message message)
which looks ok on first sight.
A Class
is equal only in its ClassLoader
. If for some reasons javax.jms.Message
is available in different classloaders in the same JVM, strange things can happen, depending on the ClassLoader of the EjbDeployer.verifier. Maybe the EjbDeployer.verifer has a access to javax.jms.Message
in another ClassLoader as MyMDB
. As result, both javax.jms.Message
are not equal to each other, although they are the same byte-code and literally exists. The EjbVerifier will warn about missing onMessage
, because javax.jms.Message
on ClassLoader A is not equal to javax.jms.Message
on ClassLoader B.
This can happen when libraries with javax.jms.Message
is copied on wrong places on the JBoss AS. So I guess - from a distance - that there is some jars containing javax.jms.Message
in wrong places on the JBoss or the EAR. For example some wrong jbossallclient.jar in the EAR.
Make sure your EAR does not contain its own copies of the javax.ejb
classes (or any javax
classes at all, for that matter). JBoss 4 and 6 have rather different classloading semantics, and what works on one may not work on the other. For example, if your EAR's lib
contained its own copies of Message
or MessageListener
, then it may no longer work.
I tried it out on "JBossAS [6.0.0.20100911-M5 "Neo"]" and Eclipse Helios
import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.ejb.MessageDrivenBean;
import javax.ejb.MessageDrivenContext;
import javax.jms.Message;
import javax.jms.MessageListener;
@MessageDriven(
activationConfig = { @ActivationConfigProperty(
propertyName = "destinationType", propertyValue = "javax.jms.Topic"
) },
mappedName = "topic/A_Topic",
messageListenerInterface = MessageListener.class)
public class MyMDB implements MessageListener, MessageDrivenBean {
private static final long serialVersionUID = -4923389997501209506L;
public MyMDB() {
// TODO Auto-generated constructor stub
}
@Override
public void ejbRemove() {
// TODO Auto-generated method stub
}
@Override
public void setMessageDrivenContext(MessageDrivenContext arg0) {
// TODO Auto-generated method stub
}
@Override
public void onMessage(Message message) {
// TODO Auto-generated method stub
}
}
And this setting works. Do you have the same imports for your bean (perhaps there was an automatic import gone wrong???)
精彩评论