Win a copy of Design for the Mind this week in the Design forum!
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

Create a new object in db using Post with Spring3 RestTemplate

 
Gabriela Cristian
Greenhorn
Posts: 18
Android
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I am using Spring 3 RestTemplate and trying to add a new object (in JSON format) from a client accessing an url that has some logic on the server side.

This is what i use from the client:

String url = "http://..../location/add";
HttpEntity<Location> entity = new HttpEntity<Location>(newLocation);
ResponseEntity<Location> response = restTemplate.postForObject(url, HttpMethod.POST, Location.class, newLocation);

The variable "restTemplate" is not null, and the same with the "newLocation" object(it has all the information needed).

On server side:


@RequestMapping(method = RequestMethod.POST, value = "/newlocation/add", headers = "Accept=application/json,text/html,application/xhtml+xml,application/xml")
public @ResponseBody
Location addLocation(@RequestBody final Location newLocation) {
locationService.saveOrUpdate(newLocation);
return newLocation;
}

The result is always :

resulted in 404 (Not Found); invoking error handler

this error.

My question is kinda off a duplicate for this thread: http://stackoverflow.com/questions/9708210/spring-resttemplate-post-body, that does not have any leads so far

I don't understand why this does not work...

Thank you for your time.
 
Mark Spritzler
ranger
Sheriff
Posts: 17278
6
IntelliJ IDE Mac Spring
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
URLs don't match.

Is it /location

or /newLocation.

They have to match the mapping.

Mark
 
Gabriela Cristian
Greenhorn
Posts: 18
Android
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Yes, you are right, i have corrected that and i still have the error:
FATAL EXCEPTION: AsyncTask #3
[2012-05-30 00:25:13 - Emulator] E/AndroidRuntime( 447): java.lang.RuntimeException: An error occured while executing doInBackground()
[2012-05-30 00:25:13 - Emulator] E/AndroidRuntime( 447): at android.os.AsyncTask$3.done(AsyncTask.java:266)
[2012-05-30 00:25:13 - Emulator] E/AndroidRuntime( 447): at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273)
[2012-05-30 00:25:13 - Emulator] E/AndroidRuntime( 447): at java.util.concurrent.FutureTask.setException(FutureTask.java:124)
[2012-05-30 00:25:13 - Emulator] E/AndroidRuntime( 447): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)
[2012-05-30 00:25:13 - Emulator] E/AndroidRuntime( 447): at java.util.concurrent.FutureTask.run(FutureTask.java:137)
[2012-05-30 00:25:13 - Emulator] E/AndroidRuntime( 447): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1081)
[2012-05-30 00:25:13 - Emulator] E/AndroidRuntime( 447): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:574)
[2012-05-30 00:25:13 - Emulator] E/AndroidRuntime( 447): at java.lang.Thread.run(Thread.java:1020)
[2012-05-30 00:25:13 - Emulator] E/AndroidRuntime( 447): Caused by: org.springframework.web.client.HttpClientErrorException: 400 Bad Request
[2012-05-30 00:25:13 - Emulator] E/AndroidRuntime( 447): at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:75)
[2012-05-30 00:25:13 - Emulator] E/AndroidRuntime( 447): at org.springframework.web.client.RestTemplate.handleResponseError(RestTemplate.java:499)
[2012-05-30 00:25:13 - Emulator] E/AndroidRuntime( 447): at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:456)
[2012-05-30 00:25:13 - Emulator] E/AndroidRuntime( 447): at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:414)
[2012-05-30 00:25:13 - Emulator] E/AndroidRuntime( 447): at org.springframework.web.client.RestTemplate.postForEntity(RestTemplate.java:315)
[2012-05-30 00:25:13 - Emulator] E/AndroidRuntime( 447): at com.be.android.locateconsultants.persistence.AsyncTaskSaveLocation.doInBackground(AsyncTaskSaveLocation.java:62)
[2012-05-30 00:25:13 - Emulator] E/AndroidRuntime( 447): at com.be.android.locateconsultants.persistence.AsyncTaskSaveLocation.doInBackground(AsyncTaskSaveLocation.java:1)
[2012-05-30 00:25:13 - Emulator] E/AndroidRuntime( 447): at android.os.AsyncTask$2.call(AsyncTask.java:252)
[2012-05-30 00:25:13 - Emulator] E/AndroidRuntime( 447): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
[2012-05-30 00:25:13 - Emulator] E/AndroidRuntime( 447): ... 4 more


I think i am missing the point here, and doing this "create new object" wrong.
Isn't this suppose to send my object that i want to create?

