In order to get GWT RequestFactory running with Grails, I am using the following approach:
class GwtController extends RequestFactoryServlet {
public GwtController() {
super()
}
def index = {
doPost request, response
}
#Override
public ServletContext getServletContext() {
return ServletContextHolder.servletContext
}
#Override
public ServletConfig getServletConfig() {
return new DummyServletConfig(getServletContext(),"grails");
}
}
where DummyServletConfig is a simple implementation of ServletConfig
This is working when deploying the app to tomcat. However, using testing or development mode, it is not. I was required to adjust the GWT Servlet in order to prevent it from using the wrong Class Loader:
In line 46 I changed
private static final RequestFactoryInterfaceValidator validator =
new RequestFactoryInterfaceValidator(log,
new RequestFactoryInterfaceValidator.ClassLoaderLoader(
ServiceLayer.class.getClassLoader()));
to
private static final RequestFactoryInterfaceValidator validator = new RequestFactoryInterfaceValidator(
log, new RequestFactoryInterfaceValidator.ClassLoaderLoader(
Thread.currentThread()
.getContextClassLoader()));
Otherwise, it wouldn't find my Domain classes (which apparently do not reside in the GrailsRootLoader but in the Thread's class loader).
Now I would like to revert my GWT servlet to the official binary released by Google and I wonder how I can fix the incorrect ClassLoader in Grails or make the RequestFactoryServlet work correctly without altering the GWT source.
I hope that GWT 2.3 will fix your problem:
http://code.google.com/p/google-web-toolkit/issues/detail?id=6092
Related
I have an application that uses Jersey/JAX-RS for web services (annotations, etc) and Guice to inject service implementations. I don't really like the way Guice works with servlets directly, I prefer the Jersey way, so I had to do a bit of fussing to get the service injections to work since Guice wouldn't be creating my servlet classes, and I didn't want to deal with the HK2-Guice bridge. I did this by creating a listener class (called Configuration) that sets up the injectors in static fields upon application startup and then manually effecting the injections in each servlet class by creating a parent class that all my servlets extend with a constructor that contains the following:
public MasterServlet() {
// in order for the Guice #Inject annotation to work, we have to create a constructor
// like this and call injectMembers(this) on all our injectors in it
Configuration.getMyServiceInjector().injectMembers(this);
Configuration.getDriverInjector().injectMembers(this);
}
I know it's kind of hacky, but this works just fine in my servlets. I can use the Guice #Inject annotations on my services and switch between named implementations and so on. The problem comes when I go to set up my unit tests. I'm using JerseyTest to do my tests, but running a test against my servlets results in a 500 error with Guice saying the following:
com.google.inject.ConfigurationException: Guice configuration errors:
1) No implementation for com.mycompany.MyService was bound.
while locating com.mycompany.MyService
for field at com.mycompany.servlet.TestGetServlet.service(TestGetServlet.java:21)
while locating com.mycompany.servlet.TestGetServlet
The test looks like this:
public class TestServletTest extends JerseyTest {
#Test
public void testServletFunctional() {
final String response = target("/testget").request().get(String.class);
assertEquals("get servlet functional", response);
}
#Before
public void setup() {
Configuration configuration = new Configuration();
configuration.contextInitialized(null);
}
#Override
protected Application configure() {
return new ResourceConfig(TestGetServlet.class);
}
}
You'll notice in the setup method I am manually creating my Configuration class since I can't rely on the test container (Grizzly) to create it (I get NullPointerExceptions without those two lines). More about this below.
And here's the servlet being tested:
#Path("/testget")
public class TestGetServlet extends MasterServlet {
#Inject
MyService service;
#GET
#Produces({"text/plain", MediaType.TEXT_PLAIN})
public String testGet() {
//service = Configuration.getServiceInjector().getInstance(MyService.class);
return "get servlet functional";
}
}
Notice the commented line in the testGet() method? If I do that instead and remove the #Inject annotation above, everything works fine, which indicates that Grizzly is not creating my servlets the way I expect.
I think what's happening is that Grizzly doesn't know about Guice. Everything seems to suggest that Grizzly isn't seeing the Configuration class, despite the fact that by putting it in my test's #Before method it seems to be at least available to the classes that use it (see: the commented line in the TestGetServlet class). I just don't know how to fix it.
I'm still trying to figure this out but in the meantime I switched from Guice to HK2, which took a bit of doing but I figured this might be helpful for anyone who runs into this problem in the future.
I consider this an answer because truthfully my attempt to bypass the Guice-HK2 bridge but still use Guice with Jersey might not have been the best idea.
Switching from Guice to HK2 takes a bit of doing and there's no comprehensive guide out there with all the answers. The dependencies are really fussy, for example. If you try to use Jersey 2.27 you may run into the famous
java.lang.IllegalStateException: InjectionManagerFactory not found
error. Jersey 2.27 is not backwards compatible with previous versions due to HK2 itself. I am still working on getting that all to work, but in the meantime I had to downgrade all my Jersey dependencies to 2.26-b06 to get HK2 working properly.
Jersey thankfully already implements a bunch of HK2 boilerplate, so all you need to get injection working is proper use of #Contract, #Service (see HK2 docs for those), and then two new classes that look like this:
public class MyHK2Binder extends AbstractBinder {
#Override
protected void configure() {
// my service here is a singleton, yours might not be, so just omit the call to in()
// also, the order here is switched from Guice! very subtle!
bind(MyServiceImpl.class).to(MyService.class).in(Singleton.class);
}
}
And this:
public class MyResourceConfig extends ResourceConfig {
public MyResourceConfig() {
register(new MyHK2Binder());
packages(true, "com.mycompany");
}
}
Simple enough, but this only works for the application itself. The test container knows nothing about it, so you have to redo the Binder and ResourceConfig yourself in your test class, like this:
public class TestServletTest extends JerseyTest {
#Test
public void testServletFunctional() {
final String response = target("/testget").request().get(String.class);
assertEquals("get servlet functional", response);
}
#Before
public void setup() {
}
#Override
protected Application configure() {
return new TestServletBinder(TestGetServlet.class);
}
public class TestServletBinder extends ResourceConfig {
public TestServletBinder(Class registeree) {
super(registeree);
register(new MyHK2Binder());
packages(true, "com.mycompany");
}
}
}
Having to do this is actually fine because you can switch out the Binder for a test binder instead, in which you've bound your service to a mocked service instead or something. I haven't done that here but that's easy enough to do: replace new MyHK2Binder() in the call to register() with one that does a binding like this instead:
bind(MyTestServiceImpl.class).to(MyService.class).in(Singleton.class);
And voila. Very nice. Obviously you could achieve a similar result with Named bindings, but this works great and might even be simpler and more clear.
Hope this helps someone save the hours I spent screwing around to get this working.
I'm trying to add a GraphQLServlet to my existing webservice using graphql-spqr.
I have added the correct annotations and now only need to setup the GraphQL endpoint, which is where I am struggling.
All tutorials and google results that I found are referring to deprecated constructors for the class graphql.servlet.SimpleGraphQLServlet
I can create a servlet object like this:
UserService userService = new UserService();
GraphQLSchema schema = new GraphQLSchemaGenerator()
.withOperationsFromSingleton(userService)
.generate();
graphql.servlet.GraphQLServlet servlet = new Builder(schema).build();
But I can't figure out if and how you can register a servlet instance.
And search engines either misinterpret my search or come up empty.
I'm grateful for any pointers.
Using Servlet 3+, you can dynamically register the servlet. This is what I did for the exact same reason (I didn't want to use deprecated constructors).
#WebListener
public class GraphQLServletRegistrationServletContextListener implements ServletContextListener {
private GraphQLSchema schema;
public GraphQLServletRegistrationServletContextListener() {}
#Inject
public GraphQLServletRegistrationServletContextListener(final GraphQLSchema schema) {
this.schema = schema;
}
#Override
public void contextInitialized(final ServletContextEvent event) {
final ServletRegistration.Dynamic dynamicGraphQLServlet
= event.getServletContext().addServlet("GraphQLEndpoint", SimpleGraphQLServlet.create(schema));
dynamicGraphQLServlet.addMapping("/graphql");
}
#Override
public void contextDestroyed(final ServletContextEvent event) {}
}
I'm using CDI to inject the GraphQLSchema, but you can just ignore that and construct it manually any way you like.
UPDATE: As of graphql-java-servlet 6.x, this answer seems to be out of date
Unless you're using Spring, it's actually quite difficult to register a servlet instance yourself (and there's no standard way to do this), as the Servlet spec never really intended it to be used this way (the container is expected to take care of instantiating the servlets). And if you are using Spring, creating a servlet is unnecessary anyway. For this reason, using the SimpleGraphQLServlet is often unintuitive and inconvenient.
One way you can go about it is to subclass the SimpleGraphQLServlet, and let the container instantiate it for you as intended:
#WebServlet(urlPatterns = "/graphql")
public class GraphQLEndpoint extends SimpleGraphQLServlet {
public GraphQLEndpoint() {
super(schema());
}
private static GraphQLSchema schema() {
UserService userService = new UserService();
GraphQLSchema schema = new GraphQLSchemaGenerator()
.withOperationsFromSingleton(userService)
.generate();
return schema;
}
}
You can also register GraphQLEndpoint the old-school way via web.xml.
You'll notice that you need to inline the entire setup as the call to super has to be the very first thing the constructor calls. This is what makes SimpleGraphQLServlet so inconvenient.
Another option is create your own servlet instead. There's really not that many things you need to do immediately. Just create the schema in its init method (no weird inline setup needed), store it in an instance field, and accept queries in doGet or doPost. There's of course the matter of handling errors, different URLs etc, which is a bit more complicated, but you don't need it right away for learning the basics.
You might also want to use a full-fledged framework, like Spring MVC or Boot. You can find an example of this in graphql-spqr samples.
I'm writing custom JAX-RS 2.0 application (under Jersey 2.3.1) which holds some data for use by all the resources.
public class WebApp extends org.glassfish.jersey.server.ResourceConfig {
public WebApp() {
packages("my.resources.package");
}
}
(I could use API's javax.ws.rs.core.Application as well, the described result is the same)
Then I inject the object into a resource
#Path("test")
public class Test {
#Context
Application app;
#GET
#Path("test")
public String test() {
return "Application class: " + app.getClass();
}
}
However, the result of a call is
Application class: class org.glassfish.jersey.server.ResourceConfig$WrappingResourceConfig
which makes me use some ugly tricks like
if (app instanceof WebApp) {
return (WebApp) app;
} else if (app instanceof ResourceConfig) {
return (WebApp) ((ResourceConfig) app).getApplication();
}
My understanding of JAX-RS 2.0 spec section 9.2.1:
The instance of the application-supplied Application subclass can be injected into a class field or method parameter using the #Context annotation. Access to the Application subclass instance allows configuration information to be centralized in that class. Note that this cannot be injected into the Application subclass itself since this would create a circular dependency.
is that application-supplied Application subclass is mine WebApp, not JAX-RS implementation-specific wrapper.
Also, changing this fragment
#Context
Application app;
to this
#Context
WebApp app;
causes app to be null, due to ClassCastException during context injection, so the declared type doesn't matter.
Is it a bug in Jersey or my misunderstanding?
UPDATE: I checked the behaviour under RESTEasy 3.0. The injected object is my WebApp, without any wrappers. I'd call it a bug in Jersey.
This doesn't seem like a bug. According to JAX-RS 2.0 spec you can inject Application into your resource classes (for example) but it does not say anything about directly injecting custom extensions of the Application. Not sure what your use-case is but you can register custom HK2 binder that will allow you to inject directly WebApp into resources:
public class WebApp extends org.glassfish.jersey.server.ResourceConfig {
public WebApp() {
packages("my.resources.package");
register(new org.glassfish.hk2.utilities.binding.AbstractBinder() {
#Override
protected void configure() {
bind(WebApp.this);
}
});
}
}
I too have encountered this using Jersey 2.4.1.
FWIW: I agree it seems like a bug according to the spec para 8.2.1. The statement "The instance of the application-supplied Application subclass" seems perfectly clear.
I have an alternative workaround that doesn't involve glassfish.hk2 but still concentrates the Jersey-specific code in the Application-derived class.
public class MyApp extends ResourceConfig {
...
static MyApp getInstance( Application application) {
try {
// for a conformant implementation
return (MyApp) application;
} catch (ClassCastException e) {
// Jersey 2.4.1 workaround
ResourceConfig rc = (ResourceConfig) application;
return (MyApp) rc.getApplication();
}
}
...
}
public class MyResource {
...
#Context Application application;
...
SomeMethod() {
... MyApp.getInstance( application);
}
}
Hope this is useful.
This appears to be fixed in a later version og Jersey. The same approach works for me with Jersey 2.16 at least. My injected Application object is of the correct subclass without any wrapping whatsoever.
Edit: Or maybe the version is irrelevant after all. Please see the comments to this answer.
I'm building rest service using an authentication/authorization mechanism as described in this tutorial: http://howtodoinjava.com/2013/06/26/jax-rs-resteasy-basic-authentication-and-authorization-tutorial/
Basically it uses the PreProcessInterceptor interface to scan the target method for annotations (from javax.annotation.security package) which describe the required roles to access that method. As the the authenticator here is an interceptor, it can cancel the target method invocation, returning a 401 (unauthorized) if needed.
The problem here is that the interface org.jboss.resteasy.spi.interception.PreProcessInterceptor is deprecated in the current RestEasy version (3.0.1), and I'm having problems trying to implement the same behaviour with the standard JAX-RS interfaces.
I'm using the javax.ws.rs.ext.ReaderInterceptor interface to intercept the call. But somehow the server never calls it: the interceptor is just ignored.
I'm registering the interceptors/resources the same way as I did with the former PreProcessInterceptor, and using the same #Provider and #ServerInterceptor annotations:
ServerApplication:
public class ServerApplication extends javax.ws.rs.core.Application {
private final HashSet<Object> singletons = new LinkedHashSet<Object>();
public ServerApplication() {
singletons.add(new SecurityInterceptor());
singletons.add( ... ); //add each of my rest resources
}
#Override
public Set<Class<?>> getClasses() {
HashSet<Class<?>> set = new HashSet<Class<?>>();
return set;
}
#Override
public Set<Object> getSingletons() {
return singletons;
}
}
SecurityInterceptor:
#Provider
#ServerInterceptor
public class SecurityInterceptor implements javax.ws.rs.ext.ReaderInterceptor {
#Override
public Object aroundReadFrom(ReaderInterceptorContext context){
//code that is never called... so lonely here...
}
}
Any insights about how can I solve this problem?
Thank you.
RESTEasy 3.x.x conforms to the JAX-RS 2.0 specification.
What you are trying to do could be accomplished (maybe better) with:
#Provider
public class SecurityInterceptor
implements javax.ws.rs.container.ContainerRequestFilter {
#Override
public void filter(ContainerRequestContext requestContext){
if (not_authenticated){ requestContext.abortWith(response)};
}
}
since the ReaderInterceptor is invoked only if the underlying MessageBodyReader.readFrom is called by the standard JAX-RS pipeline, not fromthe application code.
The reason why your interceptor is not called, though, could be the #ServerInterceptor annotation, which is a RESTEasy extension.
The spec states at ยง6.5.2 that a interceptor is globally registered, unless the #Provider is annotated with a #NameBinding annotation, but I don't know if RESTEasy can handle a #ServerInterceptor if it's not explicitly registered as shown in RestEASY Interceptor Not Being Called
If you need to get access to the underlying java.lang.reflect.Method (like you used to be able to get by implementing AcceptedByMethod), you can do the following:
ResourceMethodInvoker methodInvoker = (ResourceMethodInvoker)
requestContext.getProperty("org.jboss.resteasy.core.ResourceMethodInvoker");
Method method = methodInvoker.getMethod();
I also wanted to get access to the underlying java.lang.reflect.Method and tried mtpettyp's answer with Resteasy 3.0.8, but that was returning null on the getProperty call. I am also using Spring and resteasy-spring although I don't believe that should impact this at all.
If you run into my situation and are implementing a Post Matching ContainerRequestFilter (you kind of have to if you were expecting to get the matched resource method anyway) then you can actually cast the ContainerRequestContext to the implementation Resteasy has for the Post Match scenario. The PostMatchContainerRequestContext has a reference to the ResourceMethodInvoker.
public void filter(ContainerRequestContext context) throws IOException {
PostMatchContainerRequestContext pmContext = (PostMatchContainerRequestContext) context;
Method method = pmContext.getResourceMethod().getMethod();
/* rest of code here */
}
I have created a simple web service called TimeServerBean. It's working properly, the GlassFish server is running and I can access the WSDL file from browser. Note this is done on local host.
Next I created a new project and made a web service client and provided the URL to the WSDL file. Then I got some classes generated (JAX-WS).
On my client class I have this code:
public class SimpleClient {
#WebServiceRef(wsdlLocation = "wsdl url here")
static TimeServerBean_Service service;
private TimeServerBean bean;
public SimpleClient() {
bean = service.getTimeServerBeanPort();
}
//methods here
}
Although I get null when I call the getTimeServerBeanPort. During that time the server is up and running. Is there some obvious mistake? TimeServerBean and TimeServerBean_Service are generated classes from the WSDL.
Two suggestions:
DEFINITELY put your method in a try/catch block
Assuming that service itself is null, then try doing an explicit service.create() instead of using the #WebServiceRef annotation. Here's a good example (Websphere, but same principle):
http://www-01.ibm.com/support/docview.wss?uid=swg21264135
The #WebServiceRef annotation is only supported in certain class types. Examples are JAX-WS endpoint implementation classes, JAX-WS handler classes, Enterprise JavaBeans classes, and servlet classes. This annotation is supported in the same class types as the #Resource annotation. See the Java Platform, Enterprise Edition (Java EE) 5 specification for a complete list of supported class types.
I generally do it by creating an instance using the interface and the class.
public class SimpleClient {
// interface TimeServerBean_Service class TimeServerBean
#WebServiceRef(wsdlLocation = "wsdl url here")
static TimeServerBean_Service port = new TimeServerBean.getTimeServerBeanPort();
public static void main(String[] args) {
try {
System.out.println(port);
System.out.println(port.methodWS("args"));
} catch (Exception e) {
e.printStackTrace();
}
}
//methods here
}