Grizzly Jersey swallowing exceptions - java

I'm building a Jersey Moxy service using the quickstart archetype at the end. My code works fine and I can get some JSON returned. However as I'm developing, if I make a mistake, say the request handler has an unsupported type, I will get an empty 500 response, which makes debugging difficult. For example, if I decorate an attribute incorrectly with #XmlElementRef, I will get a response like:
$ curl -i http://localhost:8080/myapp/test
HTTP/1.1 500 Internal Server Error
Date: Thu, 05 Sep 2013 10:27:55 GMT
Connection: close
Content-Length: 0
The server will act as if nothing is wrong:
Sep 5, 2013 11:27:46 AM org.glassfish.grizzly.http.server.HttpServer start
INFO: [HttpServer] Started.
Jersey app started with WADL available at http://localhost:8080/application.wadl
Hit enter to stop it...
I tried using a log config file with:
-Djava.util.logging.config.file=log.conf
This produces plenty of output, but still doesn't show any kind of exception.
I've tried looking into Grizzly config but I can't find a way turn off graceful error handling. Ideally I would like the server to throw an exception. Any suggestions on what I'm missing?
Here's my main code:
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
import org.glassfish.jersey.moxy.json.MoxyJsonConfig;
import org.glassfish.jersey.server.ResourceConfig;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;
import java.io.IOException;
import java.net.URI;
import java.util.*;
public class Main {
// Base URI the Grizzly HTTP server will listen on
public static final String BASE_URI = "http://localhost:8080/";
/**
* Starts Grizzly HTTP server exposing JAX-RS resources defined in this application.
* #return Grizzly HTTP server.
*/
public static HttpServer startServer() {
// create a resource config that scans for JAX-RS resources and providers
// in com.myapp package
final ResourceConfig rc = new ResourceConfig().packages("com.myapp").registerInstances(new JsonMoxyConfigurationContextResolver());
// create and start a new instance of grizzly http server
// exposing the Jersey application at BASE_URI
return GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI), rc);
}
/**
* Main method.
* #param args
* #throws IOException
*/
public static void main(String[] args) throws IOException {
final HttpServer server = startServer();
System.out.println(String.format("Jersey app started with WADL available at "
+ "%sapplication.wadl\nHit enter to stop it...", BASE_URI));
System.in.read();
server.stop();
}
#Provider
final static class JsonMoxyConfigurationContextResolver implements ContextResolver<MoxyJsonConfig> {
#Override
public MoxyJsonConfig getContext(Class<?> objectType) {
final MoxyJsonConfig configuration = new MoxyJsonConfig();
Map<String, String> namespacePrefixMapper = new HashMap<String, String>(1);
namespacePrefixMapper.put("http://www.w3.org/2001/XMLSchema-instance", "xsi");
configuration.setNamespacePrefixMapper(namespacePrefixMapper);
configuration.setNamespaceSeparator(':');
return configuration;
}
}
}
The code is almost identical to the example here:
https://github.com/jersey/jersey/tree/2.2/examples/json-moxy/src/main/java/org/glassfish/jersey/examples/jsonmoxy
Full archetype generation I used:
mvn archetype:generate -DarchetypeArtifactId=jersey-quickstart-grizzly2 \
-DarchetypeGroupId=org.glassfish.jersey.archetypes -DinteractiveMode=false \
-DgroupId=com.myapp -DartifactId=yarese-service -Dpackage=com.myapp \
-DarchetypeVersion=2.2
Suggestions gratefully received.

The exception is not getting propagated to the Grizzly layer, so it should be logged by Jersey. I haven't found what kind of Logger you have to enable, but looks like custom ExceptionMapper could help.
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
import org.glassfish.grizzly.utils.Exceptions;
#Provider
public class MyExceptionMapper implements
ExceptionMapper<WebApplicationException> {
#Override
public Response toResponse(WebApplicationException ex) {
return Response.status(500).entity(Exceptions.getStackTraceAsString(ex)).type("text/plain")
.build();
}
}

