PowerMock with Jersey, InternalServerErrorException error - rest

We have a gradle Jersey project and we're trying to use PowerMock and EasyMock (and JUnit) for the unit tests because we have several static methods we need to mock. We finally got PowerMock working with Jersey (see this question), but PowerMock will only allow our REST calls to return Strings. All other return types--like Lists, for example--result in an InternalServerErrorException. Full stack trace:
javax.ws.rs.InternalServerErrorException: HTTP 500 Internal Server Error
at org.glassfish.jersey.client.JerseyInvocation.convertToException(JerseyInvocation.java:1020)
at org.glassfish.jersey.client.JerseyInvocation.translate(JerseyInvocation.java:877)
at org.glassfish.jersey.client.JerseyInvocation.access$800(JerseyInvocation.java:92)
at org.glassfish.jersey.client.JerseyInvocation$3.call(JerseyInvocation.java:722)
at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
at org.glassfish.jersey.internal.Errors.process(Errors.java:228)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:444)
at org.glassfish.jersey.client.JerseyInvocation.invoke(JerseyInvocation.java:718)
at org.glassfish.jersey.client.JerseyInvocation$Builder.method(JerseyInvocation.java:430)
at org.glassfish.jersey.client.JerseyInvocation$Builder.get(JerseyInvocation.java:321)
at com.company.project.sm.rest.PowerMockTest.aListTest(PowerMockTest.java:104)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:68)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:326)
at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:89)
at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:97)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:310)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTestInSuper(PowerMockJUnit47RunnerDelegateImpl.java:131)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.access$100(PowerMockJUnit47RunnerDelegateImpl.java:59)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner$TestExecutorStatement.evaluate(PowerMockJUnit47RunnerDelegateImpl.java:147)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.evaluateStatement(PowerMockJUnit47RunnerDelegateImpl.java:107)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTest(PowerMockJUnit47RunnerDelegateImpl.java:82)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:298)
at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:87)
at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:50)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:218)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:160)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:134)
at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:34)
at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:44)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:136)
at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:121)
at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:57)
at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:59)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:538)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:760)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:206)
The REST calls in the unit tests work without PowerMock; they fail when run with PowerMock. We can't spot what we're doing wrong.
Here are examples of our unit tests (entire class):
// comment-out these two lines to turn off PowerMock
#org.powermock.core.classloader.annotations.PowerMockIgnore({"javax.ws.*", "org.glassfish.*"})
#RunWith(PowerMockRunner.class)
public class PowerMockTest {
private JerseyTest jerseyTest;
#Before
public void setUp() throws Exception {
this.jerseyTest = new JerseyTest() {
#Override
protected Application configure() {
return PowerMockTest.this.configure();
}
};
this.jerseyTest.setUp();
}
#After
public void tearDown() throws Exception {
this.jerseyTest.tearDown();
}
public ResourceConfig configure() {
return new ResourceConfig(PowerMockTestResource.class);
}
#Test
public void thisTestWorks() {
String fooString = this.jerseyTest.target("test/string")
.request(MediaType.TEXT_PLAIN)
.get( String.class );
assertNotNull( fooString );
}
#Test
public void thisTestFails() {
List<PowerMockStringWrapper> response = this.jerseyTest.target("test/list")
.request( MediaType.APPLICATION_JSON )
.get( new GenericType<List<PowerMockStringWrapper>>() {} );
assertNotNull( response );
}
}
The .get line in thisTestFails() is the line the stack trace reports is failing.
As you can see, we're not even doing anything PowerMock-ey in our tests. The PowerMockStringWrapper is just a small class that wraps String, because Jersey (for some reason) can't return Lists of base Strings. Once again, both these unit tests work without PowerMock, but the second one fails as soon as we turn PowerMock on.
Can anyone suggest anything?

Related

Mock an Interface with Mockito return a NullPointerException

