I'm using Jersey for my RESTful services and Genson to perform my JSON/POJO conversion. There's no setup for Genson, I just drop it into the classpath and it just works, except that it throws an error on date parsing because the format is unexpected.
Now, if I were to do this as a servlet, using Gson, I set the date format on a Gson instance that I maintain. That forces the parse of the POJO to use the correct format. I see that Genson has a similar interface, but I don't know how to get the instance from the Jersey servlet service or maybe the Spring context so that I cat set the format.
So, the short question is: how do I set a date format for Genson when started through Jersey?
To configure Genson instances you can use Genson.Builder class (it is similar to Gson on this point). Then you have to inject it with Jersey.
#Component
#Provider
public class GensonProvider implements ContextResolver<Genson> {
private final Genson genson = new Genson.Builder().setDateFormat(yourDateFormat).create();
#Override
public Genson getContext(Class<?> type) {
return genson;
}
}
You might also want to have a look at how Genson is integrated into Jersey here.
Related
I am trying to develop a microservice using Spring MVC and Spring Boot. In my service I am giving result back as JSON encoded format. Currently I added action like:
#RequestMapping("/checkUsers")
public String checkLogin() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
List<Users> useObj = (List<Users>) userRepo.findAll();
return(mapper.writeValueAsString(useObj));
}
And now I found the other options through the following method
produces={"application/json; charset=UTF-8"}
Here I am not sure which method is properly using for encoding the data into JSON format in Spring. How can I proceed?
Why don’t you just use
ResponseEntity
And return
new ResponseEntity<String>(“your message”, HttpStatus.OK);
#RequestMapping(method = GET, value = "my/random/uri", produces = "application/json;charset=UTF-8")
Here produces attribute inside my #RequestMapping annotation is the producible media types of the mapped request. The format is a single media type or a sequence of media types, with a request only mapped if mentioned one matches one of these media types. and here, my #RequestMapping annotation is already serving my purpose of encoding.
Now somewhere from Spring Boot documentation:
Spring Boot is a brand new framework designed to simplify the bootstrapping and development of a new Spring
application. The framework takes an opinionated approach to
configuration, freeing developers from the need to define boilerplate
configuration.
Please don't kill the purpose of Spring Boot. :)
Additionally, I would suggest you use org.springframework.http.MediaType class. It has got all encoding types you'll ever require. Happy coding.
Please let me know if you face any difficulty while going with suggested approach.
If you use #RestController on your controller, all request mappings will produce application/json by default.
Also, there is no need to to the object mapping yourself, just return the object without mapping and let Spring/Jackson do its thing.
#RestController
public class UsersController {
// #RequestMapping("/checkUsers")
// There is an even simpler and more concise
#GetMapping("/checkUsers")
public List<User> checkLogin() throws JsonProcessingException {
return userRepo.findAll();
}
}
I'm writing a command line app that needs to serialize/deserialize a json file but can't seem to find a non-web example. All the code I found is to do with Restful API and Web.
So the question is how to set up serializer/deserializer and map pojos to json in a Spring boot command line app. It'd be great if there is a sample unit test that shows how to set up its Spring content. I tried the code snippet in Spring boot docs using #JsonTest Auto-configured JSON tests but it complains of not finding matching implementation.
Many thanks
Take a look at the Jackson project, specifically the ObjectMapper.
https://github.com/FasterXML/jackson
https://fasterxml.github.io/jackson-databind/javadoc/2.7/com/fasterxml/jackson/databind/ObjectMapper.html
The simplest way would be to create an ObjectMapper as a bean, and use that throughout your project.
#Configuration
public class MyConfig() {
#Bean
public ObjectMapper objectMapper() {
return new ObjectMapper() ;
}
}
I want to know what is the rule followed by MappingJackson2HttpMessageConverter to convert the object (returned from controller method annotated by #ResponseBody) to a json? In some situations I see that just having Jackson2 on classpath (pom.xml) is enough and the controller simply returns back its object e.g. String or a collection e.g. List<Employee> successfully to browser in json format. But, in other cases I have seen that the solution asks me to use an ObjectMapper and use method writeValueAsString to get a string and return that as a response, example HashMaps! Are there some implicit rules which MappingJackson2HttpMessageConverter uses to decide if it is able to do the conversion on its own or I need to manually do it using Objectmapper ? If I have a pojo object, which internally has few String fields, would I still need to use ObjectMapper etc? If not then would I need it if my pojo class has fields like , some List<CustomObject> and some HashMaps?
For example : example 1 does not use any ObjectMapper to convert List<Company> to json in controller method. But, example 2 needs an ObjectMapper and writeValueAsString ? plus, it's return type now is String instead of a HashMap!
If you use #RestController and you have jackson in the class path everything will be handled OK. see https://spring.io/guides/gs/rest-service/ and https://www.leveluplunch.com/java/tutorials/014-post-json-to-spring-rest-webservice/
I have written a rest service API which returns a data structure in a kind of a map layout. The map entries can be from type String, Integer or Date. The rest service method supports XML and Json output.
Now I recognized that the JSON outcome in GlassFish (Jersey) is different as in Wildfly (Reas-Easy)
When running the rest servie on GlassFish with application/json the output looks like this:
{"entity":{"item":{"name":"$modified","value":{"#type":"xs:dateTime","$":"2015-02-17T22:33:57.634+01:00"}}}}
And the same result on WildFly (Rest-Easy) looks like this:
{"entity":[{"item":[{"name":"$modified","value":[1425822673120]}]}]}
Can anybody explain this behavior? I would expect that the output in WildFly should be simmilar to GlassFish?
The interesting thing is that When I call the same method with the request header 'application/xml' both systems return the same (expected) format.
GlassFish XML:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><collection xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<entity><item><name>$modified</name>
<value xsi:type="xs:dateTime">2015-02-17T22:33:57.634+01:00</value></item></entity></collection>
Wildfly XML:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><collection xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<entity><item><name>$modified</name>
<value xsi:type="xs:dateTime">2015-03-08T14:51:13.120+01:00</value></item></entity></collection>
Is there a way to configure the JSON Format for Rest-Easy?
It would help if we had the model classes to test, so we could see which providers produce which result (while testing). But without it, I'll just throw some things to consider
Glassfish by default uses MOXy for JSON/POJO support. I personally do not like using MOXy. At first I promoted it's usage, as it's recommended by Jersey, but after a while, you start to learn its limitations. Glassfish also ships with Jackson support, but we need to either disable MOXy explicitly, or just register a Jackson Feature (which is not portable) or a combination of diabling MOXy and adding a Jackson provider.
As far as Wildfly, one thing to consider as mentioned here in the Resteasy Documentation
21.6. Possible Conflict With JAXB Provider
If your Jackson classes are annotated with JAXB annotations and you have the resteasy-jaxb-provider [which Wildfly comes shipped with] in your classpath, you may trigger the Jettision JAXB marshalling code. To turn off the JAXB json marshaller use the #org.jboss.resteasy.annotations.providers.jaxb.IgnoreMediaTypes("application/*+json") on your classes.
Another thing to consider is that both servers come shipped with providers for both Jackson 1.x and Jackson 2.x. Which ever one used may not have a difference in the marshalling result, but is relevant to the next part of this answer (also see here - though this mentions JBoss AS7, I'm not sure if it applies to Wildfly. I think Wildfly uses Jackson 2 by default though).
One way to test which provider is being used is to create a ContextResolver. Now this next example is simply for testing purposes ( you wouldn't normally just add Jackson by itself, but the Jackson provider).
Add this dependency to your project
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.4.0</version>
</dependency>
Add this class
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;
#Provider
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public class ObjectMapperContextResolver implements ContextResolver<ObjectMapper>{
static final Logger logger
= Logger.getLogger(ObjectMapperContextResolver.class.getName());
final ObjectMapper mapper = new ObjectMapper();
#Override
public ObjectMapper getContext(Class<?> type) {
logger.log(Level.INFO, "<===== ***** Jackon 2 is used ***** =====>");
return mapper;
}
}
Result
Glassfish: Jackson 2 not being used
Wildfly: Jackson 2 is used (even with JAXB annotations. Maybe you need to explicitly have the resteasy-jaxb-provider explicitly on the project classpath for the Jettison to kick in).
So how can we fix Glassfish deployment, in a portable way? One way I was able to test and get Jackson 2 to be used on both servers, is to disable MOXy, by adding a server configuration property. This is portable as the property is nothing more than a string. It will be ignored by Resteasy.
#ApplicationPath("/rest")
public class AppConfig extends Application {
#Override
public Map<String, Object> getProperties() {
Map<String, Object> properties = new HashMap<>();
properties.put("jersey.config.disableMoxyJson", true);
return properties;
}
}
We'll also need to add the Jackson provider to the project
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.4.0</version>
</dependency>
Odd that we have to add this dependency, as Glassfish already comes shipped with it, but if I don't add it, I'll get a MessageBodyWiter not found.
This solution has been tested on Wildfly 8.1 and Glassfish 4.0
JAX-RS specifies the interface MessageBodyWriter for serializing your entities but this defines only that a Java Object is converted to an OutputStream. How the result looks like is up to you or the JAX-RS runtime.
Both, RESTeasy and Jersey ship with serializers for MediaTypes like application/json or application/xml and a default serializer which is used if no better one is found.
For serializing a Java Object to XML there is JAXB as standard so the result should not differ (too much). For JSON the situation is different, there is no explicit standard but a lot of serializers like e.g:
Jackson
Jettison
Genson
They all handle some things differently can be configured differently and changed behavior during their history.
To answer the last question: If you are using RESTeasy on Wildfly you are usually using Jackson and you can configure a lot. Here's an example.
Beware that the Jackson configuration options have been renamed from time to time.
Given this repository
#RepositoryRestResource( path = "u", itemResourceRel="ui", collectionResourceRel = "us")
public interface IUserRepository extends CrudRepository<Users, Long> {
}
When I go through a controller to call my service method findAllUsers(). I transform the
list of entities result (returned by userRepository.findAll() method provided for free) to a list of domain model objects. This list of domain model objects will get properly deserialize into JSON because I am controlling how to do the deserialization. There is a specific reason why I am doing this, see further below.
Now, if I want to use the userRepository directly, I am running into a loop during the serialization because the object being deserialized are coming from the library com.vividsolutions.jts.geom.Geometry. This class contains a method as described below
Geometry getEnvelope() Returns this Geometrys bounding box.
During the deserialization, jackson runs into a loop, because of it. I am able to correct the deserialization process within my controller. How could I intercept the deserialization from a CrudRepository?
The first idea that came to me was to create an implementation of my interface and override all methods, but it defeats the purpose of doing boiler-plate code.
You show the usage of #RepositoryRestResource I am assuming you're using Spring Data REST to export your repositories. For standard Spring MVC marshaling configuration see the reference docs.
Precisely speaking, you're not intercepting the repositories. Spring Data REST uses Jackson to marshal and unmarshal the responses and requests. Hence you simply customize the Jackson ObjectMapper that SD REST will use. To do so, you extend RepositoryRestMvcConfiguration and override configureJacksonObjectMapper(…):
class MyConfiguration extends RepositoryRestMvcConfiguration {
protected void configureJacksonObjectMapper(ObjectMapper mapper) {
// register custom serialializers, modules etc.
}
}
For customization options in general, have a look at the Jackson reference documentation.