I'm using Retrofit 2.1 and Jackson in an Android app to make a post call to a service which is using Jackson to deserialize. The service is expecting the incoming json to look like:
{"#class":"com.servicepackagepath$OurClassName","prop1":"value1","prop2":"value2"}
however the json that's getting generated and being sent to the service is:
{"prop1":"value1","prop2":"value2"}
resulting in a 500. The retrofit signature looks like:
#POST("apiName")
Call<String> apiName(#Body OurClassName ourClassName);
OurClassName class on the client side is a different class than the one on the service. Exactly the same signature, but it's local.
How can I get that #class annotation to get inserted into the outgoing json?
Ok, figured it out. You need to add to your Retrofit Builder:
.addConverterFactory(JacksonConverterFactory.create(
new ObjectMapper().enableDefaultTyping(ObjectMapper.DefaultTyping.JAVA_LANG_OBJECT, JsonTypeInfo.As.PROPERTY)
))
and then on top of your class declaration do:
#JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include= JsonTypeInfo.As.PROPERTY, property="#class")
Related
I'm basically using retrofit to create a request to a server, however the date is stored in mongodb and the request returns a response that contiants $date, is there a way to retrieve it?
I'm assuming from the question title that you mean there's a json key with a dollar sign and I'll assume you're using Gson too, because that's common with Retrofit. If so, then you're looking for SerializedName
This annotation lets you specify the name in the json for the key. So in your case you'd want to add it to your model. Something like:
public class Foo {
#SerializedName("$date")
private String date;
}
in kotlin:
data class foo(
#SerializedName("\$date")
val date: String)
This annotation is used by Gson to serialize and deserialize the object into and from json.
I'm sure other libraries that can be plugged into retrofit have something similar.
Also note that on Android this annotation is very handy, because of the obfuscation tools. Usually the models are obfuscated and the variable names change. If you want to keep the right names then this is an approach to it.
I'm developing a restful web-service that should be able to return JSON or XML responses upon request. Of course, the JSON response should be identical to the XML response when the data is compared.
The thing is that I can't use a Java pojo because the returned data fields are dynamic, they are unpredictable.
For example, a specific user may have the following response:
{
"propertyA": "propertyA-Value",
"propertyB": "propertyB-Value",
}
...another user may have:
{
"propertyA": "propertyA-Value",
"propertyB": "propertyB-Value",
"propertyC": "propertyC-Value",
}
...or the XML representation would be
<results>
<propertyA>propertyA-Value</propertyA>
<propertyB>propertyB-Value</propertyB>
<propertyC>propertyC-Value</propertyC>
</results>
Is there a way to automatically serialize the structure holding the previously mentioned data, to JSON or XML. By "automatically", I mean using an API that would work with whatever fields provided.
I can't use an array\list of feature-name\feature-value structures as the service consumer needs to receive the response as mentioned.
use codehaus fasterxml object mapper. A sample app can be seen from below link
https://github.com/abhishek24509/JsonMapper
ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
the above code will help to hold dyamic response. Your pojo can have all possible field. But during mapping it will ignore unknown
I'm trying to post a POJO entity like below in Arquillian test class.
MyPojo pojo = new MyPojo();
pojo.setBuffer(ByteBuffer.wrap("Happy new year".getBytes()); //this is the problem
pojo.setOtherFiled(someotherfield)
Client client = ClientBuilder.newClient();
Invocation.Builder builder = client.target(url).request(
MediaType.APPLICATION_JSON_TYPE);
MyPojo response = builder.post(Entity.json(pojo), MyPojo.class);
My rest resource end point looks like this
MyPojo myEndPoint(MyPojo pojoParam){
//the body is immaterial since it's not going inside the body.
}
I'm getting javax.ws.rs.BadRequestException:HTTP 400 Bad Request.
If I comment out pojo.setBuffer(ByteBuffer.wrap("Happy new year".getBytes());, it's not giving that error.
What is the problem with the above code how to correct it?
Finally I figured out why it's happening. The Jackson cannot serialize ByteBuffer as it is an abstract class. It's not straight forward it might need additional type information.
At the client end we send the json(jackson serializes the POJO) but when reconstructing the POJO class before passing to the rest end point, it fails to reconstruct the object of the POJO class from json as it doesn't know how to create a ByteBuffer instance.
I figured it by trying to use jackson to serialize and de-serialize ByteBuffer in a stand alone class. It will throw
org.codehaus.jackson.map.JsonMappingException: Can not construct instance of java.nio.ByteBuffer, problem: abstract types can only be instantiated with additional type information
Jackson lies in pre-processing phase of the request processing in Resteasy. So, Resteasy is giving 400 bad request as it could not process the request.
As a work around I'm using byte[] instead of ByteBuffer and converting it to ByteBuffer instance in the end point.
Upgrading the JSON Mapper to fasterxml will fix this issue. I have upgraded and the issue is fixed for me.
https://github.com/FasterXML/jackson
I am trying to access a JAX-RS Service (jersey implementation) which is returning me a java.util.list of Employees in XML format.
The Service method signature looks like this:
#GET
#Path("/getEmployeeListXML")
#Consumes(MediaType.TEXT_PLAIN)
#Produces(MediaType.APPLICATION_XML)
public List<EmployeeXML> getEmployeeListXML(#QueryParam("id") String id){
//Some code which returns a List<EmployeeXML>
}
The format of the XML returned is like this:
<employeeXMLs>
<employeeXML>
<empId>1</empId>
<empName>John</empName>
<empAge>35</empAge>
<empSex>Male</empSex>
</employeeXML>
<employeeXML>
<empId>2</empId>
<empName>Lisa</empName>
<empAge>23</empAge>
<empSex>Female</empSex>
</employeeXML>
</employeeXMLs>
For accessing this from my jersey Client, I am using this code:
List<EmployeeXML> empListXML = (List<EmployeeXML>)service.path("rest").path("GetService").path("getEmployeeListXML").accept(MediaType.APPLICATION_XML).get(EmployeeXML.class);
This is not correct since the return type should be a list but in the get method, presently I am trying to retrieve a single object. I am not sure how to retrieve the List from the client here :(
I am getting this exception:
unexpected element (uri:"", local:"employeeXMLs"). Expected elements are <{}employeeListXML>,<{}employeeXML>
Please help me out to make this work.
Thanks,
You can use the GenericType class to fetch a list of objects:
List<EmployeeXML> empListXML = (List<EmployeeXML>)service.path("rest").path("GetService").path("getEmployeeListXML").accept(MediaType.APPLICATION_XML).get(new GenericType<List<EmployeeXML>>(){});
You need to use a 'supertype token' to define the return type in your client class:
List<EmployeeXML> empListXML = service
.path("rest")
.path("GetService")
.path("getEmployeeListXML")
.accept(MediaType.APPLICATION_XML)
.get(new GenericType<List<EmployeeXML>>() {});
The supertype token is required in order to 'retain' generic parameter information that Jersey will use when deserializing the server response.
I'm playing with RESTEasy to consume REST services, and I'm trying it out with Twitter's search API.
So I create this interface:
public interface SimpleClient {
#GET
#Path("search.json")
#Produces("application/json")
ClientResponse<Set<String>> getSearchResults(
#QueryParam("q") String hashtag,
#QueryParam("result_type") String resultType
);
}
and called it with:
SimpleClient client =
ProxyFactory.create(SimpleClient.class,"http://search.twitter.com/");
ClientResponse<Set<String>> response =
client.getSearchResults("#wowodc","recent");
System.out.println(response.getEntity(Set.class));
But I'm getting:
ClientResponseFailure: Unable to find a MessageBodyReader of content-type application/json;charset="utf-8" and type interface java.util.Set
I have tried using a POJO instead of java.util.Set, but I'm getting the same kind of exception. The only thing that didn't throw an exception is using String instead of Set.
By reading some example code on the Web, I was thinking that Set or a POJO as the entity type would have work, but it doesn't for me. The query to Twitter did return valid results.
You need to make sure you include a RESTEasy provider that can unmarshal JSON responses. There's a one based on the Jackson parser library that you can use, it's described in the docs here.