Reputation: 10359
I'm building an Android app using Robospice for communication over network. The resulting object returned from my server does not get deserialized properly. Here are the related classes:
UserRequest.java
import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpResponse;
import com.google.api.client.json.jackson.JacksonFactory;
import com.octo.android.robospice.request.googlehttpclient.GoogleHttpClientSpiceRequest;
import roboguice.util.temp.Ln;
import trees.park.cal.smoke.models.UserList;
public class UserRequest extends GoogleHttpClientSpiceRequest<UserList>{
private String baseUrl = "http://10.0.0.3:8181/users/";
public UserRequest() {
super(UserList.class);
}
@Override
public UserList loadDataFromNetwork() throws Exception {
Ln.d("Call web service " + baseUrl);
HttpRequest request = getHttpRequestFactory()
.buildGetRequest(new GenericUrl(baseUrl));
request.setParser( new JacksonFactory().createJsonObjectParser() );
HttpResponse response = request.execute();
return response.parseAs( getResultType() );
}
}
UserList.java
import java.util.ArrayList;
public class UserList extends ArrayList<User> {
}
User.java
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.Collections;
import java.util.List;
public class User {
@JsonProperty("id")private long id;
@JsonProperty("email")private String email;
@JsonProperty("password")private String password;
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
@JsonCreator
public User(@JsonProperty("id") long id, @JsonProperty("email") String email, @JsonProperty("password") String password) {
this.id = id;
this.email = email;
this.password = password;
}
}
When response.parseAs(getRequestType())
is called, an exception is raised with the following stack trace:
08-19 23:54:08.411 27117-27139/trees.park.cal.smoke E//DefaultRequestRunner.java:154﹕ 23:54:08.418 Thread-5533 An exception occurred during request network execution :
java.lang.IllegalArgumentException:
at com.google.api.client.json.JsonParser.parseValue(JsonParser.java:880)
at com.google.api.client.json.JsonParser.parse(JsonParser.java:381)
at com.google.api.client.json.JsonParser.parse(JsonParser.java:354)
at com.google.api.client.json.JsonObjectParser.parseAndClose(JsonObjectParser.java:87)
at com.google.api.client.json.JsonObjectParser.parseAndClose(JsonObjectParser.java:81)
at com.google.api.client.http.HttpResponse.parseAs(HttpResponse.java:459)
at trees.park.cal.smoke.server.UserRequest.loadDataFromNetwork(UserRequest.java:27)
at trees.park.cal.smoke.server.UserRequest.loadDataFromNetwork(UserRequest.java:12)
at com.octo.android.robospice.request.CachedSpiceRequest.loadDataFromNetwork(CachedSpiceRequest.java:48)
at com.octo.android.robospice.request.DefaultRequestRunner.processRequest(DefaultRequestRunner.java:150)
at com.octo.android.robospice.request.DefaultRequestRunner$1.run(DefaultRequestRunner.java:217)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:841)
Caused by: java.lang.IllegalArgumentException:
at com.google.api.client.json.JsonParser.parseValue(JsonParser.java:880)
at com.google.api.client.json.JsonParser.parseArray(JsonParser.java:647)
at com.google.api.client.json.JsonParser.parseValue(JsonParser.java:739)
at com.google.api.client.json.JsonParser.parse(JsonParser.java:381)
at com.google.api.client.json.JsonParser.parse(JsonParser.java:354)
at com.google.api.client.json.JsonObjectParser.parseAndClose(JsonObjectParser.java:87)
at com.google.api.client.json.JsonObjectParser.parseAndClose(JsonObjectParser.java:81)
at com.google.api.client.http.HttpResponse.parseAs(HttpResponse.java:459)
at trees.park.cal.smoke.server.UserRequest.loadDataFromNetwork(UserRequest.java:27)
at trees.park.cal.smoke.server.UserRequest.loadDataFromNetwork(UserRequest.java:12)
at com.octo.android.robospice.request.CachedSpiceRequest.loadDataFromNetwork(CachedSpiceRequest.java:48)
at com.octo.android.robospice.request.DefaultRequestRunner.processRequest(DefaultRequestRunner.java:150)
at com.octo.android.robospice.request.DefaultRequestRunner$1.run(DefaultRequestRunner.java:217)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:841)
Caused by: java.lang.IllegalArgumentException: unable to create new instance of class trees.park.cal.smoke.models.User because it has no accessible default constructor
at com.google.api.client.util.Types.handleExceptionForNewInstance(Types.java:165)
at com.google.api.client.util.Types.newInstance(Types.java:120)
at com.google.api.client.json.JsonParser.parseValue(JsonParser.java:763)
at com.google.api.client.json.JsonParser.parseArray(JsonParser.java:647)
at com.google.api.client.json.JsonParser.parseValue(JsonParser.java:739)
at com.google.api.client.json.JsonParser.parse(JsonParser.java:381)
at com.google.api.client.json.JsonParser.parse(JsonParser.java:354)
at com.google.api.client.json.JsonObjectParser.parseAndClose(JsonObjectParser.java:87)
at com.google.api.client.json.JsonObjectParser.parseAndClose(JsonObjectParser.java:81)
at com.google.api.client.http.HttpResponse.parseAs(HttpResponse.java:459)
at trees.park.cal.smoke.server.UserRequest.loadDataFromNetwork(UserRequest.java:27)
at trees.park.cal.smoke.server.UserRequest.loadDataFromNetwork(UserRequest.java:12)
at com.octo.android.robospice.request.CachedSpiceRequest.loadDataFromNetwork(CachedSpiceRequest.java:48)
at com.octo.android.robospice.request.DefaultRequestRunner.processRequest(DefaultRequestRunner.java:150)
at com.octo.android.robospice.request.DefaultRequestRunner$1.run(DefaultRequestRunner.java:217)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:841)
Caused by: java.lang.InstantiationException: can't instantiate class trees.park.cal.smoke.models.User; no empty constructor
at java.lang.Class.newInstanceImpl(Native Method)
at java.lang.Class.newInstance(Class.java:1208)
at com.google.api.client.util.Types.newInstance(Types.java:116)
at com.google.api.client.json.JsonParser.parseValue(JsonParser.java:763)
at com.google.api.client.json.JsonParser.parseArray(JsonParser.java:647)
at com.google.api.client.json.JsonParser.parseValue(JsonParser.java:739)
at com.google.api.client.json.JsonParser.parse(JsonParser.java:381)
at com.google.api.client.json.JsonParser.parse(JsonParser.java:354)
at com.google.api.client.json.JsonObjectParser.parseAndClose(JsonObjectParser.java:87)
at com.google.api.client.json.JsonObjectParser.parseAndClose(JsonObjectParser.java:81)
at com.google.api.client.http.HttpResponse.parseAs(HttpResponse.java:459)
at trees.park.cal.smoke.server.UserRequest.loadDataFromNetwork(UserRequest.java:27)
at trees.park.cal.smoke.server.UserRequest.loadDataFromNetwork(UserRequest.java:12)
at com.octo.android.robospice.request.CachedSpiceRequest.loadDataFromNetwork(CachedSpiceRequest.java:48)
at com.octo.android.robospice.request.DefaultRequestRunner.processRequest(DefaultRequestRunner.java:150)
at com.octo.android.robospice.request.DefaultRequestRunner$1.run(DefaultRequestRunner.java:217)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:841)
However, if I use the an ObjectMapper
the deserialization happens flawlessly. An example can be found in my LoginActivity (which I just wrote for testing purposes):
public class LoginActivity extends Activity{
private SpiceManager spiceManager = new SpiceManager(JacksonGoogleHttpClientSpiceService.class);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
String json = "[\n" +
" {\n" +
" \"id\": 1, \n" +
" \"email\": \"[email protected]\", \n" +
" \"password\": \"password\"\n" +
" }, \n" +
" {\n" +
" \"id\": 2, \n" +
" \"email\": \"[email protected]\", \n" +
" \"password\": \"\"\n" +
" }, \n" +
" {\n" +
" \"id\": 3, \n" +
" \"email\": \"[email protected]\", \n" +
" \"password\": \"\"\n" +
" }, \n" +
" {\n" +
" \"id\": 4, \n" +
" \"email\": \"[email protected]\", \n" +
" \"password\": \"password\"\n" +
" }\n" +
"]";
ObjectMapper mapper = new ObjectMapper();
try {
UserList result = mapper.readValue(json, UserList.class);
System.out.println("test");
} catch (IOException e) {
e.printStackTrace();
}
//stuff
}
}
If I manually replace the response.parseAs(getRequestType())
with an ObjectMapper and manually get the input stream from the HttpResponse
then I can deserialize the response perfectly.
Why can't the JsonObjectParser do what the ObjectMapper does? How can I fix this problem?
Thanks
Upvotes: 0
Views: 894
Reputation: 423
Answer is in stacktrace
Caused by: java.lang.InstantiationException: can't instantiate class trees.park.cal.smoke.models.User;
no empty constructor
Try add contructor without parameters to User
class
public User() {
}
Upvotes: 1