How to use jackson mixin on Jersey REST services method parameters - java

I had Jackson deserializing problem of one of my java class which is come from third party API that doesn't have default constructors.To overcome that issue i used JacksonMixIn and it worked fine.But the problem was that i have a REST endpoint implemented on Jersey API which is accepted one of above mentioned classes as a method parameter from client side to server side.So when deserializing it throws me following error.
No suitable constructor found for type [simple type, class net.rcarz.jiraclient.Priority]: can not instantiate from JSON object (need to add/enable type information?)
at [Source: org.glassfish.jersey.message.internal.EntityInputStream#558e8ae; line: 1, column: 454]...
Affected classes
public class TestCaseVO{
private Priority priority;
private User reporter;
}
public class Priority {
protected Priority(RestClient restclient, JSONObject json) {
super(restclient);
if (json != null)
deserialise(json);
}
}
This is the object used to communicate client to server
public class myDataObject{
private String userName;
private List<TestCaseVO> testCases;
//Getter and setters
}
Jersey Endpoint
#POST
#Path("/bug")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public TestCaseVO attachBugForTestCase(myDataObject myDataObject){
// when deserializing to MyDataObject it thorows above error
//Handle logic
}
Client side code snippet
var myDataObject= {
"testCases": [$scope.bug.TestCaseVO],
"userName":userName}
angularJsMyService.Bug.attachBug({},myDataObject)
.$promise.then(function(data){
...
}
My question is that how can i use Jackson mixin on REST methods parameters prior to Jackson deserializing them.Appreciate any help.

I guess you probably didn’t integrate Jackson with Jersey in the right way. Check out Jersey’s doc on Jackson. In your project, there should be a class implementing ContextResolver<ObjectMapper>. The ObjectMapper instance returned by getContext(Class<?> type) in this class is used by Jersey’s REST endpoints. You may to configure that ObjectMapper with your Mix-in.

Related

How to use #NotNull?

I have a Spring Boot app using Jackson. I'm not using Jersey just regular Spring MVC. I have a Wrapper Request class:
public class WrapperRequest {
#NotNull
private final Object obj; // some object that corresponds with a JSON object
#JsonCreator
public WrapperRequest(#JsonProperty("wrapper") final Object obj) {
this.obj = obj;
}
public Object getObj() {return obj}
}
The JSON for this would look like:
{
"wrapper":{
//Object data
}
}
The #NotNull from javax isn't working as I excepted. The way I want it to work is that if the consumer sends in a JSON that have a typo like:
{
"wrapperr":{
//Object data
}
}
Jackson will not map my wrapper class because the key in the JSON doesnt match the JsonProperty i.e ("wrapper") (so Object will be null and then I will get NPE later on if I tried to interact with Object. Am I using Jackson wrong? i.e Jackson maps things that it knows about and the rest is null or am I not using the #NotNull annotation correctly?
Jackson is not aware of Bean Validation annotations like #NotNull. For the specific case of "null", you can mark the constructor parameter as #JsonProperty(required = true). More generally, you can use #NotNull on a property as you did and mark your MVC controller parameter with #Valid (which will not cause deserialization to fail but will cause Spring MVC to return a 400 if the validation fails).
Note that you may also be interested in the UNWRAP_ROOT_VALUE feature, which would allow you to eliminate the need for the wrapper class in this particular case.

Serve image/file in json

assume that I have class like this
public class Entity {
private String name;
private File file;
// Getters & setters
}
is it possible to return object of this class as json? I'm using jax-rs
Yes, you can.
If you're using JAX-RS, then I expect you to know the basic of creating a REST-ful Web Services ya.
You can use #Produces("application/json") annotation in one of your endpoint. Use that endpoint to return an Entity, and it will be automatically converted as JSON.

Where to register custom ObjectMapper for my REST Service application?

I am building a REST service application with Spring and Jersey.
The "Response Content Type" can be either JSON or XML, which is why I use JAXB annotations on the fields of my POJO, which works great so far. No configuration was needed to get this to work, I just put the required .jars on the classpath.
Now, I want to add custom behaviour for (de-)serialization of Java 8 Date/Time objects and register the JavaTimeModule from Jackson.
Where would be the right place to register the Module? I know the code snippet is supposed to look something like this:
ObjectMapper tmpMapper = new ObjectMapper();
tmpMapper.registerModule(new JavaTimeModule());
But where do I actually put this code?
The place that comes to mind is my ResourceConfig class from Jersey. It looks like this:
#ApplicationPath("/rest")
public class ApplicationResourceConfig extends ResourceConfig {
public ApplicationResourceConfig() {
// Not needed because since jersey 2.9 JacksonFeature implements AutoDiscoverable
// register(JacksonFeature.class);
register(WadlFeature.class);
// Registers our own request listener for monitoring purposes
register(RestServiceApplicationEventListener.class);
// Registers the package that contains our REST resources
packages(PingResource.class.getPackage().getName());
}
What I did now was to add the following lines at the bottom of the constructor:
ObjectMapper tmpMapper = new ObjectMapper();
tmpMapper.registerModule(new JavaTimeModule());
JacksonJaxbJsonProvider tmpProvider = new JacksonJaxbJsonProvider();
tmpProvider.setMapper(tmpMapper);
register(tmpProvider);
The DateTime conversion now worked. However, some of the the JAXB behaviour changed which caused the deserialization of other beans to break. Here is what is not working anymore:
I have super class which defines a getter of a field:
public abstract class SuperClass {
#XmlElement(name = "yourField")
public abstract String getMyField();
}
(This maps the internal name of the field to different name which is exposed to the outside)
public class SubClass {
private String myField;
#Override
public String getMyField() {
return myField;
}
}
This mechanism used to work before and I could e.g. define a POST parameter of type SubClass calling the method with a JSON snippet that looks like this:
{
"yourField" : "hello world"
}
When trying this now I get the exception:
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "yourField" (class com.myProject.SubClass), not marked as ignorable (1 known property: "myField"])
at [Source: org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$UnCloseableInputStream#728b1889; line: 4, column: 14] (through reference chain: com.myProject.Subclass["yourField"])
Note however, that the basic JAXB features still work, only in this particular superclass/subclass example.
Could it be that explicitly registering a JacksonJaxbJsonProvider somehow altered the default behaviour on how to deal with JAXB annotated beans? Is there a way to maybe retrieve the existing JacksonJaxbJsonProvider (that must have been registered implicitly somehow) or the existing ObjectMapper object and register the JavaTimeModule to it instead of creating a new Mapper object and a new Provider object?

Using Retrofit / GSON how can I handle responses that are sometimes empty and other times not

I am using retrofit with GSON. The web service I am connecting to will at times return an empty payload to the client. I didn't build it this way. The problem is that this causes a json parse exception when GSON tries to parse the empty payload. How could I handle this? Is there a way to make the callback have an null model object?
So for example the server response might be "" or it might be:
{
"foo":{"id":"123","description":"abcd"}
}
I also have in java:
#Data // This comes from lombok to generate setter,getter,no args constructor...
public class Foo{
private int id;
private String description;
}
My retrofit service looks like this:
public interface MyService{
#POST("/poorly/designed/api/foo")
void getFoo(#Header("Authorization") String auth, Callback<Foo> callback);
}
Disclamer: I just typed up the most simple example I could so forgive me if I wrote something that might not be exactly syntactically correct. You get the picture.
Retrofit should generally just null out any missing values. The problem with your code is that the server returns an object with a Foo inside rather than just a Foo. Try adding another class
class FooContainer {
Foo foo;
}
and then have your API call return a FooContainer instead of a Foo.

Deserialize JSON to Map<String,String> using jackson databind

I'm using spring 4.0.5.RELEASE and jackson-databind 2.2.3 in my web application.
When sending this JSON:
{"keyField1":"57579","keyField2":"sdf","someField":"sdasd","parameters":[{"parameterName":"dfgdfg","parameterValue":"sdf"},{"parameterName":"erwer","parameterValue":"sdfsdf"}]}
to the controller all I get is a HTTP 400 Bad Request at browser,
I don't see any error at local websphere log, but after some tests I saw that the problem is with deserialization of the JSON array to the map.
I never get into the save method at the controller.
Tried some annotation like #JsonDeserialize(as=HashMap.class) without success.
How can I resolve this?
My POJO:
class MyClassId implements Serializable {
private static final long serialVersionUID = 5022985493208399875L;
String keyField1;
String keyField2;
}
#Entity
#IdClass(MyClassId.class)
public class MyClass {
#Id
String keyField1;
#Id
String keyField2;
String someField;
#ElementCollection
#MapKeyColumn(name="parameterName")
#Column(name="parameterValue", length=400)
Map<String, String> parameters;
... Getters and Setters ...
My controller:
#RestController
#RequestMapping("/myclass/**")
public class MyClassController {
#Transactional
#RequestMapping(value = "/save", method = RequestMethod.POST, consumes={"application/json"})
public #ResponseBody ServiceResponce<MyClass> save(#RequestBody MyClass processToSave) {
... Code ...
}
}
I see two solutions to your problem:
You distinguish the entity class that is persistent to the representation class that is sent back to the client. The drawback is that you need to make the representation creation explicitely in your code from the entity
If you use Jackson to serialize your response in the respone (JSON, ...), you can leverage it feature "custom serializer" to adapt the structure of the returned payload according to your needs. See this answer for more details:
Spring 3.2 and Jackson 2 custom object mapper - Spring 3.2 and Jackson 2: add custom object mapper
Register a custom Jackson ObjectMapper using Sprint JavaCconfig - http://magicmonster.com/kb/prg/java/spring/webmvc/jackson_custom.html
Restlet Complex Object to XML serializaton - Restlet Complex Object to XML serializaton
Hope it helps you,
Thierry
In the JSON, parameters is not an object but an array of objects:
"parameters":[{"parameterName":"dfgdfg","parameterValue":"sdf"}, ...
You can not map this on a
Map<String, String> parameters;
Use at least
List<Map<String, String>> parameters;

Categories