I have a REST service that has a POST endpoint. This POST endpoint needs to receive an object (TravelRequisitionFormDTO) as part of its body:
#POST
#Path("/request")
#ApiOperation(value="Request a trip. Submit the trip request.")
#ApiResponses({
#ApiResponse(code=200, message="Success"),
#ApiResponse(code=404, message="Not Found")
})
#Produces({ MediaType.APPLICATION_JSON })
public Response getSubmitTrip(#HeaderParam("Authorization") String token, #ApiParam(required = true) TravelRequisitionFormDTO travelRequisitionFormDTO, #Context HttpServletRequest request) {
...
}
So when I call the endpoint, I get the following error:
<p><b>message</b> <u>org.codehaus.jackson.map.JsonMappingException: Conflicting setter definitions for property
"contactMethods": utility.dataobjects.ContactObject#setContactMethods(1 params) vs
utility.dataobjects.ContactObject#setContactMethods(1 params)</u></p>
<p><b>description</b> <u>The request sent by the client was syntactically incorrect
(org.codehaus.jackson.map.JsonMappingException: Conflicting setter definitions for property
"contactMethods": utility.dataobjects.ContactObject#setContactMethods(1 params) vs
utility.dataobjects.ContactObject#setContactMethods(1 params)).</u></p>
The reason for the error is because the TravelRequisitionFormDTO has a member variable (called ContactObject) that has two methods that are overloaded. So when it tries to convert the JSON body to JAVA, I guess it does not know which overloaded method to use. I think it sees it as ambiguous.
public void setContactMethods(ArrayList list)
and
public void setContactMethods(String[] list)
I don't want to change ContactObject if possible, because it is used in a number of other places.
Question
Is there any way I can resolve this? i.e. so that the JSON body can be converted successfuly into the Java object?
you can keep single property accepting List. and your Contractobject can consume both Array & List.
You could annotate one setter with Jackson #JsonSetter annotation:
#JsonSetter
public void setContactMethods(ArrayList list)
Make sure that you use right package. In your case it would be org.codehaus.jackson.annotate.JsonSetter like you can see in the error message. It might happen that you have also com.fasterxml.jackson.annotation.JsonSetter in the classpath so you have to be careful not to mix it.
Alternatively you can use #JsonProperty instead.
Related
I am using Retrofit and Kotlin to build an API client. For accessibility, I will provide examples in Java.
There are a few methods in this API that require a JSON body with only one parameter. I made an annotation #SingletonBody(String) that tells a call adapter to wrap the argument in a Map<String,Object>.
For example, to rename an account we PUT a A simple json body.
curl -X PUT https://api.example.com/account/whatever -d '{ "name": "the new name for the account" }'
I want to pass a String name argument for simplicity rather than a Map. I could accomplish this by creating a default method that delegates to another method.
public interface AccountApi {
// Inconvenient delegate
#PUT("/accounts/{accountId}")
Call<Void> renameAccount(#Path("accountId") String accountId, #Body Map<String,Object> body);
// Convenient wrapper
default Call<Void> renameAccount(String accountId, String name) {
return renameAccount(accountId, Collections.singletonMap("name", name));
}
}
This felt messy to me. My #SingletonBody annotation allows me to declare only one method.
public interface AccountApi {
#PUT("/accounts/{accountId}")
Call<Void> renameAccount(#Path("accountId") String accountId,
#Body #SingletonBody("name") String name);
}
TL;DR
My #SingletonBody annotation necessarily implies Retrofit's #Body annotation. How can I tell the complier to infer #Body from #SingletonBody such that I don't need to write both? Perhaps with an annotation preprocessor?
My instinct was to extend Retrofit's annotation, but the JVM (Kotlin too) does not allow annotations to have explicit superclasses or superinterfaces.
I'm new to Jersey. So, please pardon any mistake.
I'm trying to setup a simple REST ws.
There is a method name getConnectedMHubs that have one required parameter thingID and two optional parameters: time and delta.
Is it possible to use the same method name for the two type of calls, with and without the optional parameters?
I tried to specify two pathes but got a ModelValidationException, that says:
A resource model has ambiguous (sub-)resource method for HTTP method
GET and input mime-types as defined by"#Consumes" and "#Produces"
annotations at Java methods public ...
Code sample:
#Path("/api")
public class RendezvousWebService {
#GET
#Produces(MediaType.APPLICATION_JSON)
#Path("connectedmhubs/{mhubid}")
public String getConnectedThings(#PathParam("mhubid") String strMHubID) {
// ...
return "{}";
}
#GET
#Produces(MediaType.APPLICATION_JSON)
#Path("connectedmhubs/{mhubid}/{time}/{delta}")
public String getConnectedThingsExtended(#PathParam("mhubid") String strMHubID, #PathParam("time") long timestamp, #PathParam("delta") long delta){
// ...
return "{}";
}
}
Using the #Path makes the params mandatory. You can get around this with regular expressions or you can use #QueryParam with #DefaultValue to roll the two methods into one.
Using a path pattern like this:
#Path("connectedmhubs/{mhubid}")
makes the path parameter mandatory. However, you can make use of regular expressions to overcome this limitation. See this link for details.
I need to use a response from a rest service returning JSON. However, one of the fields in the json response is the empty string. So, basically this:
{"wut":
{
"foo":"fooval",
"": "srsly"
}
}
So, I need to somehow translate this into a java class, as below:
#JsonIgnoreProperties(ignoreUnknown=true)
public class wut
{
#JsonProperty
private String foo;
#JsonProperty
private String <empty string???>;
//etc...
}
As you might expect, I don't have enough control over the endpoint to be able to give the property a name. Is there a way to handle this?
I'm using RestTemplate from spring to make the call, if that matters at all.
I'm implementing a RESTful service application for TomEE Plus 1.7.1 with Jettison as default json provider. I have several facade classes for my entitiy classes to provide CRUD functionalities for each of them. Service facades have been generated by netbeans.
This is the POST method:
#POST
public void create(Course entity) {
super.create(entity);
}
While using this method (to create a new instance in the database) I got following error:
No message body reader has been found for request class Object, ContentType : application/json.
After several hours of trying, I got it to work: I only had to add another parameter to the method, like that:
#POST
public void create(#Context Context uriInfo, Course entity) {
super.create(entity);
}
I don't understand why I had to add this Context parameter. I don't need the context variable, so actually I would like to remove it...
Does anybody know the reason?
Okay, I think I found the solution:
All my rest services have been implemented as facade classes. The abstract facade (super class of all services) has several methods like:
public void create(T entity) { getEntityManager().persist(entity); }
public void edit(T entity) {getEntityManager().merge(entity);}
These methods are used by the facade classes:
public void create(Course entity) {
super.create(entity);
}
public void edit(#PathParam("id") Integer id, Course entity) {
super.edit(entity);
}
(for better viewing I've removed the annotations here)
The difference between these two methods is, that the edit method has a second parameter "id" and so does not override the edit() method of the super class. But the create() method does only have a single parameter which causes override of the super class method "create()". I don't know why, but cxf is now creating two endpoints:
POST http://localhost:8080/webprog/api/course/ -> void create(Course)
POST http://localhost:8080/webprog/api/course/ -> void create(Object)
This is also the reason why I got it working with a secon parameter: The create() method is not getting overriden anymore.
So what i did now, is simply renaming the method in de super class, to not override them in the facade classes.
by the way: all services classes have been created by netbeans generator... maybe there is a bug in it
Here are some of the pointers
Make sure you have jettison jar in your classpath, CXF automatically registers jettison as json provider.
#Context Context is not mandatory, so if you want to access some context parameters you can add.
For Method create add Media Type #Consumes(MediaType.APPLICATION_JSON)
Finally Check why you are getting No message body reader has been found for request class Object Ideally you should have got No message body reader has been found for request class Course(There might be some issues with your class definations)
I want to use non spring bean class object as parameter for jersey web service class method. But it is giving missing dependency error at build time.
My code is:
#Component
#Path("/abcd")
public class ActorServiceEndpoint {
#POST
#Path("/test/{nonspringBean}")
#Produces(MediaType.APPLICATION_XML)
public void addActor(#PathParam("nonspringBean") MyNonSpringBeanClass nonspringBean){
}
}
The thing is path parameters come in String form. As per the specification, if we want the have a custom type be injected as a #PathParam, the custom class, should have one of three things:
A public static valueOf(String param) that returns the type
A public static fromString(String param) that returns the type
Or a public constructor that accepts a String
Another option implement a ParamConverter. You can see an example here.
If you don't own the class (it's a third-party class that you can't change) then your only option is to use the ParamConverter/ParamConverterProvider pair.
In either of these cases you'll want to construct the instance accordingly by parsing the String either in the constructor or in one of the above mentioned methods. After doing this, the custom type can be made a method parameter with the annotation.
The same holds true for other params, such as #FormParam, #HeaderParam, #QueryParam, etc.
It would help if you gave a bit more details of the error you're getting, but I see two problems with your code snippet:
The correct Spring annotation is #PathVariable, #PathParam is probably from another package. This doesn't apply as I guess you're using JAX-RS, not Spring annotations.
I'm not sure what converters are applied to path variables, but in any case it would need to have one for MyNonSpringBeanClass. I would take a String parameter and then instantiate MyNonSpringBeanClass myself in the function body.