In this article I’m going to continue exploring enterprisy (thanks JavaPosse#298 for this expression) development with Scala and sharing my experience with those Java developers, who slowly start to recognize power and usability of this beautiful language, combined with ability to stay in the comfort area of both known and new high-grade Java frameworks. Previously, I briefly described, how iBatis 3.0 framework can be used together with Scala in order to build a robust persistence layer. In what follows I will show, how easy it is to build REST endpoints with JAX-RS and SJSON library in Scala.
Jersey is the free production-ready implementation of jsr-311. It’s one of the simplest JAX-RS frameworks to use due to POJO (and also POSO) support with a wide range of annotations, and a very small additional configuration to be done in web.xml (no web.xml alteration at all is required if you use Grizzly (Simple/lightweight) HTTP web server, but I’m going to deploy my services on Tomcat). SJSON is the library developed by Debasish Ghosh that allows users to serialize/deserialize Scala classes into JSON with a very small effort (literlly, 1-2 annotations per class).
First of all, you need to update definitions of your domain classes, so that they can be recognized by SJSON:
case class Author(id: String, name: String) extends DomainClass{
private def this() = this(null, null)
}
@BeanInfo
case class Topic(id: String, name: String) extends DomainClass{
private def this() = this(null, null)
}
@BeanInfo
case class Idea(id: String, subject: String, body: String, date: Date,
@JSONTypeHint(classOf[Author]) var author: Author,
@JSONTypeHint(classOf[Topic]) var topic: Topic) extends DomainClass{
override def equals (o: Any) = o match {
case m: Idea => id equals m.id
case _ => false
}
def this(id: String, subject: String, body: String, date: Date) = this(id, subject, body, date, null, null)
private def this() = this(null, null, null, null, null, null)
}
@BeanInfo is the minimal required annotation to serialize/deserialize Scala objects into JSON. With this annotation, all the class properties of standard types will be extracted and added to JSON object instance. For the nested types that need to be converted appropriately @JSONTypeHint(classOf[<[de]serializable class with @BeanInfo annotation>]) annotation must be used.
Secondly, we need to declare REST endpoints:
def serializeAsJSON(obj: AnyRef): String = new String(Serializer.SJSON.out(obj))
def deserializeJSON[T](json: Array[Byte])(implicit m: Manifest[T]): AnyRef =
Serializer.SJSON.in[T](json)(m)
}
@Path("/idea")
class IdeaResource extends ResourcesUtil{
@PUT
def addIdeaToTopic(@Context headers: HttpHeaders, in: Array[Byte]) = {
IdeaBoxAssembly.submitIdea(
deserializeJSON[Idea](in).asInstanceOf[Idea])
}
}
@Path("/ideas")
class IdeasResource extends ResourcesUtil{
@GET @Path("/{topicId}")
@Produces(Array("application/json"))
def getIdeas(@PathParam("topicId") topicId:String):String = {
serializeAsJSON(IdeaBoxAssembly.getIdeasListByTopicId(topicId))
}
}
I have intentionally removed all JavaDocs comments, so that it become obvious how much code is required to implement REST-services (but you can find all the original code here). For more information on JAX-RS annotation you can refer to JAX-RS 1.1 specification draft.
Finally, you need to put some lines to web.xml:
<servlet-name>Jersey Web Application</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.resourceConfigClass</param-name>
<param-value>com.sun.jersey.api.core.PackagesResourceConfig</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.vasilrem.ideabox.web.resources</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey Web Application</servlet-name>
<url-pattern>/resources/*</url-pattern>
</servlet-mapping>
You need to declare the servlet (one of Jersey API) that will interrupt calls to resources, and process them correclty. And that’s all – just a few annotations here and there added to POSOs to make things work.
Specification below describes the behavior of idea/ideas resources:
"New idea, submitted via REST-service (PUT idea to resource location) " should{
"appear in the list of ideas (GET ideas from resource location)" in{
ideaResource.addIdeaToTopic(null, ideaJSON.getBytes)
ideasResource.getIdeas("1") must eventually(include(""""id":"Dummy Idea ID","subject":"Dummy Idea","topic":{"id":"1","name":"General"}}"""))
}
}
Tags: architecture, IdeaBox, java, JAX-RS, Jersey, JSON, jvm, REST, scala







Thank you! You guys do a wonderful blog, and have some wonderful contests. Maintain up the great perform.