As you've seen, Grizzly uses java.util.logging. If you'd like to see the stacktrace, you need to make sure the levels are correctly set in your log.conf file.
Here are settings that have worked for me in the past:
handlers=java.util.logging.ConsoleHandler
java.util.logging.ConsoleHandler.level=ALL
.level=ALL
org.glassfish.level=CONFIG

Related

REST-EJB AccessLocalException causes BadRequest(500) instead of Unauthorized(401)

I get the exception:
Warning: StandardWrapperValve[org.netbeans.rest.application.config.ApplicationConfig]: Servlet.service() for servlet org.netbeans.rest.application.config.ApplicationConfig threw exception
javax.ejb.AccessLocalException: Client not authorized for this invocation
This is perfectly normal, as it is not authorized for this methodcall.
Onfortunately, as this EJB is a REST Service as well, it throws a "500 - Bad Request" http status. Instead I would like to have a "401 - Unauthorized".
Should I not use EJB Security or should I catch this AccessLocalException in the ApplicationConfig or should I use Jersey to implement REST Security?
Roles are defined in the web.xml and annotations are put upon the EJB Bean.
You can define an ExceptionMapper, that maps a General Exception onto a HTTP Response.
import javax.ejb.EJBAccessException;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
#Provider
public class EJBAccessExceptionMapper implements
ExceptionMapper<EJBAccessException>
{
#Override
public Response toResponse(EJBAccessException exception)
{
return Response.status(Response.Status.UNAUTHORIZED).build();
}
}

How to simulate client-server restful web service completely in Java IDE, without deploying to a web server, using jersey?

