wood burning stoves*
The moose likes Spring and the fly likes Create a new object in db using Post with Spring3 RestTemplate Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Frameworks » Spring
Bookmark "Create a new object in db using Post with Spring3 RestTemplate" Watch "Create a new object in db using Post with Spring3 RestTemplate" New topic
Author

Create a new object in db using Post with Spring3 RestTemplate

Gabriela Cristian
Greenhorn

Joined: Dec 02, 2008
Posts: 18

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

Joined: Feb 05, 2001
Posts: 17260
    
    6

URLs don't match.

Is it /location

or /newLocation.

They have to match the mapping.

Mark


Perfect World Programming, LLC - Two Laptop Bag - Tube Organizer
How to Ask Questions the Smart Way FAQ
Gabriela Cristian
Greenhorn

Joined: Dec 02, 2008
Posts: 18

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

Joined: Mar 07, 2010
Posts: 1680
    
    7

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.



[How To Ask Questions][Read before you PM me]
Gabriela Cristian
Greenhorn

Joined: Dec 02, 2008
Posts: 18

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

Joined: Mar 07, 2010
Posts: 1680
    
    7

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

Joined: Dec 02, 2008
Posts: 18

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

Joined: Mar 07, 2010
Posts: 1680
    
    7

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

Joined: Dec 02, 2008
Posts: 18

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

Joined: Mar 07, 2010
Posts: 1680
    
    7

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

Joined: Dec 02, 2008
Posts: 18

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

Joined: Mar 07, 2010
Posts: 1680
    
    7

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

Joined: Dec 02, 2008
Posts: 18

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

Joined: Mar 07, 2010
Posts: 1680
    
    7

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

Joined: Mar 07, 2010
Posts: 1680
    
    7

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

Joined: Dec 02, 2008
Posts: 18

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!
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: Create a new object in db using Post with Spring3 RestTemplate