Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the ideal way to send a date parameter over a GET request in Play Framework?

I am new to Play Framework. I am able to send simple data types like string, integer etc directly via the request and access them in the Back end Java method.

When I try doing this in the route file,

GET    /food/fetchMealInfo/:noOfDays/:dateSelected     controllers.trackandplan.FoodController.fetchMealInfo(noOfDays : Integer, dateSelected : Date)

I am getting an error saying

Compilation error
not found: type Date

What is the correct, safe and clean way to transfer a date object from a front end AngularJS application to the Java application in Play Framework. Please guide.

like image 853
Rohit Rane Avatar asked May 06 '15 13:05

Rohit Rane


1 Answers

You have a couple options. The slightly easier way to understand is to simply transmit the date/time as a Long (unix timestamp), and convert it to a Date in the controller method.

GET    /food/fetchMealInfo/:noOfDays/:dateSelected     controllers.trackandplan.FoodController.fetchMealInfo(noOfDays: Integer, dateSelected: Long)

public static Result fetchMealInfo(Integer noOfDays, Long dateSelected) {
    Date date = new Date(dateSelected.longValue());
    ...
}

The more sophisticated way would be to use a PathBindable, which would allow you to use Date within the routes file itself. However, you would still need to transmit the Date as a Long (the PathBindable would make the conversion if possible). Unfortunately, since we obviously don't have control over Date, we have to implement PathBindable in Scala, and not Java (Java would require implementing an interface for Date, which we can't).

app/libs/PathBinders.scala

package com.example.libs

import java.util.Date
import play.api.mvc.PathBindable
import scala.util.Either

object PathBinders {

    implicit def bindableDate(implicit longBinder: PathBindable[Long]) = new PathBindable[Date] {

        override def bind(key: String, value: String): Either[String, Date] = {
            longBinder.bind(key, value).right.map(new Date(_))
        }

        override def unbind(key: String, date: Date): String = key + "=" + date.getTime().toString

    }

}

In order for the routes file to be able to pick this up, you'll need to add the following to your build.sbt file:

PlayKeys.routesImport += "com.example.libs.PathBinders._"

PlayKeys.routesImport += "java.util.Date"

Now you can use Date within your routes file (as Long), without the need to handle it specially for every method that uses it.

GET    /food/fetchMealInfo/:noOfDays/:dateSelected     controllers.trackandplan.FoodController.fetchMealInfo(noOfDays: Integer, dateSelected: Date)

Note: This might not compile straight away if you're using an older Play version. I tested it with Play 2.3.8 and sbt 0.13.5.

It is also possible to modify the PathBindable I made here to use an underlying String instead, and accept a specific date format.

package com.example.libs

import java.util.Date
import java.text.SimpleDateFormat
import play.api.mvc.PathBindable
import scala.util.{Either, Failure, Success, Try}

object PathBinders {

    implicit def bindableDate(implicit stringBinder: PathBindable[String]) = new PathBindable[Date] {

        val sdf = new SimpleDateFormat("yyyy-MM-dd")

        override def bind(key: String, value: String): Either[String, Date] = {
            for {
                dateString <- stringBinder.bind(key, value).right
                date <- Try(sdf.parse(dateString)).toOption.toRight("Invalid date format.").right
            } yield date
        }

        override def unbind(key: String, date: Date): String = key + "=" + sdf.format(date)

    }

}
like image 99
Michael Zajac Avatar answered Sep 24 '22 02:09

Michael Zajac