06 novembro 2008

RESTful Web Services with Wicket


Here at ApacheCon, with the help of Jeremy Thomerson I could finally finish an idea I had months ago. How to easily provide simple RESTful Web Services with Wicket?

Basically, I wanted to output an Object as an XML with XStream. And the result is this simple class that you can extend and just have to provide a model with an object inside. Whatever is inside the model, gets outputted. :-)

So take a look at the class and use it as you wish.

package org.wicketstuff.wicketws;

import java.io.PrintWriter;

import org.apache.wicket.Component;
import org.apache.wicket.behavior.IBehavior;
import org.apache.wicket.markup.MarkupStream;
import org.apache.wicket.markup.html.WebPage;

import com.thoughtworks.xstream.XStream;

/**
* RESTful WebSevice page
*/
public abstract class WebServicePage extends WebPage {

private static final long serialVersionUID = 1L;

public WebServicePage() {
setStatelessHint(true);
}

protected final void onRender(MarkupStream markupStream) {
PrintWriter pw = new PrintWriter(getResponse().getOutputStream());
pw.write(getXML().toString());
pw.close();
}

protected XStream createXStream() {
XStream xstream = new XStream();
xstream.setMode(XStream.ID_REFERENCES);
return xstream;
}

private CharSequence getXML() {
XStream xstream = createXStream();
return xstream.toXML(getDefaultModelObject());
}

@Override
public final String getMarkupType() {
return "xml";
}

@Override
public final boolean hasAssociatedMarkup() {
return false;
}

@Override
public final Component add(IBehavior... behaviors) {
throw new UnsupportedOperationException(
"WebServicePage does not support IBehaviours");
}

}

And here's a quick example of a WebService:

package org.wicketstuff.wicketws;

import org.apache.wicket.PageParameters;
import org.apache.wicket.model.Model;

public class UserInfo extends WebServicePage {

public UserInfo(PageParameters pg) {
Integer id = pg.getAsInteger("id");
if (id == null) {
id = 1;
}

User user = ((WicketApplication) getApplication()).getUser(id);
setDefaultModel(new Model(user));
}

}

Oh, and don't forget to mount your WebService to get the default URL Strategy that is REST-like in Wicket.

@Override
protected void init() {
mountBookmarkablePage("userInfo", UserInfo.class);
}

Now all you have to do is access http://localhost:8080/myapp/userInfo/id/1

Done!! :D

4 comentários:

Unknown disse...

Just wanted to say THANKS for a great article. It worked without any problems. I thought it might choke on nested Maps which we have in our User object to represent roles and permissions, but it transformed the Maps perfectly. The combination of Wicket and XStream makes for a really nice service provider.

jonathan disse...

Now, can you make it take a POSTed XStream-encoded object? I could use that kind of transparency! -- Jonathan Locke

CricDigs disse...

this was great! I digged it :)

Jesse Piascik disse...

Thanks so much for this. I'm using it extensively in a project I am working on. In fact I have extended it to take xml in the body of the http request, as well as JSON and JSON-RPC. The code is at http://code.google.com/p/wicket-rest/

Contato

Email:bruno.borges(at)gmail.com

LinkedIn: www.linkedin.com/in/brunocborges
Twitter: www.twitter.com/brunoborges
Comprei e Não Vou
Rio de Janeiro, RJ Brasil
Oracle
São Paulo, SP Brasil