We will also look at sending POST requests with Dojo.
You need Java 6 for this and I am also using JBoss 6.0.0.M1.
POST requests are the C in CRUD. What it means is you use it to create new items. Please see this little table.
Operation | REST method | Sample URI |
---|---|---|
Return item(s) | GET | /books (all books) /books/ (all books) /books/12 (one book with ID = 12) |
Create a new item | POST | (you pass the ID in the object itself) /books /books/ |
Update an item | PUT | (you pass the ID in the object itself) /books /books/ |
Delete an item | DELETE | /books/12 (book with ID = 12) |
As you can see, in the POST or PUT case we are not passing the ID. Instead, we will pass the entire object! Spring MVC makes it possible for us to retrieve the object straight from REST and does all the binding for us.
Also, some of the URIs are identical across the methods. That's perfectly correct - it's the method (POST, PUT) that makes the distinction. You don't have to do any additional handling in your controller methods (actions).
Let us take a look at the controller then. The code should be familiar by now.
@RequestMapping(value = "/books", method = RequestMethod.POST) public BookTO handleBookSave(HttpServletResponse response, @RequestBody @Valid BookTO bookTO) { BooksBean booksBean = Factory.getBooksBean(); return booksBean.saveBook(bookTO); }
First, notice the RequestMapping annotation and the URI that it handles (/books). Second, notice the method - it's POST which means it's supposed to handle the create case.
It's a controller method which means it's an entry point to handle REST requests and - as promised - it already retrieves an object! How does it happen? Well, that's thanks to the RequestBody annotation. It does auto-binding for us and also does type validation.
What is the Valid annotation for? It tells Spring to do JSR-303 on that object when binding. It uses Hibernate constraints, to be precise (the previously mentioned type checking is independent of this and happens with or without the Valid annotation). Please take a look at this TO object that we validate and note the validation annotations needed for JSR-303.
import javax.validation.constraints.NotNull; import org.hibernate.validator.constraints.Length; public class BookTO { // ... @NotNull @Length(min = 20) public String getName() { return name; } }
See? It's pretty easy. But... Yeah, there's a problem with it - it doesn't work. That's right, it doesn't work. What's the problem with it? Take a look at the controller code. We have two annotations on the method argument (@Valid and @RequestBody) and when combined, Spring ignores the Valid annotation. It's a bug and it has already been submitted to Spring JIRA. Let's hope this get resolved when Spring 3.1 comes out; I'm keeping my eye on it.
Let's also look at the Dojo part of the story.
function saveBook(bookName) { var newBook = { "name":bookName }; var actualContent = dojo.toJson(newBook); //Save. var deferred = this._request("rawXhrPost", { url: "http://localhost:8080/restsample-0.0.1-SNAPSHOT/rest/books.json", handleAs: "json", postData: actualContent, headers: { "Content-Type": "application/json"} }); deferred.addCallback(this, function(value) { alert("Saved! " + value.bookTO.name); }); deferred.addErrback(this, function(value) { alert("Error: " + value); }); }
We first create an object to pass - the fields have to match the TO object fields (the names have to be the same).
Then we use dojo.toJson to convert this object to a JSON string.
Next, we call our RESTful service. Notice the method - it's rawXhrPost as we need it raw for binding to work. We also pass the object (well, it's a string at this point) as postData. For PUT requests we will use, you guessed it, putData.
And that's all! Download the sample code for this article if you wish.
- REST with Spring 3.0, Spring MVC and Dojo. Part 1 - GET
- REST with Spring 3.0, Spring MVC and Dojo. Part 2 - GET from Dojo perspective
- REST with Spring 3.0, Spring MVC and Dojo. Part 3 - POST and JSR-303 validation
- REST with Spring 3.0, Spring MVC and Dojo. Part 4 - PUT (updating objects)
- REST with Spring 3.0, Spring MVC and Dojo. Part 5 - DELETE
Hi I just downloaded the source and when I tried to start the Jetty server I'm getting these errors:
ReplyDeleteWhat am I missing? Thank you.
SEVERE: Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter#0' defined in ServletContext resource [/WEB-INF/rest-servlet.xml]: Cannot create inner bean 'org.springframework.web.bind.support.ConfigurableWebBindingInitializer#1f243d1' of type [org.springframework.web.bind.support.ConfigurableWebBindingInitializer] while setting bean property 'webBindingInitializer'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.web.bind.support.ConfigurableWebBindingInitializer#1f243d1' defined in ServletContext resource [/WEB-INF/rest-servlet.xml]: Cannot resolve reference to bean 'validator' while setting bean property 'validator'; nested exception is org.springframework.beans.factory.CannotLoadBeanClassException: Error loading class [org.springframework.validation.beanvalidation.LocalValidatorFactoryBean] for bean with name 'validator' defined in ServletContext resource [/WEB-INF/rest-servlet.xml]: problem with class file or dependent class; nested exception is java.lang.NoClassDefFoundError: javax/validation/ValidatorFactory
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBean(BeanDefinitionValueResolver.java:281)
Is this still a bug in Spring?
ReplyDeleteHi, well the root cause is "nested exception is java.lang.NoClassDefFoundError: javax/validation/ValidatorFactory" so I would assume that while JBoss (I ran it on JBoss) has the proper class, Jetty doesn't.
ReplyDeleteHi,
ReplyDeleteI got Jetty to run, the app is working except for saving a book. I'm getting java.lang.NoSuchMethodError: org.codehaus.jackson.map.type.TypeFactory.type(Ljava/lang/reflect/Type;)Lorg/codehaus/jackson/type/JavaType;
I have tried springframework 3.0.3 and 3.0.5 with org.codehaus.jackson 1.4.2+ but still getting the same error. Do you have any idea?
Thank you.
Hi, are you sure you are using Jackson 1.4.2? I'm looking at this: https://jira.springsource.org/browse/SPR-7063
ReplyDeleteYes, I have read the same post and I'm using
ReplyDeleteorg.codehaus.jackson
jackson-mapper-asl
1.4.2
org.codehaus.jackson
com.springsource.org.codehaus.jackson.mapper
1.4.2
Now that I'm using 1.6.2, it's working for me.
ReplyDeleteExcellent. :) Good luck with it and thanks for visiting the blog!
ReplyDeleteI have data in Oracle in HTML form. I need to send this data in XML or JSON format. What is the best way to send html data in XML or JSON format?
ReplyDeleteHi kanneganti75,
ReplyDeleteI would expect it to be escaped automatically so you shouldn't worry.
Hi Michal,
ReplyDeleteThank you. But I need to put this html in CDATA. How can I do that? Could you please suggest me the best approach?
Sorry to answer question with a question - why do you need to put it in CDATA?
ReplyDeleteMaybe you don't?
May be I don't.That was the suggestion from my tech lead.I am sorry to bother you. I have one more query related to xml output. If data is empty jaxbMarshaller is not generating xml tag. How can I generate empty xml tags if data null
ReplyDeleteYou're not bothering me at all. :)
ReplyDeleteTo answer your question - from my experience marshallers often behave counter intuitive. I doubt you can alter its behaviour - your code should rather accommodate it. If you feel this is a bug - you should report it. Alternatively, you may want to try a different marshaller.
Cheers
Hi Michal,
ReplyDeleteI have one more question.I have more than one domain classes and relation is one to many. I need to generate xml in the following format.
Here I have two domain objects 1. emp 2. address
relationship one to many
Using JAXB how to marshall the object to the xml
Alternatively, I thought of creating a database view and map the view to the domain object.In this case I need to generate XML wrapper elements addressInfo
address type="home".
Please suggest.
Hi, I have one more quick question. How to handle images and videos in Spring REST. Images are stored in db. Also can I use MOXy JAXB with JPA and Hibernate 3.6?
ReplyDeleteHi, I have one more quick question. How to handle images and videos in Spring REST. Images are stored in db. Also can I use MOXy JAXB with JPA and Hibernate 3.6?
ReplyDeleteHi Srinivas, I have never done this, I can't answer your question. I can only suggest this discussion: http://codemonkeyism.com/how-to-put-binary-data-with-rest/
ReplyDeletegoogle 1729
ReplyDeletegoogle 1730
google 1731
google 1732
google 1733
Virginia Reckless Driving Attorneyis a legal professionals who expert in handling traffic related casese in virginia,Maryland,New jersey.The most informative post.
ReplyDelete