...
Code Block |
---|
public interface QueryAction<Criteria> { String perform(final QueryContext context, final Criteria criteria) throws QueryException; Criteria unmarshal(final String serializedCriteria) throws SerializationException; boolean isReady(); void destroy(); } |
...
Code Block |
---|
final class EchoQueryAction extends QueryAction[String] { override def unmarshal(serialized: String) = serialized override def perform(context: QueryContext, input: String) = input override def isReady = true override def destroy { } } |
This could be simplified by extending AbstractQueryAction, which provides default implementations for isReady() and destroy() which are suitable for a stateless QueryAction like EchoQueryAction:
Code Block |
---|
final class EchoQueryAction extends AbstractQueryAction[String] { override def unmarshal(serialized: String) = serialized override def perform(context: QueryContext, input: String) = input } |
QueryAction's unmarshal method defines how the input criteria is unmarshalled into a Java object. In this case, we just echoing our input, so we don't need to deserialize.
Consider a slightly more complicated QueryAction that receives as input a list of integers and returns the sum. Here the serialization format is XML, so we can extend JAXBQueryAction, which supplies an implementation of unmarshal() that uses JAXB to turn raw XML into a object in the JVM:
No Formatcode |
---|
final class AddQueryAction extends JAXBQueryAction(classOf[AddInput]) { //Take an AddInput, and return an XML-serialized AddResult override def perform(context: QueryContext, input: AddInput): String = { val result = new AddResult(input.toAdd.sum) JAXBUtils.marshalToString(result) } } |
This class takes input like:
Code Block |
---|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <ns2:AddInput xmlns:ns2="http://spin.org/xml/res/"> <number xsi:type="xs:int" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">1</number> <number xsi:type="xs:int" xmlns:xs="http://www.w3.org/2001/XMLSchemaXMLScema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">2</number> <number xsi:type="xs:int" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">3</number> </ns2:AddInput> which gets unmarshalled into a class like import java.util.{List => JList} @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "AddInput", namespace = "http://spin.org/xml/res/") @XmlRootElement(name = "AddInput", namespace = "http://spin.org/xml/res/") //The only field is a Java List, which works with JAXB final case class AddInput(private val number: JList[Int]) { { //JAXB requires a no-arg constructor; can be private *def* *this* def this() = *this*(*new* JArrayList\[Int\]) //For nicer Scala interop *def* *this* def this(toAdd: Seq\[Int\]) = *this*(*new* JArrayList(asJavaList(toAdd))) *def* def toAdd: Seq\[Int\] = number.toSeq } |
Returning Results
QueryActions return results as serialized Strings. Spin is agnostic about the contents of the returned String and, as with input, the serialization format used. In this case, if you define a class that's serializable by JAXB, like:
...