I m trying create unit tests for one project.I m facing a problem because when I try control the result of an interface(mock). When the code get the Interface variable that return a NullPointerException.
Firstly I tried #Override the method in my test class (ClassA), but it don't work. After that I tried mock the interface object and control the comportment with Mockito.When().tehnReturn();
I will put here my code, I read some solutions but none works.
My Interface:
#FunctionalInterface
public interface Interface {
UpdateXResponse process(UpdateXRequest request) throws Exception;
}
The class I want to test:
#Service(ClassA.class)
public class ClassA extends VService implements UpdateX {
#Reference
#Inject
private Interface interface;
#Inject
public ClassA(...) {...}
#Override
public UpdateXResponse process(UpdateXRequest request) throws Exception {
UpdateXResponse response = initResponse(context, request, new UpdateXResponse());
UpdateXInput input = request.getInput();
UpdateXOutput output = new UpdateXOutput();
response.setOutput(output);
try {
firstMethodCall(...);
} catch (Exception t) {
throwCorrectException(t, logger);
}
return response;
}
private void firstMethodCall(...) throws Exception {
TypeF typeF = callInterfaceMethod(...);
...
}
/**
* Orchestrates Interface service
*/
protected TypeF callInterfaceMethod(...) {
...
request.setInput(input);
request.setHeader(header);
InterfaceResponse response = interface.process(request); // LINE ERROR - In this step interface is NULL when the test get this
return response;
}
}
And finally my class test:
#RunWith(PowerMockRunner.class)
#PrepareForTest(value = {ClassA.class,Interface.class} )
public class WithPowerMockUnitTest{
#InjectMocks
private ClassA classA;
private Interface interface;
#Before
public void setUp() throws Exception {
InterfaceRequest InterfaceRequest = createInterfaceRequest();
InterfaceResponse serviceUnavailableResponse = createInterfaceResponse();
Interface = Mockito.mock(Interface.class);
when(Interface.process(Mockito.any(InterfaceRequest.class))).thenReturn(serviceUnavailableResponse);
}
#Test
public void testh() throws SOAException {
InterfaceResponse res = interface.process(Mockito.any(InterfaceRequest.class)); // There all run ok. The interface is not null and return what i expected.
System.out.println("RES "+res);
}
#Test
public void test() {
assertNotNull(classA); // not null
assertNotNull(interface); // not null
}
#Test
public void newTest() throws Exception {
InterfaceRequest InterfaceRequest = createInterfaceRequest();
InterfaceResponse serviceUnavailableResponse = createInterfaceResponse();
UpdateXResponse response = ClassA.process(updateXRequest()); // PROBLEM!! When that get the LINE ERROR the interface is null! WHY?
}
}
I put some comments in the lines where the problem exists for me.
public interface A{
Response process(Request r) throws Exception;
}
public class B{
private Class_That_Override_Interface_method ctoim;
public Response function(){
X res = method_B();
}
protected X method_B(){
response res = ctoim.process(request); // That ctoim is always NULL when the test get that line/call
}
}
Thanks
You're missing the #Mock annotation on your Interface variable.
Therefore the mock is not injected into your classA and the newTest() fails. (In this case remove Interface = Mockito.mock(Interface.class); from the setUp method).
Alternativly remove the #InjectMocks annotation and create your class under test manually passing your mock into the constructor.
For this specific case (assuming its a different case from the last question)
there doesn't seem to be a need to involve PowerMockito. So unless you left out some relevant parts you might as well just use the MockitoJUnitRunner.
Ps.:
Also remeber what I said last time about compilable examples?
interface is a keyword and can't be used for variables.
You should also aim to write variables identical all the times (not Interface and interface / classA and ClassA)
And in case you haven't read it yet check out the help section about minmal reproducible examples.
Edit:
I fogot to mention that the line interface.process(Mockito.any(InterfaceRequest.class)); in testh() is actually invalid syntax. You should use ArgumentMatchers only for parameters of mocked methods.
Also consider adding the MockitoAnnotations.initMocks(this); to your setUp method, when using the PowerMockRunner.

Jersey client with RxJava conflicts with resteasy