HttpEntity<Location> entity = new HttpEntity<Location>(
newLocation);
ResponseEntity<Location> response = restTemplate.postForEntity(
url, entity, Location.class);
?
 
Bill Gorder
Bartender
Posts: 1682
7
Android IntelliJ IDE Linux Mac OS X Spring
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
If you are using spring 3.1 prefer produces and consumes over setting the headers the old way.


Once you have done this the controller is expecting the content type header on the incoming message to be set to one of the accepted values in the consumes. It is going to look at accept header on the request and will oblige by returning that type (assuming that it is one of the types defined in the produces). You are getting a 400 bad request because these headers are not being set properly.

You could make a couple generic methods like I have shown below and pass your Location object to getHttpEntityWithJsonHeaders. This will return the HttpEntity with the headers properly set to send and receive JSON from the controller.

 
Gabriela Cristian
Greenhorn
Posts: 18
Android
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hello,

I followed your advice but still crashes at this line :
ResponseEntity<Location> response = restTemplate.postForEntity(
url, entity, Location.class);


I think i will try to change the url, asking for a value for each property from Location:
/newlocation/add/{city}/{country}...
 
Bill Gorder
Bartender
Posts: 1682
7
Android IntelliJ IDE Linux Mac OS X Spring
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Yeah if you took my example exactly as I wrote it, it would fail (I think I was tired)


This line should be like this for using multiple headers. I think I must have been tired.



Let me know what the exception is if it is still dying on you.

Also if it does still die on you try one more thing for me. Remove the produces and consumes altogether (but leave in the bit that sets the headers on the client side) and try it again. This should tell the controller to essentially accept anything. I want to see if we can at least get in your handler method. I am fairly certain your error is a header issue. The other thing you can do is use hte RestClient plugin for Firefox to test your controller. Just be sure to set the headers on that as well.

Thanks,
 
Gabriela Cristian
Greenhorn
Posts: 18
Android
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hello, thank you first for your help and time spent so far.

This is the error ...
[]======URL : http://10.0.2.2:8080/AppBackend/service/location/add
[2012-05-30 15:27:05 - Emulator] D/dalvikvm( 549): GC_CONCURRENT freed 325K, 6% free 7694K/8135K, paused 5ms+8ms
[2012-05-30 15:27:05 - Emulator] W/dalvikvm( 549): threadid=9: thread exiting with uncaught exception (group=0x40014760)
[2012-05-30 15:27:05 - Emulator] E/AndroidRuntime( 549): FATAL EXCEPTION: AsyncTask #1
[2012-05-30 15:27:05 - Emulator] E/AndroidRuntime( 549): java.lang.RuntimeException: An error occured while executing doInBackground()
[2012-05-30 15:27:05 - Emulator] E/AndroidRuntime( 549): at android.os.AsyncTask$3.done(AsyncTask.java:266)
[2012-05-30 15:27:05 - Emulator] E/AndroidRuntime( 549): at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273)
[2012-05-30 15:27:05 - Emulator] E/AndroidRuntime( 549): at java.util.concurrent.FutureTask.setException(FutureTask.java:124)
[2012-05-30 15:27:05 - Emulator] E/AndroidRuntime( 549): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)
[2012-05-30 15:27:05 - Emulator] E/AndroidRuntime( 549): at java.util.concurrent.FutureTask.run(FutureTask.java:137)
[2012-05-30 15:27:05 - Emulator] E/AndroidRuntime( 549): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1081)
[2012-05-30 15:27:05 - Emulator] E/AndroidRuntime( 549): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:574)
[2012-05-30 15:27:05 - Emulator] E/AndroidRuntime( 549): at java.lang.Thread.run(Thread.java:1020)
[2012-05-30 15:27:05 - Emulator] E/AndroidRuntime( 549): Caused by: java.lang.IllegalArgumentException: Invalid amount of variables values in [http://10.0.2.2:8080/AppBackend/service/location/add]: expected 0; got 1
[2012-05-30 15:27:05 - Emulator] E/AndroidRuntime( 549): at org.springframework.web.util.UriTemplate.expand(UriTemplate.java:127)
[2012-05-30 15:27:05 - Emulator] E/AndroidRuntime( 549): at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:413)
[2012-05-30 15:27:05 - Emulator] E/AndroidRuntime( 549): at org.springframework.web.client.RestTemplate.postForEntity(RestTemplate.java:315)
[2012-05-30 15:27:05 - Emulator] E/AndroidRuntime( 549): at com.be.android.locateconsultants.persistence.AsyncTaskSaveLocation.doInBackground(AsyncTaskSaveLocation.java:59)
[2012-05-30 15:27:05 - Emulator] E/AndroidRuntime( 549): at com.be.android.locateconsultants.persistence.AsyncTaskSaveLocation.doInBackground(AsyncTaskSaveLocation.java:1)
[2012-05-30 15:27:05 - Emulator] E/AndroidRuntime( 549): at android.os.AsyncTask$2.call(AsyncTask.java:252)
[2012-05-30 15:27:05 - Emulator] E/AndroidRuntime( 549): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
[2012-05-30 15:27:05 - Emulator] E/AndroidRuntime( 549): ... 4 more
 