I don't if this is even possible, which is why I thought I'd ask.
I forgot to mention I'm using Jersey 1.19 and Java 1.6.
I created a RESTful web service in Java using the Jersey API, as well as client code to call the web service. The client code is Jersey-based, as well. The problem I'm running into is I don't want to deploy the JAR file to the web server every time I make a change and want to test -- the web server is on a remote server and I"m coding on a local computer.
Is it possible to simulate a client-server web service call completely within the IDE (i.e. Eclipse)? In other words, I want to call the web service from my
local computer, without having to host it on a web server; no different than
calling a function.
Here is the client code:
package com.xyzcorp.webservices;
import javax.ws.rs.core.MediaType;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
public class RestClient {
public static void main(String[] args) {
Client client = Client.create();
/*
Right now, it's calling the web service on the web server.
I want to call this same web service but from within the code local
to my computer, without hosting it on a web server.
*/
WebResource webResource = client.resource("http://myserver.com/rest/ids/12345");
ClientResponse response = webResource.accept(MediaType.APPLICATION_JSON).get(ClientResponse.class);
if (response.getStatus() != 200) {
throw new RuntimeException("Failed : HTTP error code : " + response.getStatus());
}
}
}
Here is the web service code:
package com.xyzcorp.webservices;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import com.xyzcorp.webservices.EmpData;
#Path("/rest")
public class RestWebService {
#GET
#Path("/ids/{ids}")
#Produces(MediaType.APPLICATION_JSON)
public EmpData getEmpDataJSON(
#PathParam("ids") String ids)
...
return empData;
}
}
Is it possible to call the RestWebService class directly without having to use a web server? I.e. `WebResource webResource = client.resource(new RestWebService().EmpData("12345"));
Thank you very much.
Use Jersey Test Framework. Run (semi) Integration/Unit tests on your resources like you would a normal unit test. For example
public class MainTest extends JerseyTest {
public MainTest() throws Exception {
super("com.sun.jersey.samples.helloworld.resources");
}
#Test
public void testHelloWorld() {
WebResource webResource = resource();
String responseMsg = webResource.path("helloworld").get(String.class);
assertEquals("Hello World", responseMsg);
}
}
The JerseyTest will start and stop an embedded server for each test case. It could even be an in memory server (so as not to take so much load time) depending on what server dependency you want to use. Here's an example dependency
<dependency>
<groupId>com.sun.jersey.jersey-test-framework</groupId>
<artifactId>jersey-test-framework-grizzly2</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
The link I provided shows other dependencies you can use.
Here is another example usage (the bottom part is for Jersey 1.x - the top is 2.x)
This might be of use to you:
http://www.eclipse.org/webtools/community/education/web/t320/Implementing_a_Simple_Web_Service.pdf
particularly page 12 onwards.
Hope it helps.
EDIT : just in case, your machine URL will contain "localhost" for services running on your local computer.

Java SOAP client using SOAP UI library and WSDL file

I'm trying to build a Java based SOAP client which imports a WSDL file and sends a request to the end point specified in the WSDL. I'm currently using the SOAP UI library and while it can compile, it is connecting to the wrong endpoint. In addition, I'm not sure where/how I define the authentication credentials (user/pass).
I am using a base code found on this site but this doesn't include authentication. It is also getting the endpoint from the wrong attribute when I run the code. Please help!
package com.bbog.soap;
import com.eviware.soapui.impl.wsdl.WsdlInterface;
import com.eviware.soapui.impl.wsdl.WsdlOperation;
import com.eviware.soapui.impl.wsdl.WsdlProject;
import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlImporter;
import com.eviware.soapui.model.iface.Operation;
public class WsdlAnalyzer {
public static void main(String[] args) throws Exception {
WsdlProject project = new WsdlProject();
WsdlInterface[] wsdls = WsdlImporter.importWsdl(project, "file:/home/asarkar/Documents/EthocaAlerts-Sandbox.wsdl");
WsdlInterface wsdl = wsdls[0];
for (Operation operation : wsdl.getOperationList()) {
WsdlOperation op = (WsdlOperation) operation;
System.out.println("OP:"+op.getName());
System.out.println(op.createRequest(true));
System.out.println("Response:");
System.out.println(op.createResponse(true));
}
}
}

Why is ServletTester in Jetty 9.x so slow?

Jetty's ServletTester is pretty useful for testing Servlet apps. I have used Jetty 6's ServletTester before and it worked perfectly.
For example:
Jetty 6.x
pom.xml
<dependency>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-servlet-tester</artifactId>
<version>6.1.26</version>
<scope>test</scope>
</dependency>
SampleServletTest.java
package example;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import org.mortbay.jetty.testing.HttpTester;
import org.mortbay.jetty.testing.ServletTester;
public class SampleServletTest {
#Test
public void testDoGet() throws Exception {
ServletTester tester = new ServletTester();
tester.addServlet(SampleServlet.class, "/index");
tester.start();
HttpTester request = new HttpTester();
request.setMethod("GET");
request.setHeader("Host", "tester"); // should be "tester"
request.setURI("/index");
request.setVersion("HTTP/1.1");
request.setContent("");
String responses = tester.getResponses(request.generate());
HttpTester response = new HttpTester();
response.parse(responses);
assertThat(response.getStatus(), is(equalTo(200)));
}
}
Jetty 9.x
ServletTester's APIs are much improved in Jetty 9.x.
pom.xml
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<version>9.0.7.v20131107</version>
<scope>test</scope>
</dependency>
SampleServletTest.java
package example;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import org.eclipse.jetty.http.HttpTester;
import org.eclipse.jetty.servlet.ServletTester;
public class SampleServletTest {
#Test
public void testDoGet() throws Exception {
ServletTester tester = new ServletTester();
tester.addServlet(SampleServlet.class, "/index");
tester.start();
HttpTester.Request request = HttpTester.newRequest();
request.setMethod("GET");
request.setHeader("Host", "tester"); // should be "tester"
request.setURI("/index");
request.setVersion("HTTP/1.1");
request.setContent("");
HttpTester.Response response = HttpTester.parseResponse(tester.getResponses(request.generate()));
assertThat(response.getStatus(), is(equalTo(200)));
}
}
New API looks very cool but unfortunately above code runs much slowly... This code takes 10 seconds to run every time. Can you believe it?
Is there anyone who has knowledge of this issue? If this is just my mistake, it's very good news.
This is normal behavior for the request configuration you have.
It has to do with HTTP persistent connections.
Jetty 6's servlet tester defaulted to HTTP/1.0 behavior.
HTTP/1.0 has no official specification for persistent connections, but clients have evolved over the years to adopt a non-persistent behavior, which can be overridden with a negotiated Connection header.
With HTTP/1.0, its 1 request, then 1 response, then connection is closed. Unless the client sends a Connection: Keep-Alive header (and the server responds with the same header)
Jetty 9's HttpTester also defaults to HTTP/1.0.
You specified request.setVersion("HTTP/1.1"); in your example, where all connections are considered persistent unless declared otherwise. So adding Connection: close will force the server to close the connection after the response has been sent, not waiting for another request.
So you have 2 options here:
Stick with HTTP/1.1 and also add request.setHeader("Connection", "close");
or downgrade your HTTP version to 1.0. using either:
request.setVersion("HTTP/1.0");
or comment out the call to request.setVersion(); and rely on default behavior.

MessageBodyWriter not found for media type=Application/json, glassfish

I'm using JAX-RS to create simple restful json my first method work fine but when I add 2nd to get all vendorNOS"ID" method I have this exception when I view the in browser I also debug the Restful service and it work fine it gell all vendorNOS"ID"
my output from vendorFacadeBean is {1,2,3,4,5,6,11,13}
HTTP Status 500 - Internal Server Error
type Exception report
messageInternal Server Error
descriptionThe server encountered an internal error that prevented it from fulfilling this request.
exception
javax.servlet.ServletException: org.glassfish.jersey.message.internal.MessageBodyProviderNotFoundException: MessageBodyWriter not found for media type=Application/json, type=class java.util.Vector, genericType=java.util.List<java.lang.Integer>.
root cause
org.glassfish.jersey.message.internal.MessageBodyProviderNotFoundException: MessageBodyWriter not found for media type=Application/json, type=class java.util.Vector, genericType=java.util.List<java.lang.Integer>.
note The full stack traces of the exception and its root causes are available in the GlassFish Server Open Source Edition 4.0 logs.
GlassFish Server Open Source Edition 4.0
java source code
package resources;
import case2dtos.VendorEJBDTO;
import case2ejbs.VendorFacadeBean;
import java.util.List;
import javax.ejb.EJB;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.PathParam;
import javax.ws.rs.Consumes;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.GET;
import javax.ws.rs.Produces;
import javax.enterprise.context.RequestScoped;
/**
* REST Web Service
*
* #author abdallaelnajjar
*/
#Path("vendors")
#RequestScoped
public class VendorsResource {
#EJB
private VendorFacadeBean vendorFacadeBean;
#Context
private UriInfo context;
/**
* Creates a new instance of VendorsResource
*/
public VendorsResource() {
}
/**
* Retrieves representation of an instance of resources.VendorsResource
* #return an instance of java.lang.String
*/
#GET
#Path("getAVendor/{vendorno}")
#Produces("Application/json")
public VendorEJBDTO getAVendor(#PathParam("vendorno")int vendorno)
{
return vendorFacadeBean.getVendorInfo(vendorno);
}
/**
* Retrieves representation of an instance of resources.VendorsResource
* #return an instance of java.lang.String
*/
#GET
#Path("getVendornos")
#Produces("Application/json")
public List<Integer> getVendornos()
{
List<Integer> vendornosList = null;
try
{
vendornosList = vendorFacadeBean.getVendorsnos();
}
catch(Exception e)
{
System.out.println(e.getMessage());
}
return vendornosList;
}
}
Use genson (https://code.google.com/p/genson/downloads/list) jar and add this to class path. This will convert any object to json format. You get this error because you do not have a json provider. And it is better to return object rather than toString().
As well as you can use JAXB jar which comes with jersey bundle. This will support both XML and JSON. You can find the jar inside /ext folder of jersey distribution.
I solved it by adding the following dependency.
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-moxy</artifactId>
<version>2.17</version>
</dependency>
I am using jersey-spring3, jersey 2 and spring4.
The problem seems with List<Integer> that you are returning from second method.
Are you seeing error like the following?
javax.ws.rs.WebApplicationException: com.sun.jersey.api.MessageException: A message body writer for Java class java.util.ArrayList, and Java type class java.util.ArrayList, and MIME media type application/xml was not found
Please refer to GenericEntity. Moreover this seems duplicate.

Categories