Here i am listing some json to pojo convertion java api's
GSon
Jackson
JSONGen
JSON Tools
Can you please list out these api's according their performance and ease of use. Also let me know if there is any other java api which is better than the above
Mainly this depends on the context of what kind of app are you developing, and it it is in the client side (for example, Android) or in the server side (for example, SpringMVC). This is my experience, maybe someone has more points to prove that me. I always use Jackson in SpringMVC servers, why?, because It's simple, when you're developing a RESTfull webservices you leave to SpringMVC the managment of the system such as redirect requests, perform the bussiness logic, and more. You will have then two servlets one to manage the page request such as go to http://myserver.com/home/myprofile/ and another servlet to expose an RESTfull api, this is where Jackson enter, as you know (or maybe not) all the webapps that run in Tomcat has an web.xml, here you tell to the Tomcat instance who servlet It's gonna to handle what request, checkout this example:
<!-- Spring MVC Dispatcher Servlet -->
<servlet>
<servlet-name>SpringMvcServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:config/applicationContext.xml
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>SpringMvcServlet</servlet-name>
<url-pattern>/home/*</url-pattern>
</servlet-mapping>
<!-- Jersey -->
<servlet>
<servlet-name>jersey-serlvet</servlet-name>
<servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>ar.com.kimboo.server.rest</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jersey-serlvet</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
Jersey It's a library that uses Jackson to serialize/deserialize HttpRequest. Note that all the request to /home/* are handled by SpringMVC and all request to /rest/* are handled by Jersey. So when you hit something like hit to "http://server.com/server/rest/animals/" and the request It's delivered to:
#Component
#Path("/animals")
public class AdvertisingRESTServiceImpl {
#Autowired AnimalServiceImpl animalsService;
/**
* #return All animals in the db.
* #uri http://localhost:8080/server/rest/animals/
*/
#GET #Path("/") #Produces(MediaType.APPLICATION_JSON)
public #ResponseBody List<Animals> getAllAnimals() {
return animalsService.getAllAnimals();
}
}
You can return a collection of Objects and Jersey will take care of serialize them. Everything behind scene without configure nothing but some xml. Sure you can use another libraries to serialize json in the server side like GSON. But you have to implmenet your own HttpMessageConverter (this class takes care of serialize/deserialize the json) what Jersey already had.
Always that I work in the client side (Android) I use gson to serialize/deserialize json from the server side. I prefer used Gson because It's pretty simple you, rather than use RestTemplate or some library. The only thing that I need do with Gson is... nothing:
This turn an object instance into json:
String json = new Gson().toJson(new Puppy("Robert",2));
And this turns a json into an object:
Animal robert = new Gson().fromJson("{name:\"Robert\",age:\"2\"}", Animal.class);
With this kind of tool you can do some cool Restfull http client, like this one:
public class HttpFuck {
Gson gson = new Gson();
public <T> T post(String url, Class<T> clazz, List<NameValuePair> parameters) {
// Create a new HttpClient and Post Header
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(url);
try {
// Add your data
httppost.setEntity(new UrlEncodedFormEntity(parameters));
// Execute HTTP Post Request
HttpResponse response = httpclient.execute(httppost);
StringBuilder json = inputStreamToString(response.getEntity().getContent());
T gsonObject = gson.fromJson(json.toString(), clazz);
return gsonObject;
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public <T> T get(String url, Class<T> clazz) {
// Create a new HttpClient and Post Header
HttpClient httpclient = new DefaultHttpClient();
HttpGet httppost = new HttpGet(url);
try {
// Execute HTTP Post Request
HttpResponse response = httpclient.execute(httppost);
StringBuilder json = inputStreamToString(response.getEntity().getContent());
T gsonObject = gson.fromJson(json.toString(), clazz);
return gsonObject;
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
// Fast Implementation
private StringBuilder inputStreamToString(InputStream is) throws IOException {
String line = "";
StringBuilder total = new StringBuilder();
// Wrap a BufferedReader around the InputStream
BufferedReader rd = new BufferedReader(new InputStreamReader(is));
// Read response until the end
while ((line = rd.readLine()) != null) {
total.append(line);
}
// Return full string
return total;
}
}
The bad news are that you have to wrap almost everything in an object. For example you cant do something like new Gson().fromJson(string, String.class). But It's pretty flexive, I strongly recommend it to use it in Android apps.
Well long story short, this is all that I know about json technologies, hope this helps you. :)
Related
I'm writing a JSX-RS based Spring+CXF client for a service that sends a simple response as below.
JSON : Response
{
"message": "Hey Karthik"
}
I have the following configuration in my spring.xml:
<jaxrs:providers>
<bean class="org.apache.cxf.jaxrs.provider.json.JSONProvider">
<property name="dropRootElement" value="true" />
</bean>
</jaxrs:providers>
My entity class looks like this
#XmlRootElement
public class HiModel {
private String message;
public HiModel(){}
.
.
.
}
My JAX-RS client is like this:
#Test
public void getMessage(){
WebClient client = WebClient.create("http://localhost:8182");
client.path("hiService/sayHi/hi");
client.type(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON);
Response r = client.get();
System.out.println(r.readEntity(HiModel.class));
}
I get the error : No message body reader has been found for class com.karthik.model.HiModel, ContentType: application/json
How do I resolve it? There are lots of questions with the method I chose to write as client, but I first need to get this resolved. Please help.
EDIT 1 : I can resolve it by
System.out.println(r.readEntity(String.class));
But, How do I resolve it with the entity as HiModel.class
In case it helps someone. I had similar scenario, and I managed to solve it using Jackson JSON library. Using your example:
WebClient client = WebClient.create("http://localhost:8182/hiService/sayHi/hi");
Response r = client.accept("application/json").get();
MappingJsonFactory factory = new MappingJsonFactory();
JsonParser parser = factory.createJsonParser((InputStream)r.getEntity());
HiModel hiModel= parser.readValueAs(HiModel.class);
Very similar test is actually present within Apache CXF JAX-RS archetype.
Add it to the webclient object.
List<Object> providers = new ArrayList<>();
// add custom providers if any
providers.add(new JacksonJaxbJsonProvider());
WebClient client = WebClient.create(ENDPOINT_ADDRESS,providers);
If you are not using spring to configure cxf then:
1) in Web.xml
<servlet>
<display-name>CXFNonSpringJaxrsServlet</display-name>
<servlet-name>CXFNonSpringJaxrsServlet</servlet-name>
<servlet-class>org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet
</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>
com.jaxrs.JaxRsConfigApplication
</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>CXFNonSpringJaxrsServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
2) On the JaxRsConfigApplication.java
public class JaxRsConfigApplication extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> resources = new HashSet<>();
resources.add(ServicioPistaRest.class);
resources.add(ConsultarDatosSolicitud.class);
return resources;
}
#Override
public Set<Object> getSingletons() {
Set<Object> classes = new HashSet<>();
JacksonJaxbJsonProvider jacksonJaxbJsonProvider = new JacksonJaxbJsonProvider();
classes.add(jacksonJaxbJsonProvider);
return classes;
}
}
I have a Jersey (2.14) application, which works all right. I have some services running there. Now I'd like to configure the ServletContainer so, that any not catched Exceptions should be intercepted and logged or emailed somewhere.
I have already an implementation of ApplicationEventListener and a test endpoint for generating an exception.
This is the method, which should generate an exception (this is working :-) :
#GET
#Path(TEST_EXCEPTION)
public String testException(#Context final ServletContext context) {
String s = null;
int size = 0;
if (System.nanoTime() % 10 != 0) {
s = null;
} else {
s = "No exception will occur";
}
size = s.length();
return Integer.toString(size) + ":" + s;
}
And this is the implementation if my ApplicationEventListener:
public class MyApplicationEventListener implements ApplicationEventListener {
private transient volatile int count = 0;
private int exceptions = 0;
#Override
public void onEvent(final ApplicationEvent applicationEvent) {
ApplicationEvent.Type type = applicationEvent.getType();
}
#Override
public RequestEventListener onRequest(final RequestEvent requestEvent) {
RequestEvent.Type type = requestEvent.getType();
if (type == RequestEvent.Type.ON_EXCEPTION) {
exceptions++;
}
count++;
return null;
}
}
And this the configuration in my web.xml:
<servlet>
<servlet-name>jersey-servlet</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>com....rest</param-value>
</init-param>
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>
com....filter.MyApplicationEventListener
</param-value>
</init-param>
<init-param>
<param-name>jersey.config.server.tracing</param-name>
<param-value>ALL</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
onEvent() and onRequest() are both been called, but when an Exception happens, I don't get a ON_EXCEPTION, but a START.
What am I doing wrong? Or how can I get all exceptions resulting from the methods of my Jersey service?
I'd like to have/make something like Spring's HandlerExceptionResolver.
You can do this pretty easy with an ExceptionMapper. If an exception occurs you still should send a response back to the client. But in here you could also send an email message or log a ticket etc.
Here is an example that I did for ConstraintViolations but this can be an exception mapper for type Exception. You can check the type of the exception and do something accordingly. In the toResponse you could implement a notfiyEmail method that could send the stack trace and messge to an email address for example or log a jira ticket which I have done in the past. Note though that you need to add the #Provider at the top and tell your rest Application/ResourceConfig to scan the package for this class. Alternatively you can register it manually with your ResourceConfig.
#Provider
public class ConstraintViolationExceptionMapper implements ExceptionMapper<ConstraintViolationException> {
private static final Logger logger = Logger.getLogger(ConstraintViolationExceptionMapper.class.getName());
public Response toResponse(ConstraintViolationException exception) {
final int violationCount = exception.getConstraintViolations().size();
ConstraintViolation<?>[] constraintViolations = exception.getConstraintViolations().toArray(
new ConstraintViolation<?>[violationCount]);
Violation[] violations = new Violation[exception.getConstraintViolations().size()];
for (int i = 0; i < violationCount; i++) {
ConstraintViolation<?> cv = constraintViolations[i];
Violation violation = new Violation(cv.getPropertyPath().toString(), cv.getMessage());
violations[i] = violation;
}
ConstraintErrorResponse responseEntity = new ConstraintErrorResponse();
responseEntity.setViolations(violations);
logger.info("Seinding exception response");
return Response.status(Response.Status.BAD_REQUEST).entity(responseEntity).build();
}
}
...when an Exception happens, I don't get a ON_EXCEPTION, but a
START.
What am I doing wrong?
You need to return an instance of RequestEventListener from the START event, rather than returning null, in order to tell Jersey to carry on firing events for the request.
From 21.1.2. Event Listeners :
The second method onRequest is invoked by Jersey runtime every time a
new request is received. The request event type passed to the method
is always START. If you want to listen to any other request lifecycle
events for the new request, you are expected to return an instance of
RequestEventListener that will handle the request.
See https://stackoverflow.com/a/33271754/5473824 for an example which logs exception events.
I am developing a REST service using SpringMVC, where I have #RequestMapping at class and method level.
This application is currently configured to return error-page jsp configured in web.xml.
<error-page>
<error-code>404</error-code>
<location>/resourceNotFound</location>
</error-page>
I however want to return custom JSON instead of this error page.
I am able to handle exception and return json for other exceptions, by writing this in controller, but not sure how and where to write the logic to return JSON when the url does not exist at all.
#ExceptionHandler(TypeMismatchException.class)
#ResponseStatus(value=HttpStatus.NOT_FOUND)
#ResponseBody
public ResponseEntity<String> handleTypeMismatchException(HttpServletRequest req, TypeMismatchException ex) {
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json; charset=utf-8");
Locale locale = LocaleContextHolder.getLocale();
String errorMessage = messageSource.getMessage("error.patient.bad.request", null, locale);
errorMessage += ex.getValue();
String errorURL = req.getRequestURL().toString();
ErrorInfo errorInfo = new ErrorInfo(errorURL, errorMessage);
return new ResponseEntity<String>(errorInfo.toJson(), headers, HttpStatus.BAD_REQUEST);
}
I tried #ControllerAdvice, it works for other exception scenarios, but not when mapping is not avaialble,
#ControllerAdvice
public class RestExceptionProcessor {
#Autowired
private MessageSource messageSource;
#ExceptionHandler(HttpRequestMethodNotSupportedException.class)
#ResponseStatus(value=HttpStatus.NOT_FOUND)
#ResponseBody
public ResponseEntity<String> requestMethodNotSupported(HttpServletRequest req, HttpRequestMethodNotSupportedException ex) {
Locale locale = LocaleContextHolder.getLocale();
String errorMessage = messageSource.getMessage("error.patient.bad.id", null, locale);
String errorURL = req.getRequestURL().toString();
ErrorInfo errorInfo = new ErrorInfo(errorURL, errorMessage);
return new ResponseEntity<String>(errorInfo.toJson(), HttpStatus.BAD_REQUEST);
}
#ExceptionHandler(NoSuchRequestHandlingMethodException.class)
#ResponseStatus(value=HttpStatus.NOT_FOUND)
#ResponseBody
public ResponseEntity<String> requestHandlingMethodNotSupported(HttpServletRequest req, NoSuchRequestHandlingMethodException ex) {
Locale locale = LocaleContextHolder.getLocale();
String errorMessage = messageSource.getMessage("error.patient.bad.id", null, locale);
String errorURL = req.getRequestURL().toString();
ErrorInfo errorInfo = new ErrorInfo(errorURL, errorMessage);
return new ResponseEntity<String>(errorInfo.toJson(), HttpStatus.BAD_REQUEST);
}
}
After digging around DispatcherServlet and HttpServletBean.init() in SpringFramework I see that its possible in Spring 4.
org.springframework.web.servlet.DispatcherServlet
/** Throw a NoHandlerFoundException if no Handler was found to process this request? **/
private boolean throwExceptionIfNoHandlerFound = false;
protected void noHandlerFound(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (pageNotFoundLogger.isWarnEnabled()) {
String requestUri = urlPathHelper.getRequestUri(request);
pageNotFoundLogger.warn("No mapping found for HTTP request with URI [" + requestUri +
"] in DispatcherServlet with name '" + getServletName() + "'");
}
if(throwExceptionIfNoHandlerFound) {
ServletServerHttpRequest req = new ServletServerHttpRequest(request);
throw new NoHandlerFoundException(req.getMethod().name(),
req.getServletRequest().getRequestURI(),req.getHeaders());
} else {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
}
}
throwExceptionIfNoHandlerFound is false by default and we should enable that in web.xml
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>throwExceptionIfNoHandlerFound</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
And then you can catch it in a class annotated with #ControllerAdvice using this method.
#ExceptionHandler(NoHandlerFoundException.class)
#ResponseStatus(value=HttpStatus.NOT_FOUND)
#ResponseBody
public ResponseEntity<String> requestHandlingNoHandlerFound(HttpServletRequest req, NoHandlerFoundException ex) {
Locale locale = LocaleContextHolder.getLocale();
String errorMessage = messageSource.getMessage("error.bad.url", null, locale);
String errorURL = req.getRequestURL().toString();
ErrorInfo errorInfo = new ErrorInfo(errorURL, errorMessage);
return new ResponseEntity<String>(errorInfo.toJson(), HttpStatus.BAD_REQUEST);
}
Which allows me to return JSON response for bad URLs for which no mapping exist, instead of redirecting to a JSP page :)
{"message":"URL does not exist","url":"http://localhost:8080/service/patientssd"}
If you are using Spring Boot, set BOTH of these two properties:
spring.resources.add-mappings=false
spring.mvc.throw-exception-if-no-handler-found=true
Now your #ControllerAdvice annotated class can handle the "NoHandlerFoundException", as below.
#ControllerAdvice
#RequestMapping(produces = "application/json")
#ResponseBody
public class RestControllerAdvice {
#ExceptionHandler(NoHandlerFoundException.class)
public ResponseEntity<Map<String, Object>> unhandledPath(final NoHandlerFoundException e) {
Map<String, Object> errorInfo = new LinkedHashMap<>();
errorInfo.put("timestamp", new Date());
errorInfo.put("httpCode", HttpStatus.NOT_FOUND.value());
errorInfo.put("httpStatus", HttpStatus.NOT_FOUND.getReasonPhrase());
errorInfo.put("errorMessage", e.getMessage());
return new ResponseEntity<Map<String, Object>>(errorInfo, HttpStatus.NOT_FOUND);
}
}
note it is not sufficient to only specify this property:
spring.mvc.throw-exception-if-no-handler-found=true
, as by default Spring maps unknown urls to /**, so there really never is "no handler found".
To disable the unknown url mapping to /**, you need
spring.resources.add-mappings=false ,
which is why the two properties together produce the desired behavior.
If you're using spring 3.2 or later you can use a controller advice (#ControllerAdvice) to deal with, amongst other things, mapping errors (404's). You can find documentation here. Take a look at section 17.11. You can use this, for example, to provide more detailed logging on why your request bindings aren't being matched for specific urls, or to simply return a more specific response than a generic 404.
you can return json in the location below,that /handle/404.
<error-page>
<error-code>404</error-code>
<location>/handle/404</location>
</error-page>
after you config this in web.xml,a 404 error will redirect to /handle/404,and you can create a controller with this mapping and return a json result. for example.
#RestController
#RequestMapping(value = "handle")
public class HttpErrorController {
#RequestMapping(value = "404")
public String handle404() {
return "404 error";
}
}
While implementing a File Uploader controller in Spring MVC I stucked with one problem. My code snap is given below.
#Controller
public class FileUploader extends AbstractBaseController implements HandlerExceptionResolver
{
#RequestMapping(value = "/uploadFile", method = RequestMethod.POST)
#ResponseBody
public JSONObject handleFileUpload(#RequestParam("file") MultipartFile file)
{
JSONObject returnObj = new JSONObject();
if (file.isEmpty())
{
returnObj.put("success", "false");
returnObj.put("message", "File is empty");
}
else
{
try
{
//my file upload logic goes here
}
catch (Exception e)
{
returnObj.put("success", "false");
returnObj.put("message", "File not uploaded.");
}
}
return returnObj;
}
#Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object obj, Exception exception)
{
ModelAndView model = new ModelAndView();
Map map = new HashMap();
if (exception instanceof MaxUploadSizeExceededException)
{
// I want to return JSONObject from here like given below.
/**
* { "message":"File size exceeded", "success":"false" }
* */
map.put("message", "File size exceeded");
map.put("success", "false");
model.addObject(map);
}
return model;
}
}
and my spring configuration look likes
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver" >
<property name="maxUploadSize" value="300000"/>
</bean>
now In my controller I want to return JSONObject instead of ModelAndView in resolveException method in my controller as given in code snap because I am developing some like REST method to upload file.
any ideas?
Thanks
If you use the Spring 3.2 above, I recommend this way.
At first, declare the ControllerAdvice.
#Controller
#ControllerAdvice
public class JAttachfileApi extends BaseApi
And make the Exception Handler to response JSON Object as following.
#ExceptionHandler(MaxUploadSizeExceededException.class)
public #ResponseBody Map<String,Object> handleMaxUploadSizeExceededException(
MaxUploadSizeExceededException ex)
{
Map<String,Object> result = getResult();
JFileUploadJsonResponse errorResult = new JFileUploadJsonResponse();
errorResult.setError("Maximum upload size of "+ex.getMaxUploadSize()+" bytes exceeded.");
List<JFileUploadJsonResponse> resultData = new ArrayList<JFileUploadJsonResponse>();
resultData.add(errorResult);
result.put("files", resultData);
return result;
}
You simply can annotate the method resolveException as #ExceptionHandler() and then you can have its signature like any other controller method. So placing #ResponseBody before the return type should work.
"Much like standard controller methods annotated with a #RequestMapping annotation, the method arguments and return values of #ExceptionHandler methods can be flexible. For example, the HttpServletRequest can be accessed in Servlet environments and the PortletRequest in Portlet environments. The return type can be a String, which is interpreted as a view name, a ModelAndView object, a ResponseEntity, or you can also add the #ResponseBody to have the method return value converted with message converters and written to the response stream."
I'm using apache httpcompnonents library for httpclient. I want to use it in a multithreaded application where number of threads are going to be really high and there would be frequent http calls. This is the code I'm using to read the response after execute call.
HttpEntity entity = httpResponse.getEntity();
String response = EntityUtils.toString(entity);
I just want to confirm that is it the most efficient way of reading the response?
Thanks,
Hemant
This in fact represents the most inefficient way of processing an HTTP response.
You most likely want to digest the content of the response into a domain object of a sort. So, what is the point of buffering it in-memory in a form of a string?
The recommended way to deal with response processing is by using a custom ResponseHandler that can process the content by streaming it directly from the underlying connection. The added benefit of using a ResponseHandler is that it completely relieves from dealing with connection release and resource deallocation.
EDIT: modified the sample code to use JSON
Here's an example of it using HttpClient 4.2 and Jackson JSON processor. Stuff is assumed to be your domain object with JSON bindings.
ResponseHandler<Stuff> rh = new ResponseHandler<Stuff>() {
#Override
public Stuff handleResponse(
final HttpResponse response) throws IOException {
StatusLine statusLine = response.getStatusLine();
if (statusLine.getStatusCode() >= 300) {
throw new HttpResponseException(
statusLine.getStatusCode(),
statusLine.getReasonPhrase());
}
HttpEntity entity = response.getEntity();
if (entity == null) {
throw new ClientProtocolException("Response contains no content");
}
JsonFactory jsonf = new JsonFactory();
InputStream instream = entity.getContent();
// try - finally is not strictly necessary here
// but is a good practice
try {
JsonParser jsonParser = jsonf.createParser(instream);
// Use the parser to deserialize the object from the content stream
return stuff;
} finally {
instream.close();
}
}
};
DefaultHttpClient client = new DefaultHttpClient();
Stuff mystuff = client.execute(new HttpGet("http://somehost/stuff"), rh);