Bill Gorder
Bartender
Posts: 1682
7
Android IntelliJ IDE Linux Mac OS X Spring
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The reason you are getting this error is you have must have a handler mapping with URI variables on it for example http://example.com/hotels/{hotel}/bookings/{booking}.

With a pattern like this Spring uses a class called UriTemplate and calls expand() on it. It expects 2 and exactly 2 parameters (1 for {hotel} and one for {booking} if it gets anything other than 2 it throws that exception.


Did you already change your location value to /newlocation/add/{city}/{country}... like you had talked about? If so change it back to what you had in the beginning i.e /newlocation/add

Edit: Looks like maybe it could be on the client side too. Are you setting your URL to http://10.0.2.2:8080/AppBackend/service/location/add but passing in extra parameters?
 
Gabriela Cristian
Greenhorn
Posts: 18
Android
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Yes, i have corrected that
[]======URL to add: http://10.0.2.2:8080/AppBackend/service/location/add
[2012-05-30 16:18:50 - Emulator] D/dalvikvm( 450): GC_CONCURRENT freed 333K, 6% free 7698K/8135K, paused 5ms+8ms
[2012-05-30 16:18:51 - Emulator] D/dalvikvm( 450): GC_CONCURRENT freed 665K, 10% free 7489K/8263K, paused 5ms+4ms
[2012-05-30 16:18:51 - Emulator] I/dalvikvm( 450): Jit: resizing JitTable from 512 to 1024
[2012-05-30 16:18:52 - Emulator] W/RestTemplate( 450): POST request for "http://10.0.2.2:8080/AppBackend/service/location/add" resulted in 400 (Bad Request); invoking error handler
[2012-05-30 16:18:52 - Emulator] W/dalvikvm( 450): threadid=10: thread exiting with uncaught exception (group=0x40014760)
[2012-05-30 16:18:52 - Emulator] E/AndroidRuntime( 450): FATAL EXCEPTION: AsyncTask #1
[2012-05-30 16:18:52 - Emulator] E/AndroidRuntime( 450): java.lang.RuntimeException: An error occured while executing doInBackground()
[2012-05-30 16:18:52 - Emulator] E/AndroidRuntime( 450): at android.os.AsyncTask$3.done(AsyncTask.java:266)
[2012-05-30 16:18:52 - Emulator] E/AndroidRuntime( 450): at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273)
[2012-05-30 16:18:52 - Emulator] E/AndroidRuntime( 450): at java.util.concurrent.FutureTask.setException(FutureTask.java:124)
[2012-05-30 16:18:52 - Emulator] E/AndroidRuntime( 450): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)
[2012-05-30 16:18:52 - Emulator] E/AndroidRuntime( 450): at java.util.concurrent.FutureTask.run(FutureTask.java:137)
[2012-05-30 16:18:52 - Emulator] E/AndroidRuntime( 450): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1081)
[2012-05-30 16:18:52 - Emulator] E/AndroidRuntime( 450): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:574)
[2012-05-30 16:18:52 - Emulator] E/AndroidRuntime( 450): at java.lang.Thread.run(Thread.java:1020)
[2012-05-30 16:18:52 - Emulator] E/AndroidRuntime( 450): Caused by: org.springframework.web.client.HttpClientErrorException: 400 Bad Request
[2012-05-30 16:18:52 - Emulator] E/AndroidRuntime( 450): at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:75)
[2012-05-30 16:18:52 - Emulator] E/AndroidRuntime( 450): at org.springframework.web.client.RestTemplate.handleResponseError(RestTemplate.java:499)
[2012-05-30 16:18:52 - Emulator] E/AndroidRuntime( 450): at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:456)
[2012-05-30 16:18:52 - Emulator] E/AndroidRuntime( 450): at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:414)
[2012-05-30 16:18:52 - Emulator] E/AndroidRuntime( 450): at org.springframework.web.client.RestTemplate.postForEntity(RestTemplate.java:315)
[2012-05-30 16:18:52 - Emulator] E/AndroidRuntime( 450): at com.be.android.locateconsultants.persistence.AsyncTaskSaveLocation.doInBackground(AsyncTaskSaveLocation.java:59)
[2012-05-30 16:18:52 - Emulator] E/AndroidRuntime( 450): at com.be.android.locateconsultants.persistence.AsyncTaskSaveLocation.doInBackground(AsyncTaskSaveLocation.java:1)
[2012-05-30 16:18:52 - Emulator] E/AndroidRuntime( 450): at android.os.AsyncTask$2.call(AsyncTask.java:252)
[2012-05-30 16:18:52 - Emulator] E/AndroidRuntime( 450): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
[2012-05-30 16:18:52 - Emulator] E/AndroidRuntime( 450): ... 4 more


