Using Gson with Interface Types - java

I am working on some server code, where the client sends requests in form of JSON. My problem is, there are a number of possible requests, all varying in small implementation details.
I therefore thought to use a Request interface, defined as:
public interface Request {
Response process ( );
}
From there, I implemented the interface in a class named LoginRequest as shown:
public class LoginRequest implements Request {
private String type = "LOGIN";
private String username;
private String password;
public LoginRequest(String username, String password) {
this.username = username;
this.password = password;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
/**
* This method is what actually runs the login process, returning an
* appropriate response depending on the outcome of the process.
*/
#Override
public Response process() {
// TODO: Authenticate the user - Does username/password combo exist
// TODO: If the user details are ok, create the Player and add to list of available players
// TODO: Return a response indicating success or failure of the authentication
return null;
}
#Override
public String toString() {
return "LoginRequest [type=" + type + ", username=" + username
+ ", password=" + password + "]";
}
}
To work with JSON, I created a GsonBuilder instance and registered an InstanceCreator as shown:
public class LoginRequestCreator implements InstanceCreator<LoginRequest> {
#Override
public LoginRequest createInstance(Type arg0) {
return new LoginRequest("username", "password");
}
}
which I then used as shown in the snippet below:
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(LoginRequest.class, new LoginRequestCreator());
Gson parser = builder.create();
Request request = parser.fromJson(completeInput, LoginRequest.class);
System.out.println(request);
and I get the expected output.
The thing I wish to do is replace the line Request request = parser.fromJson(completeInput, LoginRequest.class); with something similar to Request request = parser.fromJson(completeInput, Request.class); but doing that will not work, since Request is an interface.
I want my Gson to return the appropriate type of request depending on the received JSON.
An example of the JSON I passed to the server is shown below:
{
"type":"LOGIN",
"username":"someuser",
"password":"somepass"
}
To reiterate, I am looking for a way to parse requests (In JSON) from clients and return objects of classes implementing the Request interface

Polymorphic mapping of the type described is not available in Gson without some level of custom coding. There is an extension type adapter available as an extra that provides a bulk of the functionality you are looking for, with the caveat that the polymorphic sub-types need to be declared to the adapter ahead of time. Here is an example of its use:
public interface Response {}
public interface Request {
public Response process();
}
public class LoginRequest implements Request {
private String userName;
private String password;
// Constructors, getters/setters, overrides
}
public class PingRequest implements Request {
private String host;
private Integer attempts;
// Constructors, getters/setters, overrides
}
public class RequestTest {
#Test
public void testPolymorphicSerializeDeserializeWithGSON() throws Exception {
final TypeToken<List<Request>> requestListTypeToken = new TypeToken<List<Request>>() {
};
final RuntimeTypeAdapterFactory<Request> typeFactory = RuntimeTypeAdapterFactory
.of(Request.class, "type")
.registerSubtype(LoginRequest.class)
.registerSubtype(PingRequest.class);
final Gson gson = new GsonBuilder().registerTypeAdapterFactory(
typeFactory).create();
final List<Request> requestList = Arrays.asList(new LoginRequest(
"bob.villa", "passw0rd"), new LoginRequest("nantucket.jones",
"crabdip"), new PingRequest("example.com", 5));
final String serialized = gson.toJson(requestList,
requestListTypeToken.getType());
System.out.println("Original List: " + requestList);
System.out.println("Serialized JSON: " + serialized);
final List<Request> deserializedRequestList = gson.fromJson(serialized,
requestListTypeToken.getType());
System.out.println("Deserialized list: " + deserializedRequestList);
}
}
Note that you don't actually need to define the type property on the individual Java objects - it exists only in the JSON.

Assuming that the different possible JSON requests you may have are not extremely different to each other, I suggest a different approach, simpler in my opinion.
Let's say that you have these 3 different JSON requests:
{
"type":"LOGIN",
"username":"someuser",
"password":"somepass"
}
////////////////////////////////
{
"type":"SOMEREQUEST",
"param1":"someValue",
"param2":"someValue"
}
////////////////////////////////
{
"type":"OTHERREQUEST",
"param3":"someValue"
}
Gson allows you to have a single class to wrap all the possible responses, like this:
public class Request {
#SerializedName("type")
private String type;
#SerializedName("username")
private String username;
#SerializedName("password")
private String password;
#SerializedName("param1")
private String param1;
#SerializedName("param2")
private String param2;
#SerializedName("param3")
private String param3;
//getters & setters
}
By using the annotation #SerializedName, when Gson try to parse the JSON request, it just look, for each named attribute in the class, if there's a field in the JSON request with the same name. If there's no such field, the attribute in the class is just set to null.
This way you can parse many different JSON responses using only your Request class, like this:
Gson gson = new Gson();
Request request = gson.fromJson(jsonString, Request.class);
Once you have your JSON request parsed into your class, you can transfer the data from the wrap class to a concrete XxxxRequest object, something like:
switch (request.getType()) {
case "LOGIN":
LoginRequest req = new LoginRequest(request.getUsername(), request.getPassword());
break;
case "SOMEREQUEST":
SomeRequest req = new SomeRequest(request.getParam1(), request.getParam2());
break;
case "OTHERREQUEST":
OtherRequest req = new OtherRequest(request.getParam3());
break;
}
Note that this approach gets a bit more tedious if you have many different JSON requests and those requests are very different to each other, but even so I think is a good and very simple approach...

Genson library provides support for polymorphic types by default. Here is how it would work:
// tell genson to enable polymorphic types support
Genson genson = new Genson.Builder().setWithClassMetadata(true).create();
// json value will be {"#class":"mypackage.LoginRequest", ... other properties ...}
String json = genson.serialize(someRequest);
// the value of #class property will be used to detect that the concrete type is LoginRequest
Request request = genson.deserialize(json, Request.class);
You can also use aliases for your types.
// a better way to achieve the same thing would be to use an alias
// no need to use setWithClassMetadata(true) as when you add an alias Genson
// will automatically enable the class metadata mechanism
genson = new Genson.Builder().addAlias("loginRequest", LoginRequest.class).create();
// output is {"#class":"loginRequest", ... other properties ...}
genson.serialize(someRequest);

By default, GSON cannot differentiate classes serialized as JSON; in other words, you will need to explicitly tell the parser what class you are expecting.
A solution could be custom deserializing or using a type adapter, as described here.

I found this answer: https://stackoverflow.com/a/28830173 which solved my issue when using Calendar as the interface as the RunTimeType would be GregorianCalendar.

Have a utility method to create GSON for an interface of generic type.
// Utility method to register interface and its implementation to work with GSON
public static <T> Gson buildInterface(Class<T> interfaceType, List<Class<? extends T>> interfaceImplmentations) {
final RuntimeTypeAdapterFactory<T> typeFactory = RuntimeTypeAdapterFactory.of(interfaceType, "type");
for (Class<? extends T> implementation : interfaceImplmentations) {
typeFactory.registerSubtype(implementation);
}
final Gson gson = new GsonBuilder().registerTypeAdapterFactory(typeFactory).create();
return gson;
}
// Build Gson
List<Class<? extends Request>> customConfigs = new ArrayList<>();
customConfigs.add(LoginRequest.getClass());
customConfigs.add(SomeOtherRequest.getClass());
Gson gson = buildInterface(Request.class, customConfigs);
Use this gson to serialize or deserialize and this works.

Related

Retrofit request body: Required fields

The process of using a request body is described in the official API Declaration page as such:
#POST("users/new")
Call<User> createUser(#Body User user);
While there is no guide for creating the User object, I imagine it can look something like this:
public class User {
public String name;
public String group;
}
By extension, this would result in a request body like this:
{
"name": string,
"group": string
}
By default, these fields seem to be optional. What is the best way I can make them required?
There are many ways of accomplishing such a behavior. You can:
... validate your objects to be POSTed before you invoke a Retrofitted-service (user input forms, etc), and let it fail fast.
... validate your domain objects, centralized, in a Retrofit request converter and use chained converters
... validate your data transfer objects objects (if you have any), centralized, after they are converted from domain objects and prepared to be sent
... rely on the server API implementation and don't care for validation at the client side: no need to duplicate server logic ad-hoc, you may run out sync with the server API validation, you write more code, etc. This is what I was suggesting you in that comment.
If you really need to validate the request bodies before they are sent, you should go with the first option. If you want to make the validation fully centralized, you can implement a custom Retrofit converter to make pre-validation on fly. (The code below uses Java 8 and a little bit of Google Guava, Retrofit 2 and Gson, however it can be easily reworked for another components).
Consider these:
interface IService {
#POST("/")
Call<String> post(
#Body User user
);
}
final class User {
final String name;
final String group;
User(final String name, final String group) {
this.name = name;
this.group = group;
}
}
Now we can implement Retrofit-stuff. The following mockOkHttpClient is a mock OkHttpClient to consume any request and respond with HTTP 200 OK and "OK".
private static final OkHttpClient mockOkHttpClient = new OkHttpClient.Builder()
.addInterceptor(chain -> new Response.Builder()
.request(chain.request())
.protocol(HTTP_1_0)
.code(HTTP_OK)
.body(ResponseBody.create(MediaType.parse("application/json"), "\"OK\""))
.build()
)
.build();
Now let's make a simple test:
final Iterable<Retrofit> retrofits = ImmutableList.of(
getAsIsRetrofit(),
getValidatedDomainObjectsRetrofit(),
getValidatedDataTransferObjectsRetrofit()
);
final User user = new User("user", "group");
for ( final Retrofit retrofit : retrofits ) {
final IService service = retrofit.create(IService.class);
final String message = service.post(user).execute().body();
System.out.println(message);
}
As you can see, there are three Retrofit instances that are instantiated with different configurations to demonstrate each of them.
The following Retrofit instance does not care the validation itself. And this is another time I recommend you to go with: simply post what you get as is and let the server API implementation deal with it itself. Consider the API implementation to return nice responses like HTTP 400 Bad Request, etc.
private static Retrofit getAsIsRetrofit() {
return new Retrofit.Builder()
.client(mockOkHttpClient)
.baseUrl("http://whatever")
.addConverterFactory(GsonConverterFactory.create())
.build();
}
The following Retrofit instance validates the given User object before it's converted to a Gson-friendly representation (depends on if you have domain objects to data transfer object transformations in your application):
private static Retrofit getValidatedDomainObjectsRetrofit() {
return new Retrofit.Builder()
.client(mockOkHttpClient)
.baseUrl("http://whatever")
.addConverterFactory(new Converter.Factory() {
#Override
public Converter<?, RequestBody> requestBodyConverter(final Type type, final Annotation[] parameterAnnotations,
final Annotation[] methodAnnotations, final Retrofit retrofit) {
if ( type != User.class ) {
return null;
}
final Converter<Object, RequestBody> nextConverter = retrofit.nextRequestBodyConverter(this, type, parameterAnnotations, methodAnnotations);
return (Converter<Object, RequestBody>) value -> {
if ( value instanceof User ) {
final User user = (User) value;
requireNonNull(user.name, "name must not be null");
requireNonNull(user.group, "group must not be null");
}
return nextConverter.convert(value);
};
}
})
.addConverterFactory(GsonConverterFactory.create())
.build();
}
And the next one validates data transfer objects before they are written to output streams. Probably the most low-level instance here.
private static Retrofit getValidatedDataTransferObjectsRetrofit() {
final Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(new TypeAdapterFactory() {
#Override
public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) {
if ( typeToken.getRawType() != User.class ) {
return null;
}
final TypeAdapter<T> delegateTypeAdapter = gson.getDelegateAdapter(this, typeToken);
return new TypeAdapter<T>() {
#Override
public void write(final JsonWriter out, final T value)
throws IOException {
if ( value instanceof User ) {
final User user = (User) value;
requireNonNull(user.name, "name must not be null");
requireNonNull(user.group, "group must not be null");
}
delegateTypeAdapter.write(out, value);
}
#Override
public T read(final JsonReader in)
throws IOException {
return delegateTypeAdapter.read(in);
}
};
}
})
.create();
return new Retrofit.Builder()
.client(mockOkHttpClient)
.baseUrl("http://whatever")
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
}
Note that requireNonNull is a JDK 8 method, and if you want something like #NotNull, you can implement your own annotation processor, or find such an implementation in the Internet considering my implementation idea useless. :) However, I think you'd like the as-is approach the most.

Java how to store object of varying type

I am currently using Spring MVC and Hibernate to develop my web app. Still learning inner workings of java.
I find my self in a situation where I need to store data in a field that could accept different type of Objects along with some other strings of data. More precisely I want to create a ReturnObject that could hold messages, error code...etc. This way my return JSON could stay consistent through out the api.
This is how I created my ReturnObject
public class ReturnResponse {
//Set fields
private Object returnObj; <----- Need this to accept different types
private HttpStatus httpStatus;
private String message;
private String developerMessage;
// Start build
public ReturnResponse(){
this.returnObj = returnObj;
this.httpStatus =.....etc.
}
// Setters... getters...
}
private Object returnObj; so that this field could accept Collection, Maps, Class..etc but is this safe?
I seem to remember that its always a good practice to declare specific object type in the field to ensure type-safe.
Questions
Do you see foreseeable problem in the future, is there a better way of doing this?
If this is not type safe, how would I make it safer.
You can use a generic :
public class ReturnResponse<ObjectType> {
private ObjectType returnObj;
private HttpStatus httpStatus;
private String message;
private String developerMessage;
public ReturnResponse(ObjectType returnObj, /*other parameters...*/) {
this.returnObj = returnObj;
// set other parameters
}
public ObjectType getReturnObj() {
return this.returnObj;
}
// ...
}
It will work if you know when you instanciate your ReturnResponse what's the type of the returned object.
I use this pattern in most of my API without problem.
If you want "to store data in a field that could accept different type of Objects along with some other strings of data." then you need to have a base class for that object which in your case will probably be Object.
The problem is that you need to have some way to decipher later in your code, what type of object that is - which in most cases I think will be undesirable and will require unsafe casting.
Only way I can think of to make it more safe is to make some kind of wrapper like:
public class Bean {
private String string;
private Integer integer;
private List<String> list;
private Bicycle bicycle;
//setters
//...
public Optional<Bicycle> getBicycle() {
return Optional.ofNullable(bicycle);
}
//... and so on...
}
The error handler should be in the controller and it should respond an http error. That means a correct HTTP error status, and a desired error message. An error should not look like a successful request (No status code 200). It's an error. In your front end you should handle the http error response accordingly.
With spring this can be very easy a nicely done. Here is an example of an error handler of a project of mine. It's an own class with the annotation #ControllerAdvice. spring will automatically use that.
This class will automatically catch any unhandled exception that are defined with #ExceptionHandler and send in my case a ShortExceptionResponse that contains the type and the message of the exception thrown, with a correct Http error status defined with #ResponseStatus.
In your front end you can react accordingly to the different HTTP status error codes. It's nice and generic.
#ControllerAdvice
public class RestExceptionResponseHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(SetRestController.class);
#ExceptionHandler(NoSuchElementException.class)
#ResponseStatus(HttpStatus.NOT_FOUND)
public #ResponseBody
ShortExceptionResponse noSuchElementExceptionHandler(Exception ex) {
LOGGER.error("An error occured processing a rest request", ex);
return new ShortExceptionResponse(ex);
}
#ExceptionHandler(value = {EntityAlreadyExistsException.class})
#ResponseStatus(HttpStatus.FORBIDDEN)
public #ResponseBody
ShortExceptionResponse entityAlreadyExistsExceptionHandler(EntityAlreadyExistsException ex) {
LOGGER.debug("A rest request could not been process due an illegal state of the target entity", ex);
return new ShortExceptionResponse(ex);
}
#ExceptionHandler(value = {IllegalArgumentException.class, UnsupportedOperationException.class})
#ResponseStatus(HttpStatus.BAD_REQUEST)
public #ResponseBody
ShortExceptionResponse illegalArgumentExceptionHandler(Exception ex) {
LOGGER.error("An error occured processing a rest request", ex);
return new ShortExceptionResponse(ex);
}
#ExceptionHandler(value = {HttpMessageNotReadableException.class})
#ResponseStatus(HttpStatus.BAD_REQUEST)
public #ResponseBody
ShortExceptionResponse httpMessageNotReadableExceptionHandler(Exception ex) {
LOGGER.error("An error occured processing a rest request", ex);
if (ex.getCause() instanceof InvalidFormatException) {
return new ShortExceptionResponse(new InvalidValueException(((InvalidFormatException) ex.getCause()).getOriginalMessage()));
}
return new ShortExceptionResponse(ex);
}
...
...
}
In the actual controller you just keep throwing the exception and it will be handled by your error handler
#RequestMapping(method = RequestMethod.POST)
public #ResponseBody
MetadataDTO createMetadata(#RequestBody MetadataDTO metaDataDTO) throws EntityAlreadyExistsException {
MetadataDTO result = metaDataService.createMetadata(metaDataDTO.getName(), metaDataDTO.getDescription(), metaDataDTO.getType());
return result;
}
You can create a 'model' class to store the full object to be converted to json:
#AllArgsConstructor //or make a constructor with all the fields manually
class ResponseObject {
User user;
House house;
Car car;
}
Since you are using Spring, you already have the Jackson library. So you can do:
#Autowired ObjectMapper objectMapper; // no need to configure anything to use this
public String getJson(){
User user = new User("user", "password");
House house = new House(4, true, ...);
Car car = new Car();
ResponseObject resp = new ResponseObject(user, house, car);
String json = null;
json = objectMapper.convertValue(resp, ResponseObject.class);
// or:
try {
json = objectMapper.writeValueAsString(resp);
} catch (Exception e) {
...
}
// or: (would need to use a google Gson dependency)
Gson gson = new Gson();
json = gson.toJson(resp, ResponseObject.class);
return json;
}
Alternatively, if you really need the flexibility,
#Autowired ObjectMapper mapper;
public void printJson() {
Map<String, Object> jsonMap = new HashMap<>();
jsonMap.put("number", 5);
jsonMap.put("String", "string");
jsonMap.put("kanky", 987L);
String json = mapper.writeValueAsString(jsonMap);
System.out.println("json: " + json);
} // works fine if your map values have a toString defined