I have a web application deployed to JBOSS. It contains dependency to jersey-rx-client-rxjava package and one of the packages has transient dependency to resteasy-jaxrs.
I have the following code.
RxObservable.newClient()
.target(fullURL)
.request()
.header("Authorization", "Bearer " + config.getApiKey())
.rx()
.post(javax.ws.rs.client.Entity.entity(context, MediaType.APPLICATION_JSON_TYPE), AIResponse.class)
.map(new Func1<AIResponse, String>() {
#Override
public String call(AIResponse res) {
return res.getType();
}
})
.subscribe(new Action1<String>() {
#Override
public void call(final String type) {
Log.info(type);
}
}, new Action1<Throwable>() {
#Override
public void call(final Throwable throwable) {
//async.resume(throwable);
Log.error(throwable.getMessage(), throwable);
}
}, new Action0() {
#Override
public void call() {
//async.resume(throwable);
Log.info("Done");
}
});
At this line, the following exception is thrown.
final JerseyInvocation invocation = (JerseyInvocation) getBuilder().build(name, entity);
Why does the build method return org.jboss.resteasy.client.jaxrs.internal.ClientInvocation, instead of JerseyInvocation?
2017-03-20 12:18:43,678 ERROR [com.optawork.bot.CustomResource] (default task-2) org.jboss.resteasy.client.jaxrs.internal.ClientInvocation cannot be cast to org.glassfish.jersey.client.JerseyInvocation: java.lang.ClassCastException: org.jboss.resteasy.client.jaxrs.internal.ClientInvocation cannot be cast to org.glassfish.jersey.client.JerseyInvocation
at org.glassfish.jersey.client.rx.rxjava.JerseyRxObservableInvoker$2.call(JerseyRxObservableInvoker.java:89)
at org.glassfish.jersey.client.rx.rxjava.JerseyRxObservableInvoker$2.call(JerseyRxObservableInvoker.java:83)
at rx.Observable.unsafeSubscribe(Observable.java:10142)
at rx.internal.operators.OnSubscribeMap.call(OnSubscribeMap.java:48)
at rx.internal.operators.OnSubscribeMap.call(OnSubscribeMap.java:33)
at rx.Observable.subscribe(Observable.java:10238)
at rx.Observable.subscribe(Observable.java:10205)
at rx.Observable.subscribe(Observable.java:10086)
at ai.api.AIDataService.converse(AIDataService.java:601)
Why does the build method return org.jboss.resteasy.client.jaxrs.internal.ClientInvocation, instead of JerseyInvocation
It's just how the JAX-RS Client API is designed. When we try to call ClientBuilder.newBuilder (which is done internally), the JAX-RS API does a service lookup for any implementation of the JAX-RS Client API. If there is none, it falls back to Jersey. The problem is that when the service lookup is done, RESTEasy's client is found on the classpath.
The Jersey RX API has a from(Client) method that we can user, instead of the default newClient. This will allow us to pass an explicit JerseyClient instead of using the JAX-RS API ClientBuilder.newBuilder/newClient
// actual JerseyClient which implements Client
Client client = new JerseyClientBuilder().build();
RxObservable.from(client)
JerseyClientBuilder has pretty much the same API as the JAX-RS ClientBuilder, so you can use it pretty much the same way.

GWT SyncProxy Testing

I create a new Web Application Project with the standard GWT example. Then i want to test the greetingserviceimpl with the following test class. I don't know where is the problem. I also upload the project: http://ul.to/1pz1989y
public class RPCTest extends GWTTestCase {
#Override
public String getModuleName() {
// TODO Auto-generated method stub
return "de.GreetingTest";
}
public void testGreetingAsync() {
GreetingServiceAsync rpcService = (GreetingServiceAsync) SyncProxy.newProxyInstance(GreetingServiceAsync.class,"http://127.0.0.1:8888/GreetingTest.html?gwt.codesvr=127.0.0.1:9997");
rpcService.greetServer("GWT User", new AsyncCallback<String>() {
public void onFailure(Throwable ex) {
ex.printStackTrace();
fail(ex.getMessage());
}
public void onSuccess(String result) {
assertNotNull(result);
finishTest();//
}
});
delayTestFinish(1000);
}
}
Validating newly compiled units
Ignored 1 unit with compilation errors in first pass.
Compile with -strict or with -logLevel set to TRACE or DEBUG to see all errors.
[ERROR] Line 17: No source code is available for type com.gdevelop.gwt.syncrpc.SyncProxy; did you forget to inherit a required module?
[ERROR] Unable to find type 'de.client.RPCTest'
[ERROR] Hint: Previous compiler errors may have made this type unavailable
[ERROR] Hint: Check the inheritance chain from your module; it may not be inheriting a required module or a module may not be adding its source path entries properly
Your rpc service is async - it doesn't finish by the time that the testGreetingAsync method returns. GWTTestCase (but you are extending TestCase, you should probably change this) has support for this though - call delayTestFinish at the end of the method to indicate that the test is async. Then, call finishTest once you are successful.
public class RPCtest extends GWTTestCase {
public void testGreetingAsync() {
GreetingServiceAsync rpcService = (GreetingServiceAsync) SyncProxy.newProxyInstance(GreetingServiceAsync.class,"http://127.0.0.1:8888/Tests.html?gwt.codesvr=127.0.0.1:9997");
rpcService.greetServer("GWT User", new AsyncCallback() {
public void onFailure(Throwable ex) {
//indicate that a failure has occured
ex.printStackTrace();
fail(ex.getMessage());//something like this
}
public void onSuccess(Object result) {
//verify the value...
assertNotNull(result);
//Then, once sure the value is good, finish the test
finishTest();//This tells GWTTestCase that the async part is done
}
});
delayTestFinish(1000);//1000 means 'delay for 1 second, after that time out'
}
}
Edit for updated question:
The test class 'de.RPCTest' was not found in module 'de.GreetingTest'; no compilation unit for that type was seen
Just like your regular GWT code must be in a client package, so must your GWTTestCase code - this also gets run as JavaScript so it can properly be tested as if it were in a browser. Based on the error, I'm guessing your EntryPoint, etc are in de.client - this test should be there too.

