Eval Tree in Scala 2.11.7 - scala

I'm trying to implement JSON-RPC server in Scala and want to mark my remote methods with annotations. Also it will be nice if method itself should not be worried about input parameters validation, so I want to put this validations inside annotation. I ended up with this:
class RPCMethod(validators: (String, PartialFunction[Any, Boolean])*) extends StaticAnnotation
And remote method is annotated like this:
#RPCMethod(
"name" -> {
case x: String => x == "Andrey"
}
)
Now I'm trying to extract the {case ...} part and eval it to a function to check inbound value. But all I could get with reflection is a Tree:
val annotation = method.annotations.find(_.tree.tpe == typeOf[RPCMethod]).get
val validators = annotation.tree.children.tail
if (validators.isEmpty) {
return true
} else {
validators.head match {
case q"scala.this.Predef.ArrowAssoc[$_](${name: String}).->[$_]($func)" => // Don't know how to eval 'func'
case _ => throw some error
}
}
So how can I get a valid function object from this Tree?

Related

Possible ways to check if a value exists in a sequence scala

case class dummy(val prop:Seq[Test])
case class Test(val s :String)
case class Result(val s :String)
def myFunc:Result = {
val s = "11,22,33"
val t = Test(s)
val list = dummy(Seq(t))
val code = Option("25")
val result = code.exists(p => {
list.prop.exists(d => d.s.split(",").contains(p))
})
if (result) {
Result("found")
} else {
Result("Not Found")
}
}
I am calling function myFunc, but instead of evaluating a boolean using if/else construct.
Any possible ways to avoid using If else construct
There is nothing wrong with using the if/else, but you could do this:
code
.flatMap(c => list.prop.find(_.s.split(",").contains(c)))
.map(_ => Result("Found")).getOrElse(Result("Not Found"))
The idea here is that instead of returning a Boolean at each stage we are passing an Option along. Then at the end if the Option is defined we can map that into a Result("Found"), and if it is not defined the .getOrElse will return a Result("Not Found").

Loss of type info in servlet code

I have a simple flash implementation for use with Jersey that looks like this:
#PostConstruct def before { flash.rotateIn }
#PreDestroy def after { flash.rotateOut }
object flash {
val KeyNow = "local.flash.now"
val KeyNext = "local.flash.next"
// case class Wrapper(wrapped: Map[String, Seq[String]])
case class Wrapper(wrapped: String)
def rotateIn {
for {
session <- Option(request.getSession(false))
obj <- Option(session.getAttribute(KeyNext))
} {
request.setAttribute(KeyNow, obj)
session.removeAttribute(KeyNext)
}
}
def rotateOut {
for (obj <- Option(request.getAttribute(KeyNext))) {
request.getSession.setAttribute(KeyNext, obj)
}
}
def now = Option(request.getAttribute(KeyNow)) match {
case Some(x: Wrapper) => x.wrapped
case Some(x) if x.isInstanceOf[Wrapper] => "WHAT"
case _ => "NOPE"
}
def next(value: String) {
request.setAttribute(KeyNext, Wrapper(value))
}
}
I have simplified it here somewhat, but it lets me set a value for flash with flash.next and read the current flash value with flash.now.
The weird thing is that my now value is always "WHAT". If I do something similar in my REPL, I don't have the same issues:
val req = new org.springframework.mock.web.MockHttpServletRequest
val res = req.getSession
res.setAttribute("foo", Wrapper("foo"))
req.setAttribute("foo", res.getAttribute("foo"))
// Is not None
Option(req.getAttribute("foo")).collect { case x: Wrapper => x }
Am I missing something obvious?
EDIT
I've added a minimal example webapp replicating this issue at https://github.com/kardeiz/sc-issue-20160229.
I tried your example. Check my answer for your other question for details how pattern matching works in this case.
In short, as you Wrapper is an inner class, patter matching also checks the "outer class" reference. It seems that depending on the application server implementation Router.flash can be different instance for each request, so pattern matching fails.
Simple fix for that is to make Wrapper top-level class, so it doesn't have reference to any other class.

How to define a custom argument matcher with mockito in spec2?

I want to verify if the business logic passes the expected user object to dao, but I can't figure how to write an custom argument matcher for it.
"user" should {
"be saved" in {
val dao = new UserDao()
dao.save(any[User]) returns mock[User]
runMyBusinessLogic();
val expectedUser = new User("Freewind", 123.23234)
there was one(dao).save(mymatcher(expectedUser));
}
}
The User class:
case class User(name:String, random: Double)
Which contains a double field, that I need to do some special comparison for it.
The mymatcher is the matcher I want to define:
def mymatcher(expected: User) = ??? {
// compare `name` and `random`
}
But I don't know how to do it in spec2, and can't find any useful documents. Any helps?
I use beLike matcher. Like this:
one(daoMock).insert { beLike[MyEntity] { case t:Entity => {
t.summary mustEqual "Summary"
t.description mustEqual "Description"
}}}
Inside beLike matcher you could use ordinary value matchers.
For mockito matching I used Matchers.argThat
import org.mockito.Matchers
import org.mockito.Mockito.verify
verify(service).methodCall(Matchers.argThat({
case CaseClass("const", arg2) =>
arg2 == expected
case _ => false
}))