Thanks
 
Bill Gorder
Bartender
Posts: 1682
7
Android IntelliJ IDE Linux Mac OS X Spring
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ok so lets try to to broaden the scope of what the controller will take. Remove any consumes= produces= or header= from your request mapping, and see if you can at least get into the controller method. You can try it with and without setting the headers on the client side (by that I mean using the 2 methods I provided earlier).

If you set a break point on the first line of your handler method in your controller you should be able to hit it.

Thanks,
 
Gabriela Cristian
Greenhorn
Posts: 18
Android
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
It doesn't even enter in the controller(from the server side)

It all stops in the client:
Caused by: org.springframework.web.client.HttpClientErrorException: 400 Bad Request
and sometimes it gives me error 404 not found.

 
Bill Gorder
Bartender
Posts: 1682
7
Android IntelliJ IDE Linux Mac OS X Spring
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Lets try to test the controller mapping independently of the RestTemplate.

1. Install this add-on for firefox https://addons.mozilla.org/en-US/firefox/addon/restclient/
2. Once it is installed open it from the tools menu in firefox
3. Select the headers option at the top and select 'custom header' (you will do this twice and add both the following
-- Name = Content-Type value = application/json
-- Name = Accept value = application/json
4. Set the method to POST
5 Set the URL to 10.0.2.2:8080/AppBackend/service/location/add
6. Put some valid JSON for your location in the Body input field
7. Click SEND

See if you get into your controller.

Thanks
 
Gabriela Cristian
Greenhorn
Posts: 18
Android
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Wow, this tool is very useful for me. Thank you.

I made the request and it told me that the request syntax is not correct. This is what i am trying to send as a json format:
{
"idlocationhistory": 33,
"city": "sibiu",
"country": "palilula",
"hotel": "Gigel",
"start_date": 1328133600000,
"end_date": 1328133600000,
"consultantId": 1,
"hotel_address": "testm",
"created": 1328133600000
}

and it tell me "The request sent by the client was syntactically incorrect ()". So now i am checking the type of data if it's correct.
I looked on this tutorial here and the JSON format should be with brakets {} right?
 
Bill Gorder
Bartender
Posts: 1682
7
Android IntelliJ IDE Linux Mac OS X Spring
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
At first glance it is syntactically correct JSON, but that does not mean it is right.


A couple other questions:

1. Do you have jackson on the classpath for both the client and server projects?



2. Is your location object a simple pojo? By that I mean are there any methods public or private that are not getters and setters for the fields?

If the answer to 1 is yes and the answer to 2 is yes I guess I will need to you post your Location POJO in its entirety so I can see if something stands out. I would look to make sure that your field names match the getter and setter names (best way to do this is let eclipse generate the getter and setters) if you have refactored field names maybe just delete the getters and setters and regenerate them. Also make sure that the JSON you are posting below matches the field names. Do you really use field names with underscores in it? Do you really have a field called idlocationhistory in your pojo or is it camel case like idLocationHistory? These need to match up.

Thanks,
 
Bill Gorder
Bartender
Posts: 1682
7
Android IntelliJ IDE Linux Mac OS X Spring
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Meh I gave you bad info for the jackson library. What I posted is right for the server side since it looks like you are using spring-android on the client side you will want to follow this for including the correct jackson lib.

http://static.springsource.org/spring-android/docs/1.0.0.RC1/reference/htmlsingle/#rest-template-howtoget-jackson

(You can alternatively use GSON and as long as it marshals to equivalent JSON that should be fine as well)
 
Gabriela Cristian
Greenhorn
Posts: 18
Android
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hello,
Sorry for this late reply. Yes i am using Spring on the server side and Android for the client side.
On the Android part i did not make use of JACKSON and maybe this is the trouble. On the server side i configured this and it works, because i can for instance get a response of all users in the my database, so it reaches my controllers on the server or do anything that uses Http GET. Found this article: here and will follow your link as well.
Thank you!
 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic