-
1. Re: Can Errai be used with existing JAX-RS interfaces?
froed May 28, 2012 10:39 AM (in response to mcaspers)I am also searching for possibility to use already existing REST-Interfaces, i.e. provided by an EJB.
The way I go actually is to duplicate the Interfaces and model classes in my GWT-Project. In this case the GWT-Compiler is able to find all the code. Every time the REST-Interfaces in the EJB changes I have to change them also in the GWT-Project, which is annoying and error prone.
Since I know it is not enough to set
RestClient.setApplicationRoot("http://127.0.0.1:8080/rest");
because the Errai JSON format is not compatible i.e. with Jackson (see: https://issues.jboss.org/browse/ERRAI-295), it is required to set
RestClient.setJacksonMarshallingActive(true);
using both I was able to call the EJBs REST-Interface with my duplicate approach, but there were response exceptions, which I was not able to fix.
I would be an amazing feature of ERRAI JAX-RS to access existing REST-Interfaces. May be one can present a way how to accomplish this.
-
2. Re: Can Errai be used with existing JAX-RS interfaces?
csa May 28, 2012 10:45 AM (in response to mcaspers)Hi,
The error you are seeing suggests that Errai could not find a single remote (or JAX-RS) interface. Does your GWT module (the one containing RESTInterfaceV1) contain an ErraiApp.properties file? It's a marker file required for classpath scanning (even if empty).
Concerning marshalling:
Which JSON library is used by your JAX-RS endpoint? If Jackson is used you can use Errai 2.1-SNAPSHOT which contains a client-side Jackson transformer. Alternatively, you could deploy the errai-jaxrs-provider which registers a MessageBodyReader/Writer for Errai's JSON format.
In any case the classes used in your remote interfaces have to be known to errai-marshalling. If you can't annotate them with @Portable, you can alternatively list these classes in your ErraiApp.properties:
errai.marshalling.serializableTypes=org.foo.client.UserEntity \
org.foo.client.GroupEntity
Cheers,
Christian
-
3. Re: Can Errai be used with existing JAX-RS interfaces?
csa May 28, 2012 10:58 AM (in response to froed)Hi Dave,
What prevents you from sharing your JAX-RS interface on the client and server?
If you were already able to call your JAX-RS endpoints, what were the response exceptions you were getting? We should be able to figure out the problem with the exception details.
Cheers,
Christian
-
4. Re: Can Errai be used with existing JAX-RS interfaces?
froed May 28, 2012 12:09 PM (in response to csa)Hi Christian, thanks for the quick response.
While debugging the client GWT and server EJB code I see that the client call is successfully on the server side. After that I identified the exception in
AbstractCollectionMarshaller
at
collection.add(ctx.getMarshallerInstance(type).demarshall(elem, ctx));
the Client exception:
java.lang.NullPointerException: null at org.jboss.errai.marshalling.client.marshallers.AbstractCollectionMarshaller.marshallToCollection(AbstractCollectionMarshaller.java:77) at org.jboss.errai.marshalling.client.marshallers.ListMarshaller.doDemarshall(ListMarshaller.java:43) at org.jboss.errai.marshalling.client.marshallers.ListMarshaller.doDemarshall(ListMarshaller.java:1) at org.jboss.errai.marshalling.client.marshallers.AbstractCollectionMarshaller.doDemarshall(AbstractCollectionMarshaller.java:47) at org.jboss.errai.marshalling.client.marshallers.AbstractCollectionMarshaller.doDemarshall(AbstractCollectionMarshaller.java:1) at org.jboss.errai.marshalling.client.marshallers.AbstractBackReferencingMarshaller.demarshall(AbstractBackReferencingMarshaller.java:67) at org.jboss.errai.marshalling.client.Marshalling.fromJSON(Marshalling.java:157) at org.jboss.errai.enterprise.client.jaxrs.MarshallingWrapper.fromJSON(MarshallingWrapper.java:56) at org.jboss.errai.enterprise.client.jaxrs.JaxrsProxyLoaderImpl$1MemberResourceServiceImpl$1.onResponseReceived(JaxrsProxyLoaderImpl.java:87) 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:601) 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:172) at com.google.gwt.dev.shell.BrowserChannelServer.reactToMessagesWhileWaitingForReturn(BrowserChannelServer.java:337) at com.google.gwt.dev.shell.BrowserChannelServer.invokeJavascript(BrowserChannelServer.java:218) at com.google.gwt.dev.shell.ModuleSpaceOOPHM.doInvoke(ModuleSpaceOOPHM.java:136) 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:213) 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:601) 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:172) at com.google.gwt.dev.shell.BrowserChannelServer.reactToMessages(BrowserChannelServer.java:292) at com.google.gwt.dev.shell.BrowserChannelServer.processConnection(BrowserChannelServer.java:546) at com.google.gwt.dev.shell.BrowserChannelServer.run(BrowserChannelServer.java:363) at java.lang.Thread.run(Thread.java:722)
I'am using the errai 2.1-SNAPSHOT
This is my client code:
@Inject private Caller<org.jboss.sample.rest.client.shared.MemberResourceService> memberService; final RemoteCallback<List<Member>> memberCallback = new RemoteCallback<List<Member>>() { @Override public void callback(List<Member> members) { for (final Member member : members) { //addCustomerToTable(customer, customersTable.getRowCount() + 1); System.out.println("Members-Name:"+ member.getName()); } } }; memberService.call(memberCallback).listAllMembers();
-
5. Re: Can Errai be used with existing JAX-RS interfaces?
csa May 28, 2012 12:21 PM (in response to froed)So it seems Errai didn't find a marshaller for your Member class. Is it @Portable or configured in ErraiApp.properites?
-
6. Re: Can Errai be used with existing JAX-RS interfaces?
froed May 28, 2012 3:38 PM (in response to csa)Hi,
The Member class was annotated with @Portable. Now I've created ErraiApp.properites for the Member class project with
errai.marshalling.serializableTypes=org.jboss.sample.main.SampleMain.model.Member
and another ErraiApp.properites for my REST Interface in the web project provides the REST Interface
the previous exception is gone, but now I get
21:31:56.504 [ERROR] [App] Uncaught exception escaped java.lang.RuntimeException: error demarshalling entity: org.jboss.sample.main.SampleMain.model.Member at org.jboss.errai.marshalling.client.api.MarshallerFactoryImpl$7.demarshall(MarshallerFactoryImpl.java:518) at org.jboss.errai.marshalling.client.api.MarshallerFactoryImpl$7.demarshall(MarshallerFactoryImpl.java:1) at org.jboss.errai.marshalling.client.marshallers.AbstractCollectionMarshaller.marshallToCollection(AbstractCollectionMarshaller.java:77) at org.jboss.errai.marshalling.client.marshallers.ListMarshaller.doDemarshall(ListMarshaller.java:43) at org.jboss.errai.marshalling.client.marshallers.ListMarshaller.doDemarshall(ListMarshaller.java:1) at org.jboss.errai.marshalling.client.marshallers.AbstractCollectionMarshaller.doDemarshall(AbstractCollectionMarshaller.java:47) at org.jboss.errai.marshalling.client.marshallers.AbstractCollectionMarshaller.doDemarshall(AbstractCollectionMarshaller.java:1) at org.jboss.errai.marshalling.client.marshallers.AbstractBackReferencingMarshaller.demarshall(AbstractBackReferencingMarshaller.java:67) at org.jboss.errai.marshalling.client.Marshalling.fromJSON(Marshalling.java:157) at org.jboss.errai.enterprise.client.jaxrs.MarshallingWrapper.fromJSON(MarshallingWrapper.java:56) at org.jboss.errai.enterprise.client.jaxrs.JaxrsProxyLoaderImpl$1MemberResourceServiceImpl$1.onResponseReceived(JaxrsProxyLoaderImpl.java:300) 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:601) 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:172) at com.google.gwt.dev.shell.BrowserChannelServer.reactToMessagesWhileWaitingForReturn(BrowserChannelServer.java:337) at com.google.gwt.dev.shell.BrowserChannelServer.invokeJavascript(BrowserChannelServer.java:218) at com.google.gwt.dev.shell.ModuleSpaceOOPHM.doInvoke(ModuleSpaceOOPHM.java:136) 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:213) 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:601) 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:172) at com.google.gwt.dev.shell.BrowserChannelServer.reactToMessages(BrowserChannelServer.java:292) at com.google.gwt.dev.shell.BrowserChannelServer.processConnection(BrowserChannelServer.java:546) at com.google.gwt.dev.shell.BrowserChannelServer.run(BrowserChannelServer.java:363) at java.lang.Thread.run(Thread.java:722) Caused by: org.jboss.errai.marshalling.client.api.exceptions.MarshallingException: cannot demarshall as java.lang.Long: expected qualified value but got: org.jboss.errai.marshalling.client.api.json.impl.gwt.GWTJSONValue@71164f01 at org.jboss.errai.marshalling.client.marshallers.LongMarshaller.doNotNullDemarshall(LongMarshaller.java:44) at org.jboss.errai.marshalling.client.marshallers.LongMarshaller.doNotNullDemarshall(LongMarshaller.java:1) at org.jboss.errai.marshalling.client.marshallers.AbstractNullableMarshaller.demarshall(AbstractNullableMarshaller.java:19) at org.jboss.errai.marshalling.client.api.MarshallerFactoryImpl$7.demarshall(MarshallerFactoryImpl.java:504) at org.jboss.errai.marshalling.client.api.MarshallerFactoryImpl$7.demarshall(MarshallerFactoryImpl.java:1) at org.jboss.errai.marshalling.client.marshallers.AbstractCollectionMarshaller.marshallToCollection(AbstractCollectionMarshaller.java:77) at org.jboss.errai.marshalling.client.marshallers.ListMarshaller.doDemarshall(ListMarshaller.java:43) at org.jboss.errai.marshalling.client.marshallers.ListMarshaller.doDemarshall(ListMarshaller.java:1) at org.jboss.errai.marshalling.client.marshallers.AbstractCollectionMarshaller.doDemarshall(AbstractCollectionMarshaller.java:47) at org.jboss.errai.marshalling.client.marshallers.AbstractCollectionMarshaller.doDemarshall(AbstractCollectionMarshaller.java:1) at org.jboss.errai.marshalling.client.marshallers.AbstractBackReferencingMarshaller.demarshall(AbstractBackReferencingMarshaller.java:67) at org.jboss.errai.marshalling.client.Marshalling.fromJSON(Marshalling.java:157) at org.jboss.errai.enterprise.client.jaxrs.MarshallingWrapper.fromJSON(MarshallingWrapper.java:56) at org.jboss.errai.enterprise.client.jaxrs.JaxrsProxyLoaderImpl$1MemberResourceServiceImpl$1.onResponseReceived(JaxrsProxyLoaderImpl.java:300) 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:601) 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:172) at com.google.gwt.dev.shell.BrowserChannelServer.reactToMessagesWhileWaitingForReturn(BrowserChannelServer.java:337) at com.google.gwt.dev.shell.BrowserChannelServer.invokeJavascript(BrowserChannelServer.java:218) at com.google.gwt.dev.shell.ModuleSpaceOOPHM.doInvoke(ModuleSpaceOOPHM.java:136) 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:213) 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:601) 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:172) at com.google.gwt.dev.shell.BrowserChannelServer.reactToMessages(BrowserChannelServer.java:292) at com.google.gwt.dev.shell.BrowserChannelServer.processConnection(BrowserChannelServer.java:546) at com.google.gwt.dev.shell.BrowserChannelServer.run(BrowserChannelServer.java:363) at java.lang.Thread.run(Thread.java:722)
it is the following part
@Override public Long doNotNullDemarshall(EJValue o, MarshallingSession ctx) { if (o.isObject() != null) { EJValue numValue = o.isObject().get(SerializationParts.NUMERIC_VALUE); return Long.parseLong(numValue.isString().stringValue()); } else { throw new MarshallingException("cannot demarshall as java.lang.Long: expected qualified value but got: " + o); } }
in LongMarshaller class
-
7. Re: Can Errai be used with existing JAX-RS interfaces?
csa May 28, 2012 5:25 PM (in response to froed)OK that was a bug when transforming Long values between Errai's JSON and Jackson. It's fixed now and new 2.1-SNAPSHOTs have been published.
-
8. Re: Can Errai be used with existing JAX-RS interfaces?
mcaspers May 28, 2012 6:02 PM (in response to csa)Thanks for the response Christian. I was missing the ErraiApp.properties file. However, adding it into the JAR files doesn't seem to have made any difference to the error.
My JAR file is a mixture of classes that I don't want to expose to GWT starting at com.company.general, and then a package tree starting at com.company.productname.rest that I do want to share. The rest.gwt.xml file is located at com.company.productname.
I have tried placing an empty ErraiApp.properties file alongside the rest.gwt.xml in the com.company.productname package, and also at the root in the src/main/java directory, but in both cases the "
There are no proxy providers registered yet
" error is displayed. -
9. Re: Can Errai be used with existing JAX-RS interfaces?
csa May 28, 2012 6:29 PM (in response to mcaspers)I take it you have an <inherits name="org.jboss.errai.enterprise.Jaxrs"/> in your client's gwt.xml and your interface has an @Path annotation?
Also make sure that your interfaces are in a GWT client package (either *.client.* or whatever is configured as a source path in your gwt.xml).
If that's all the case and you still get the error you could step into JaxrsProxyLoaderGenerator. That's where the classpath is scanned for your JAX-RS annotated interfaces and see what's going wrong.
-
10. Re: Can Errai be used with existing JAX-RS interfaces?
froed May 29, 2012 5:01 AM (in response to csa)Hi Christian,
thanks for the fix, now it works.
For those who are interested in the solution I want to give some background information. I used the following maven archetypes
Group Id
org.jboss.spec.archetypes
Artifact Id
jboss-javaee6-webapp-ear-archetype 7.1.1.Beta2
and the following as the errai jax-rs maven module of the above, which calls the REST endpoint (war project)
https://docs.jboss.org/author/display/ERRAI/Errai+JAX-RS+Maven+Archetype
May be one could create an template for a quickstart
-
Sample-rest.tar.gz 104.3 KB
-
-
11. Re: Can Errai be used with existing JAX-RS interfaces?
mcaspers May 29, 2012 4:09 PM (in response to csa)My test Errai app has one class, shown below. This is a stripped down version of what you get in the JAX-RS archetype.
package com.redhat.topicindex.extras.client.local; import javax.annotation.PostConstruct; import org.jboss.errai.bus.client.api.ErrorCallback; import org.jboss.errai.bus.client.api.Message; import org.jboss.errai.bus.client.api.RemoteCallback; import org.jboss.errai.enterprise.client.jaxrs.api.RestClient; import org.jboss.errai.ioc.client.api.EntryPoint; import com.redhat.topicindex.rest.sharedinterface.RESTTest; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.client.ui.VerticalPanel; /** * Example code showing how to use Errai-JAXRS. * * @author Christian Sadilek <csadilek@redhat.com> */ @EntryPoint public class App { @PostConstruct public void init() { interfaceTest(); runREST(); } private void interfaceTest() { final RESTTest impl = new RESTTest() { @Override public String doStuff() { return "Yay"; } }; System.out.println(impl.doStuff()); } private void runREST() { RestClient.setApplicationRoot("http://localhost:8080/TopicIndex/seam/resource/rest"); final RemoteCallback<String> successCallback = new RemoteCallback<String>() { @Override public void callback(final String retValue) { Window.alert(retValue); } }; final ErrorCallback errorCallback = new ErrorCallback() { @Override public boolean error(final Message message, final Throwable throwable) { Window.alert("The REST call was unsuccessful"); return true; } }; try { RESTTest restMethod = RestClient.create(RESTTest.class, successCallback, errorCallback); restMethod.doStuff(); } catch (final Exception ex) { ex.printStackTrace(); Window.alert(ex.toString()); } } }
The interface RESTTest exists in a JAR file that has been included with the project. It is a simple interface with one method.
package com.redhat.topicindex.rest.sharedinterface; import javax.ws.rs.Consumes; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; @Path("test") public interface RESTTest { @GET @Path("/topic/get/html") @Produces(MediaType.APPLICATION_XHTML_XML) @Consumes({ "*" }) public String doStuff(); }
As you can see, the method interfaceTest() implements this interface and writes some text to the console. This method does work - I can see "Yay" being printed to the console. I'm taking this to mean that the GWT module exposes the interface correctly in the JAR file and is referenced correctly my project.
The runREST() method tries to run the REST method. It displays the following exception.
java.lang.RuntimeException: No proxy provider found for type:com.redhat.topicindex.rest.sharedinterface.RESTTest
If I copy the RESTTest interface to the com.redhat.topicindex.extras.client.local package and run it again, the REST method is called as expected, so it does not appear to be an issue with the RESTTest interface itself.
The JAR file does include a ErraiApp.properties file alongside the .gwt.xml file.
The App.gwt.xml file is shown below.
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 1.6//EN" "http://google-web-toolkit.googlecode.com/svn/releases/1.6/distro-source/core/src/gwt-module.dtd"> <module rename-to="App"> <inherits name='com.google.gwt.user.User'/> <inherits name="org.jboss.errai.common.ErraiCommon"/> <inherits name="org.jboss.errai.ioc.Container"/> <inherits name="org.jboss.errai.enterprise.Jaxrs"/> <inherits name="javax.ws.rs.core"/> <inherits name="com.redhat.topicindex.rest"/> </module>
-
12. Re: Can Errai be used with existing JAX-RS interfaces?
mcaspers May 29, 2012 4:29 PM (in response to mcaspers)Ah, I see my problem. The ErraiApp.properties file has to be in the root directory of the JAR file, not in a sub directory/package.
-
13. Re: Can Errai be used with existing JAX-RS interfaces?
csa May 29, 2012 4:34 PM (in response to mcaspers)OK so it works now? I was about to write that your rest.gwt.xml should also have a <source path="rest"> element.
-
14. Re: Can Errai be used with existing JAX-RS interfaces?
mcaspers May 29, 2012 7:01 PM (in response to csa)Yes, moving the ErraiApp.properties file to the root directory of the JAR file has fixed the issue.
Now it's onto implementing CORS so I can actually use the REST service from an Errai debug server...