How do I write this without using a Try/Catch block?

I am looking to rewrite this scala function, but I am new to the language, I understand there is a alternative to using try\catch blocks. How would you guys rewrite this function?
def updateStationPost = Action { implicit request =>
StationForm.bindFromRequest.fold(
errors => { //needs to be revised!!
BadRequest(html.updateStation(errors,
Station(
request.body.asFormUrlEncoded.get("id")(0).toLong,
request.body.asFormUrlEncoded.get("operator")(0).toLong,
request.body.asFormUrlEncoded.get("name")(0),
try {
request.body.asFormUrlEncoded.get("number")(0).toInt
} catch {
case e:Exception => { 0 } //this exception happens when trying to convert the number when there is nothing in the flash scope to convert.
},
request.body.asFormUrlEncoded.get("timezone")(0)
),
Operators.retrieveJustOperators() //ugh... needs to be revised..
)
)
},
{ case(stationFormObj) =>
Stations.update(stationFormObj)
Redirect(routes.StationsController.index)
}
)
}
A general way of managing this is to use Try to wrap code that could throw an exception. Some of the ways of using this are illustrated below:
def unpredictable() = {
Try(Console.readLine("Int please: ").toInt) getOrElse 0
}
If the console read does not contain a parseable integer, then it throws an exception. This code just returns a 0 if there was an error, but you could put other statements there. As an alternative, you could use pattern matching to handle the situation.
def unpredictable() = {
Try(Console.readLine("Int please: ").toInt) match {
case Success(i) => i
case Failure(e) => println(e.getMessage())
}
}
You can also just return a Try and let the caller decide how to handle the failure.
How about:
import scala.util.control.Exception.handling
// Create a val like this as you reuse it over and over
val form: Option[Map[String, Seq[String]]] = request.body.asFormUrlEncoded
// Create some helper functions like this
val nfeHandler = handling(classOf[NumberFormatException]) by (_ => 0)
val intNFEHandler = (str: String) => nfeHandler apply str.toInt
val longNFEHandler = (str: String) => nfeHandler apply str.toLong
// You can use this instead of your try catch.. but this is just a sugar.. perhaps cleaner
intNFEHandler apply form.get("id")(0)
Here if the form was something like: Option(Map("id" -> Seq.empty[String]))
form.get("id")(0) would blow up with java.lang.IndexOutOfBoundsException.
I would suggest to have another helper:
// takes fieldNames and returns Option(fieldValue)
val fieldValueOpt = (fieldName: String) => form.flatMap(_.get(fieldName).flatMap(_.headOption))
Then create a validate method which performs pattern matching on all the fieldValue optionals, extract the values and create your Station object.

Play Framework Async Response Error

I have a Play framework controller method that returns either a Byte Array or a String based on the request header. Here is what it looks like:
def returnResponse = Action(parse.anyContent) {
request =>
println(request.body)
val buffer: RawBuffer = request.body.asRaw.get
val js: String = buffer.asBytes() match {
case Some(x) => new String(x, "UTF-8")
case None => scala.io.Source.fromFile(buffer.asFile).mkString
}
val resultJsonfut = scala.concurrent.Future { serviceCall.run(js) }
Async {
resultJsonfut.map(s => {
val out = if(request.headers.toSimpleMap.exists(_ == (CONTENT_ENCODING, "gzip"))) getBytePayload(s) else s
Ok(out)
})
}
}
I do not see any error in IntelliJ, but when I compile it, it fails with the following error:
Cannot write an instance of java.io.Serializable to HTTP response. Try to define a Writeable[java.io.Serializable]
Why is that? But however if I modify it a little bit to look like as below:
Async {
if(request.headers.toSimpleMap.exists(_ == (CONTENT_ENCODING, "gzip"))) {
resultJsonfut.map(s => Ok(getBytePayload(s)))
} else {
resultJsonfut.map(s => Ok(s))
}
}
It compiles fine. Any reasons why it behaves this way?
This happens because the return types of getBytePayload(s) and s are different.
Consider the simplier example:
val test = if (true) "1" else 0
The type of test value will be Any.
In general the if-else in Scala produces the value and the type of this value will be the common type for both statements.
So considering the Int type hierarchy looks like this: Int --> AnyVal --> Any
and the String type hierarchy looks like this: String --> AnyRef --> Any
the first common type for them is Any and in your case it seems to be a Serializable