A parameterized AutoBean type containing a typed member

Question
Is there any way to deserialize JSON using the AutoBean framework such that the resulting bean has a type parameter that affects the type of one or more of its members?
Background
RPC with JSON results
I'm using GWT (RequestBuilder) to perform RPC requests. The JSON payload returned is of the following form:
{
"resultSet": [{...}, {...}, ...], // items requested; say, items 150-160
"totalCount": 15330 // total matching items in DB
}
The objects in resultSet vary in type depending on the specific RPC I'm calling.
AutoBean interface
I'd like to deserialize this JSON using AutoBean. I'm trying to represent this object as follows:
interface RpcResults<T> {
List<T> getResultSet();
void setResultSet(List<T> resultSet);
int getTotalCount();
void setTotalCount(int totalCount);
}
I've also created appropriate interfaces representing each type of object that could exist within resultSet. Finally, I set up the appropriate call to AutoBeanCodex.decode.
Running the code
Attempting to run this code in development mode causes the following stack trace to appear in the console:
19:44:23.791 [ERROR] [xcbackend] Uncaught exception escaped
java.lang.IllegalArgumentException: The AutoBeanFactory cannot create a java.lang.Object
at com.google.gwt.autobean.shared.AutoBeanCodex$Decoder.push(AutoBeanCodex.java:240)
at com.google.gwt.autobean.shared.AutoBeanCodex$Decoder.decode(AutoBeanCodex.java:50)
at com.google.gwt.autobean.shared.AutoBeanCodex$Decoder.visitCollectionProperty(AutoBeanCodex.java:83)
at com.citrix.xenclient.backend.client.json.RpcResultsAutoBean.traverseProperties(RpcResultsAutoBean.java:100)
at com.google.gwt.autobean.shared.impl.AbstractAutoBean.traverse(AbstractAutoBean.java:153)
at com.google.gwt.autobean.shared.impl.AbstractAutoBean.accept(AbstractAutoBean.java:112)
at com.google.gwt.autobean.shared.AutoBeanCodex$Decoder.decode(AutoBeanCodex.java:51)
at com.google.gwt.autobean.shared.AutoBeanCodex.decode(AutoBeanCodex.java:505)
at com.google.gwt.autobean.shared.AutoBeanCodex.decode(AutoBeanCodex.java:521)
at com.citrix.xenclient.backend.client.services.JSONResponseResultSetHandler.onResponseReceived(JSONResponseResultSetHandler.java:51)
at com.google.gwt.http.client.Request.fireOnResponseReceived(Request.java:287)
at com.google.gwt.http.client.RequestBuilder$1.onReadyStateChange(RequestBuilder.java:395)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:616)
at com.google.gwt.dev.shell.MethodAdaptor.invoke(MethodAdaptor.java:103)
at com.google.gwt.dev.shell.MethodDispatch.invoke(MethodDispatch.java:71)
at com.google.gwt.dev.shell.OophmSessionHandler.invoke(OophmSessionHandler.java:157)
at com.google.gwt.dev.shell.BrowserChannelServer.reactToMessagesWhileWaitingForReturn(BrowserChannelServer.java:326)
at com.google.gwt.dev.shell.BrowserChannelServer.invokeJavascript(BrowserChannelServer.java:207)
at com.google.gwt.dev.shell.ModuleSpaceOOPHM.doInvoke(ModuleSpaceOOPHM.java:126)
at com.google.gwt.dev.shell.ModuleSpace.invokeNative(ModuleSpace.java:561)
at com.google.gwt.dev.shell.ModuleSpace.invokeNativeObject(ModuleSpace.java:269)
at com.google.gwt.dev.shell.JavaScriptHost.invokeNativeObject(JavaScriptHost.java:91)
at com.google.gwt.core.client.impl.Impl.apply(Impl.java)
at com.google.gwt.core.client.impl.Impl.entry0(Impl.java:214)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:616)
at com.google.gwt.dev.shell.MethodAdaptor.invoke(MethodAdaptor.java:103)
at com.google.gwt.dev.shell.MethodDispatch.invoke(MethodDispatch.java:71)
at com.google.gwt.dev.shell.OophmSessionHandler.invoke(OophmSessionHandler.java:157)
at com.google.gwt.dev.shell.BrowserChannelServer.reactToMessages(BrowserChannelServer.java:281)
at com.google.gwt.dev.shell.BrowserChannelServer.processConnection(BrowserChannelServer.java:531)
at com.google.gwt.dev.shell.BrowserChannelServer.run(BrowserChannelServer.java:352)
at java.lang.Thread.run(Thread.java:636)
Based on this stack trace, my hunch is the following:
Type erasure makes it seem that RpcResults.getResultSet() is returning a raw List.
The AutoBean deserialiser attempts to create Object instances for each item in resultSet.
Failure
Question again
Am I missing something in the AutoBean API that will allow me to do this easily? If not, is there an obvious point of attack I should look into? Is there a more sensible alternative for what I'm doing (other than JSONParser and JavaScriptObject, which I'm already using)?
This is not simple, due to Java type erasure. The type T does not exist at runtime, having been erased to Object in lieu of any other lower bound. The AutoBeanCodex requires type information in order to reify the elements of the incoming json payload. This type information is usually provided by the AutoBean implementation, but due to the T erasure, all it knows is that it contains a List<Object>.
If you can provide a class literal at runtime, the getter could be declared as Splittable getResultSet() and the individual elements of the list reified by calling AutoBeanCodex.decode(autoBeanFactory, SomeInterfaceType.class, getResultSet().get(index)). By using a Category, you could add a <T> T getResultAs(Class<T> clazz, int index) method to the AutoBean interface. This would look something like:
#Category(MyCategory.class)
interface MyFactory extends AutoBeanFactory {
AutoBean<ResultContainer> resultContainer();
}
interface ResultContainer<T> {
Splittable getResultSet();
// It's the class literal that makes it work
T getResultAs(Class<T> clazz, int index);
}
class MyCategory {
public static <T> T getResultAs(Autobean<ResultContainer> bean,
Class<T> clazz, int index) {
return AutoBeanCodex.decode(bean.getFactory(), clazz,
bean.as().getResultSet().get(index)).as();
}
}
Try overriding the .getResultSet() and .setResultSet() methods in your object-specific interfaces:
interface FooRpcResults extends RpcResults<Foo> {
#Override
List<Foo> getResultSet();
#Override
void setResultSet(List<Foo> value);
}
The following test works for me (GWT 2.3.0):
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import com.google.web.bindery.autobean.shared.AutoBean;
import com.google.web.bindery.autobean.shared.AutoBeanCodex;
import com.google.web.bindery.autobean.shared.AutoBeanFactory;
import com.google.web.bindery.autobean.shared.AutoBeanUtils;
import com.google.web.bindery.autobean.vm.AutoBeanFactorySource;
public class AutoBeanTest {
public static interface Page<T> {
int getDataSize();
List<T> getPage();
int getStartIndex();
void setDataSize(int value);
void setPage(List<T> value);
void setStartIndex(int value);
}
public static interface Thing {
String getName();
void setName(String value);
}
public static interface ThingFactory extends AutoBeanFactory {
AutoBean<Thing> createThing();
AutoBean<ThingPage> createThingPage();
}
public static interface ThingPage extends Page<Thing> {
#Override
List<Thing> getPage();
#Override
void setPage(List<Thing> value);
}
#Test
public void testAutoBean() {
final ThingFactory factory = AutoBeanFactorySource
.create(ThingFactory.class);
final Thing thing1 = factory.createThing().as();
thing1.setName("One");
final Thing thing2 = factory.createThing().as();
thing2.setName("Two");
final List<Thing> things = new ArrayList<Thing>();
things.add(thing1);
things.add(thing2);
final Page<Thing> page = factory.createThingPage().as();
page.setStartIndex(50);
page.setDataSize(1000);
page.setPage(things);
final String json = AutoBeanCodex.encode(
AutoBeanUtils.getAutoBean(page)).getPayload();
final Page<Thing> receivedPage = AutoBeanCodex.decode(factory,
ThingPage.class, json).as();
assertEquals(receivedPage.getStartIndex(), page.getStartIndex());
assertEquals(receivedPage.getDataSize(), page.getDataSize());
assertNotNull(receivedPage.getPage());
assertEquals(receivedPage.getPage().size(), page.getPage().size());
for (int i = 0; i < receivedPage.getPage().size(); i++) {
assertNotNull(receivedPage.getPage().get(i));
assertEquals(receivedPage.getPage().get(i).getName(), page
.getPage().get(i).getName());
}
}
}
Removing the overrides in the ThingPage interface will break it.

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???)