Wednesday, June 27, 2007

JDK 1.6 + JBoss 4.2.0 + EJB3 Web Service + Axis2

Few days ago I started to implement web service in current project.I exposed a few methods in existing EJB.The deployment of WS to JBoss server and generating WS client using Axis2 are ok.But when the client trying to invoke the WS at server,exception was thrown at server side.

java.lang.UnsupportedOperationException: setProperty must be overridden by all subclasses of SOAPMessage
at javax.xml.soap.SOAPMessage.setProperty(SOAPMessage.java:424)
at org.jboss.ws.soap.SOAPMessageImpl.(SOAPMessageImpl.java:65)
at org.jboss.ws.soap.MessageFactoryImpl.createMessage(MessageFactoryImpl.java:115)
at org.jboss.ws.binding.soap.SOAP11BindingProvider.createMessage(SOAP11BindingProvider.java:59)
at org.jboss.ws.binding.soap.SOAPBindingProvider.bindRequestMessage(SOAPBindingProvider.java:89)
at org.jboss.ws.binding.soap.SOAP11BindingProvider.bindRequestMessage(SOAP11BindingProvider.java:65)
at org.jboss.ws.jaxrpc.CallImpl.invokeInternal(CallImpl.java:645)
at org.jboss.ws.jaxrpc.CallImpl.invoke(CallImpl.java:404)
...

Same problem was reported at JBossWS Jira .click here

After I googling,I found that this problem only arise when we use JDK 6. I tried to switch back to JDK5,and it works. Then I tried various methods, such as trying to deploy on JBoss 5.0 beta yet it still doesn't work. According to some forumers, the reason for this is the SAAJ classes being used in Sun JDK 1.6.0 are not compatible with JBossWS since they use their own SAAJ jar named jboss-saaj.jar. So,we will need to make sure that jboss-saaj is loaded before default one.

The solution to this is modifying JBoss lib folder structure.
1.Move all the jar file from ${JBOSS_HOME}/lib into ${JBOSS_HOME}/lib/endorsed except getopt.jar, jboss-system.jar, jboss-jmx.jar
2.Make sure the jboss-saaj.jar and jboss-jaxrpc.jar is in it.

It works for me after I modified the structure. :)

Wednesday, June 20, 2007

Strange Generic Problem

Today my colleague asked me a question about generic in Java.
Here's the code

package test;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class TestGeneric {
public static void main(String[] args)throws Exception{
List list = new ArrayList();
list.add("test");
List newList = list;
newList.add(4);
System.out.println(list.get(1));

List list2 = new ArrayList();
list2.add(new Date());
List newList2 = list2;
newList2.add("test");
System.out.println(list2.get(0));
}
}

And an exception was thrown when executing it.
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
at test.TestGeneric.main(TestGeneric.java:13)


But if I commented out line 13,it works.The thing is quite weird as if the type casting rule is applied list,why doesn't it applied on list2?Obviously,we put an integer into a list which is expecting Date object,and when we print it,it wasn't cast to Data object.Then I decompiled the class file and this is what i get.

package test;

import java.io.PrintStream;
import java.util.*;

public class TestGeneric
{

public TestGeneric()
{
}

public static void main(String args[])
throws Exception
{
List list = new ArrayList();
list.add("test");
List newList = list;
newList.add(Integer.valueOf(4));
System.out.println((String)list.get(1));
List list2 = new ArrayList();
list2.add(new Date());
List newList2 = list2;
newList2.add("test");
System.out.println(list2.get(0));
}
}

We look at line "System.out.println((String)list.get(1));" ,value in list was typecast to String object,where as "System.out.println(list2.get(0));" the value in list2 wasn't typecast to Date object.

Any idea?