GWT - Serializing POST parameter in JSON before sending

I am trying to invoke a REST server from my GWT client. The server is not under my control and I am using GWT just for the client. The service expects to receive a JSON which is going to be deserialized with Jackson and mapped to a Java bean like this:
public DTO {
String username;
String password;
/*...*/
}
Therefore, on my GWT project I created this class:
import com.google.gwt.json.client.JSONObject;
import com.lh.clte.client.gui.util.CLTELabelProperties;
public class DTO extends JSONObject {
String username;
String password;
/*...*/
}
And I am trying to send a POST request this way:
DTO dto= new DTO();
dto.setUsername(username);
dto.setPassword(password);
RequestBuilder b = new RequestBuilder(RequestBuilder.POST, url);
b.setHeader("content-type", "application/x-www-form-urlencoded");
/***** ERROR *************/
String data = dto.toString(); // JSONObject.toString(), no ovveriding
/*************************/
b.setRequestData(data);
b.setCallback(new MyCallback<DTO>());
try {
b.send();
} catch (RequestException e) {
e.printStackTrace();
}
However, the toString method doesn't produce the expected JSON, but rather the string "{}". Where am I doing it wrong?
I also tried com.google.gwt.json.client.dev.JsonObject, but it doesn't change the outcome.
You have to stringify your JSO object before sending over the wire:
String data = JsonUtils.stringify(dto);
This function is available in 2.7.0-SNAPSHOT, for 2.6.1 you have to create your own JSNI method
String data = stringify(dto);
private native String stringfy(JavaScriptObject jso) /*-{
return JSON.stringify(obj);
}-*/;
JSONObject is a "map", it's not meant to be extended.
You could have your accessors store the value in an internal JSONObject rather than in fields, or you could use a JavaScriptObject with accessors written in JSNI and using JsonUtils for parsing and JSONObject for serialization (new JSONObject(myJso).toString(), pending GWT 2.7's JsonUtils.stringify), or you could use AutoBeans.
See also https://stackoverflow.com/a/10685489/116472 or How to genearte JSON on the client, among many others.
If your backend uses Jackson, you should give gwt-jackson a try.
You'll be able to use any DTO and even the server beans if you have access to the sources.
You declare your mapper like that :
public static interface DTOWriter extends ObjectWriter<DTO> {}
And then :
DTOWriter dtoWriter = GWT.create(DTOWriter.class);
String data = dtoWriter.write(dto);
BTW, shouldn't your Content-type header be application/json ?
An alternative approach will be to use RestyGWT (http://restygwt.fusesource.org/).
RestyGWT will take care of both serializing to/from JSON and also doing the POST request.
In your example, you will need a Class that defines which fields are serializable:
public class DTO {
#Json(name = "username") // 'username' will be the name of the parameter in the json object
private String username;
#Json(name = "password")
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
Then, you define the service by extending RestService
public interface DTORestService extends RestService {
/**
* Utility/Convenience class.
* Use DTORestService.App.getInstance() to access static instance of DTORestService
*/
public static class App {
private static DTORestService ourInstance = null;
public static DTORestService getInstance() {
if (ourInstance == null) {
Defaults.setServiceRoot(host); // the host from the 'url' you want the POST to be sent
ourInstance = (DTORestService) GWT.create(DTORestService.class);
}
return ourInstance;
}
}
#POST
#Path("/dto.json") // the path from the 'url' you want the POST to be sent
public void getDTO(DTO dto, // the json object you want to add to the post
MethodCallback<DTO> callback); // the method callback with any json result you will receive
}
Finally, you can call it by doing:
DTO dto = new DTO();
dto.setUsername(username);
dto.setPassword(password);
DTORestService.getInstance().getDTO(dto, new AMethodCallback<DTO>());
hope it helps

How to parse JSON Response to POJO with AndroidAnnotations?

I'm using AndroidAnnotations to build a Rest for an Android Application.
On the Serverside im using PHP, which send a json looking like :
{"tag":"register","success":0,"error":2,"msg":"User already existed","body":[]}
I have two POJOS :
User.java:
public class User implements Serializable {
private String name;
private String email;
private String password;
//getter and setter Methods
}
Response.java:
public class RegistrationResponse implements Serializable {
private String tag;
private int success;
private int error;
private String msg;
private String body;
//getter and setter Methods
}
Rest Client:
#Rest(rootUrl = "http://my.domain.com", converters = {
MappingJacksonHttpMessageConverter.class,
StringHttpMessageConverter.class, GsonHttpMessageConverter.class }, interceptors = { MyInterceptor.class })
public interface RestClient extends RestClientErrorHandling {
#Post("/user/register/{name}/{email}/{pass}")
#Accept(MediaType.APPLICATION_JSON_VALUE)
Response sendUserRegistration(User user, String name, String email,
String pass);
RestTemplate getRestTemplate();
}
Activity.java:
//User and Response are POJOs
Response result = RestClient.sendUserRegistration(user,
user.getName(),user.getEmail(),user.getPassword());
But i got an Null Pointer Exception error on Activity.java. But if i change the return value of "sendUserRegistration" function to String all work. So my "Response" POJO seems not to be converted from AndroidAnnotations.
How can i convert the Rest Response to my "Response"-POJO using AndroidAnnotations?
You don't need to return the entire response object per rest call, just set the response to your custom object. Or you can also return a JsonObject also and use gson to convert it later on.
#Rest(rootUrl = "http://my.domain.com", converters = {
MappingJacksonHttpMessageConverter.class,
StringHttpMessageConverter.class, GsonHttpMessageConverter.class }, interceptors = { MyInterceptor.class })
public interface RestClient extends RestClientErrorHandling {
#Post("/user/register/{name}/{email}/{pass}")
#Accept(MediaType.APPLICATION_JSON_VALUE)
User sendUserRegistration(User user, String name, String email,
String pass);
RestTemplate getRestTemplate();
}
then just simply call
User newUser = RestClient.sendUserRegistration(user,
user.getName(),user.getEmail(),user.getPassword());
AA relies on Spring Android RestTemplate to make the rest call. And in order to build requests and handle responses this lib uses converters. And to know which converter the RestTemplate should use, it checks the content-type response header.
As MappingJacksonHttpMessageConverter and GsonHttpMessageConverter handles only http response with content-type=application/json and your result is converted to string, I'm pretty sure you forgot to set this header in your php server. So it send the default one (ie: text/plain) which is only handle by StringHttpMessageConverter.
Also, the body field is an object in your json example, but in your POJO you declared it as a String. So parsing will fail on this point.

No suitable HttpMessageConverter found when trying to execute restclient request

I'm trying to use Spring for Android rest client to send data with an http post , to avoid creating and parsing the json data.
From their manual they have the following method:
restTemplate.postForObject(url, m, String.class)
After the method is called I get the following exception:
No suitable HttpMessageConverter found when trying to execute restclient request
My activity code snippet is :
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MappingJacksonHttpMessageConverter());
restTemplate.getMessageConverters().add(new StringHttpMessageConverter());
Message m = new Message();
m.setLibrary("1");
m.setPassword("1395");
m.setUserName("1395");
String result = restTemplate.postForObject(url, m, String.class);
And the Message object is :
public class Message {
private String UserName, Password, Library;
public String getUserName() {
return UserName;
}
public void setUserName(String userName) {
UserName = userName;
}
public String getPassword() {
return Password;
}
public void setPassword(String password) {
Password = password;
}
public String getLibrary() {
return Library;
}
public void setLibrary(String library) {
Library = library;
}
}
Why can't it convert the Message object to JSON ?
There could be a few different reasons why this can happen. In my case, i had the RestTemplate already wired in, but still got this error. Turns out, i had to add a dependency on "jackson-databind":
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
It looks like you have not added a Message-specific HttpMessageConverter. HttpMessageConverter is an interface. You need to create a class that implements HttpMessageConverter<Message> and add an instance of that class to the RestTemplate via restTemplate.getMessageConverters().add(new MyMessageConverter());
Your code looks fine in general. Maybe this is a version problem. Check whether you use Jackson 2, and if so, change the converter to MappingJackson2HttpMessageConverter.
No need for something like HttpMessageConverter<Message>.
On a side node:
Java convention is to use lower casing for variable names. So, it would be more readable for other Java developers to do:
private String library;
public void setLibrary(String library) {
this.library = library;
}

Categories