An MVC library for the Spark-Kotlin project
Caisson is an attempt introduce some basic MVC functionality to the Spark-Kotlin project. It is inspired by SpringMVC, but with a much smaller and simpler scope. Step one is to introduce model binding and converters to Spark-Kotlin, using annotations and reflection to construct instances of Kotlin classes from a Spark-Kotlin request parameter map.
Users of the library will be able to bind any model class from a spark-kotlin request, mapping the request param names to the constructor parameters for the model. For instance, to bind the Person
model from the spark-kotlin request, simply call the bind<>()
function on the request
, supplying the model class in the generics diamonds.
post("/addPerson") {
val person = request.bind<Person>()
println("person is ${person?.name}, born on ${person?.date}")
}
This assumes the following Person
model and a custom converter class (annotated with @CConverter
) to parse the request parameter string. Note that only fields defined in the class's primary constructor can be bound; you are welcome to add additional fields or calculated values in the class's init { }
block. A data class
is an obvious choice for a model, but ordinary classes work too.
data class Person(val name:String, @CConverter(converterClass = SimpleDateConverter::class) val date: Date)
class SimpleDateConverter : Converter {
override fun convert(from: String): Date? {
val sdf: SimpleDateFormat = SimpleDateFormat("dd/MM/yyyy")
try {
return sdf.parse(from)
} catch (e: ParseException) {
return Date()
}
}
}
To implement file uploading, your model class must contain a field of type CaissonMultipartContent
(or a List of these). Caisson will store each of the uploaded files' bytestreams in the CaissonMultipartContent
object:
data class MyFiles(val upload: List<MultipartCaissonContent>)
And use these classes with Spark-Kotlin's normal request object. You must specify the names of the HTML input components used.
<form name="fileUpload">
<input type="file" name="upload">
<input type="file" name="upload">
</form>
val myFiles = request.bind<MyFiles>(arrayListOf("upload"))
Alternatively, if each input component has a different name, supply a List of their names as the third parameter.
<form name="fileUpload">
<input type="file" name="drivingLicense">
<input type="file" name="passport">
</form>
val myFiles = request.bind<MyFiles>(arrayListOf("drivingLicense","passport"))
This project is in the very earliest stages, and I have a lot to learn about Kotlin, HTTP requests, Reflection and more besides. So don't even think of using it :). There is a corresponding demo project hosted on github called https://github.com/v79/spark-caisson-integration which implements all the features of Caisson and may prove useful while I'm still working on the documentation.