Type mismatch when using Scala Trait in Play? - scala

Using the Play! Framework 1.2.4. I've got a nifty trait that checks an API key and HTTPS, but if I want to access the account associated with that key and reference it in my controller, it throws a type mismatch; found : java.lang.Object required: Long
So here's my API controller (incomplete):
object API extends Controller with Squeryl with SecureAPI {
import views.API._
def job(param:String) = {
val Job = models.Job
param match {
case "new" => Job.createFromParams(params,thisAccount) //thisAccount comes from the trait
case "update" =>
case "get" =>
case "list" =>
}
}
}
and the secure trait:
trait SecureAPI {
self:Controller =>
#Before
def checkSecurity(key:String) = {
if(!self.request.secure.booleanValue) {
Redirect("https://" + request.host + request.url);
} else {
models.Account.getByKey(key) match {
case Some(account) => {
renderArgs += "account" -> account.id
Continue
}
case _ => Forbidden("Key is not authorized.")
}
}
}
def thisAccount = renderArgs("account").get
}
How would I properly access thisAccount? Thanks

Your problem is simply that renderArgs is only declared to return an Object from its get call (which is fair enough because it could be just about anything).
Consequently the inferred type of your thisAccount method will be () => Object.
You'll need to cast the returned type into a Long, something like (though perhaps with some error-checking):
def thisAccount = renderArgs("account").get.asInstanceOf[Long]

Related

(Scala 2.12.8) pattern type is incompatible with expected type for parameterized type inside of parameterized class

(Scala 2.12.8)
Full Example
So lets say you have some "TypeEvidence" for some specific concrete types:
sealed trait TypeEvidence[+T]
object TypeEvidence{
case object DoubleType extends TypeEvidence[Double]
case object LongType extends TypeEvidence[Long]
case object StringType extends TypeEvidence[String]
}
I can match on those evidence objects like this:
object ThisIsOk{
def apply[T](ev: TypeEvidence[T]): Option[T] = {
ev match {
case TypeEvidence.DoubleType => Some(123.456)
case TypeEvidence.LongType => Some(1234L)
case _ => None
}
}
}
But not like this:
class ThisFails[T]{
def apply(ev: TypeEvidence[T]): Option[T] = {
ev match {
case TypeEvidence.DoubleType => Some(123.456)
case TypeEvidence.LongType => Some(1234L)
case _ => None
}
}
}
This fails to compile with:
pattern type is incompatible with expected type;
found : TypeEvidence.DoubleType.type
required: TypeEvidence[T]
pattern type is incompatible with expected type;
found : TypeEvidence.LongType.type
required: TypeEvidence[T]
Why is this? And how can this be worked around?
What if you do this with a type class?
class ThisFails[T]{
def apply(ev: TypeEvidence[T])(implicit
teto: TypeEvidenceToOption[T]
): Option[T] = teto(ev)
}
trait TypeEvidenceToOption[T] {
def apply(ev: TypeEvidence[T]): Option[T]
}
object TypeEvidenceToOption {
implicit val double: TypeEvidenceToOption[Double] =
{ case TypeEvidence.DoubleType => Some(123.456) }
implicit val long: TypeEvidenceToOption[Long] =
{ case TypeEvidence.LongType => Some(1234L) }
implicit def default[T]: TypeEvidenceToOption[T] = _ => None
}
new ThisFails[Double].apply(TypeEvidence.DoubleType) // Some(123.456)
new ThisFails[Long].apply(TypeEvidence.LongType) // Some(1234)
new ThisFails[String].apply(TypeEvidence.StringType) // None
I'm not entirely sure why it didn't work the way you expected. The only reasonable explanation I tell to myself is that the compiler has no issue using T as a placeholder for any type while T belongs to the parameterized method, whereas when it belongs to a parameterized class, it's more restrictive in terms of what you can do with it.
As a workaround, you can use .type and .asIstanceOf:
class ThisFails[T] {
def apply(ev: TypeEvidence[T]): Option[T] = {
ev match {
case _: TypeEvidence.DoubleType.type => Some(123.456.asInstanceOf[T])
case _: TypeEvidence.LongType.type => Some(1234L.asInstanceOf[T])
case _ => None
}
}
}
val x = new ThisFails[Long]
val x2 = new ThisFails[Double]
val x3 = new ThisFails[String]
println(x.apply(TypeEvidence.LongType)) // Some(1234)
println(x2.apply(TypeEvidence.DoubleType)) // Some(123.456)
println(x3.apply(TypeEvidence.StringType)) // None
I'm aware it's not nice, but you asked for a workaround. This pattern match now matches an object of the given type. Of course, with this workaround, having the objects "caseable" is redundant now.
I had a peek at the disassembled code of object ThisIsOk to figure out this workaround:
public static class ThisIsOk$
{
public static final ThisIsOk$ MODULE$;
static {
ThisIsOk$.MODULE$ = new ThisIsOk$();
}
public <T> Option<T> apply(final Main.TypeEvidence<T> ev) {
Object module$;
if (Main.TypeEvidence$.DoubleType$.MODULE$.equals(ev)) {
module$ = new Some((Object)BoxesRunTime.boxToDouble(123.456));
}
else if (Main.TypeEvidence$.LongType$.MODULE$.equals(ev)) {
module$ = new Some((Object)BoxesRunTime.boxToLong(1234L));
}
else {
module$ = None$.MODULE$;
}
return (Option<T>)module$;
}
}
I saw here the way pattern match works is by calling equals on their types, but since equals is not overridden, what this actually does is a reference check. Recall:
// in Object.java file:
public boolean equals(Object obj) {
return (this == obj);
}
Also I saw a cast to Option<T> in the end.
So with these observations, the class ThisFails[T] workaround I just showed earlier gets disassembled into this:
public static class ThisFails<T>
{
public Option<T> apply(final Main.TypeEvidence<T> ev) {
Object module$;
if (Main.TypeEvidence$.DoubleType$.MODULE$ == ev) {
module$ = new Some((Object)BoxesRunTime.boxToDouble(123.456));
}
else if (Main.TypeEvidence$.LongType$.MODULE$ == ev) {
module$ = new Some((Object)BoxesRunTime.boxToLong(1234L));
}
else {
module$ = None$.MODULE$;
}
return (Option<T>)module$;
}
}
Which is almost identical to the object ThisIsOk's disassembled code, except for using == instead of equals, which does not matter in this case, as I explained earlier.
I tested it with both Scala 2.13.8 and your version here on Scastie, and both worked.

How to make only few datatype which is not related to each other acceptable by generics

There is a trait which works perfectly. However, I would like to refactor the part related to generic [T] in order to limit the data type which could be accepted by generic [T] (I need only Option[JsValue] , JsValue , StringEnumEntry , String ). Is it possible to solve this problem through shapeless coproduct? Maybe there are other solutions?
trait ParameterBinders extends Log {
def jsonBinder[T](json: T, jsonType: java.lang.String = "json"): ParameterBinderWithValue = {
val jsonObject = new PGobject()
jsonObject.setType(jsonType)
json match {
case json: Option[JsValue] =>
jsonObject.setValue(json.map(Json.stringify).orNull)
case json: JsValue =>
jsonObject.setValue(Json.stringify(json))
case json: StringEnumEntry =>
jsonObject.setValue(json.value)
case json: String =>
jsonObject.setValue(json)
case _ =>
logger.error("unexpected data type ")
}
if (jsonType == "JSONSCHEMATYPE" || jsonType == "SYSPROPERTYTYPE") {
ParameterBinder(this, (ps, i) => {
ps.setObject(i, jsonObject)
})
} else {
ParameterBinder(json, (ps, i) => {
ps.setObject(i, jsonObject)
})
}
}
}
The easiest way is to use an ADT as described in the link of the first comment.
If you don't want to change the types that are accepted in jsonBinder then you can solve the problem by using a typeclass.
e.g.
trait JsonBindValue[T] {
def value(t: T): String
}
you would then have to provide instances for your accepted datatypes
object JsonBindValue {
implicit val OptJsBinder = new JsonBindValue[Option[JsValue]] {
def value(t: Option[JsValue]): String = {
t.map(Json.stringify).orNull
}
}
... more instances here
}
finally your function would look like this:
def jsonBinder[T : JsonBindValue](json: T, jsonType: java.lang.String = "json"): ParameterBinderWithValue = {
val binder = implicitly[JsonBindValue[T]]
jsonObject.setType(jsonType)
jsonObject.setValue(binder.value(json))
...
}
if you call the function without a implicit instance in scope you will get a compile time error.

missing FromRequestUnmarshaller[Entity] on akka post route

Let me start by saying that i am very new to akka-http, none of the books i have covered the marsheling topic well. So it is bit of a blackbox for me. I was able to obtain the following (Un)Marsheller which is capable of returning both json and protobuf based on a request header.
This part of the code works fine and i have a get route defined in akka-http and it works fine.
trait PBMarshaller {
private val protobufContentType = ContentType(MediaType.applicationBinary("octet-stream", Compressible, "proto"))
private val applicationJsonContentType = ContentTypes.`application/json`
implicit def PBFromRequestUnmarshaller[T <: GeneratedMessage with Message[T]](companion: GeneratedMessageCompanion[T]): FromEntityUnmarshaller[T] = {
Unmarshaller.withMaterializer[HttpEntity, T](_ => implicit mat => {
case entity#HttpEntity.Strict(`applicationJsonContentType`, data) =>
val charBuffer = Unmarshaller.bestUnmarshallingCharsetFor(entity)
FastFuture.successful(JsonFormat.fromJsonString(data.decodeString(charBuffer.nioCharset().name()))(companion))
case entity#HttpEntity.Strict(`protobufContentType`, data) =>
FastFuture.successful(companion.parseFrom(CodedInputStream.newInstance(data.asByteBuffer)))
case entity =>
Future.failed(UnsupportedContentTypeException(applicationJsonContentType, protobufContentType))
})
}
implicit def PBToEntityMarshaller[T <: GeneratedMessage]: ToEntityMarshaller[T] = {
def jsonMarshaller(): ToEntityMarshaller[T] = {
val contentType = applicationJsonContentType
Marshaller.withFixedContentType(contentType) { value =>
HttpEntity(contentType, JsonFormat.toJsonString(value))
}
}
def protobufMarshaller(): ToEntityMarshaller[T] = {
Marshaller.withFixedContentType(protobufContentType) { value =>
HttpEntity(protobufContentType, value.toByteArray)
}
}
Marshaller.oneOf(protobufMarshaller(), jsonMarshaller())
}
}
the issue i am facing is on the post route.
(post & entity(as[PropertyEntity])) { propertyEntity =>
complete {
saveProperty(propertyEntity)
}
}
During compilation time, i get the following error
Error:(20, 24) could not find implicit value for parameter um: akka.http.scaladsl.unmarshalling.FromRequestUnmarshaller[PropertyEntity]
(post & entity(as[PropertyEntity])) { propertyEntity =>
I am not sure exactly what i am missing. Do i need to define an implicit FromRequestUnmarshaller ? if so what should it have?
i was able to hack something together that works for the moment, but i still don't know how to create a general Unmarshaller that can decode any ScalaPB case class
implicit val um:Unmarshaller[HttpEntity, PropertyEntity] = {
Unmarshaller.byteStringUnmarshaller.mapWithCharset { (data, charset) =>
val charBuffer = Unmarshaller.bestUnmarshallingCharsetFor(data)
JsonFormat.fromJsonString(data.decodeString(charBuffer.nioCharset().name()))(PropertyEntity)
/*PropertyEntity.parseFrom(CodedInputStream.newInstance(data.asByteBuffer))*/
}
}
even this i don't know how to have both decoders enabled at the same time. so i have commented one out.

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.

Can't access generic function type in a inner PartialFunction

I am currently writing a generic function to execute Dispatch async requests, but I can't access generic type in Dispatch handler:
private def execQuery[MessageType](query : Req, errorMsg : String)
{
Http(query OK as.String).either
.onSuccess
{
case Left(error) => println(errorMsg)
case Right(json) => println( new MessageType(json) ) // error here
}
}
I have an error on new MessageType : "Cannot resolve symbol MessageType" in "new MessageType(json)".
Can you help me ?
Thank you in advance
Victor
EDIT : I have found an other interesting way here http://www.brentsowers.com/2011/11/writing-generic-functions-that-take.html. You have to use the manifest feature :
class DynamicTestClass() {
def output() {
println("Hello from a dynamically sent class")
}
}
def testFunc[T : Manifest]() : T = {
manifest[T].erasure.newInstance().asInstanceOf[T]
}
val dynamicTestClassInstance = testFunc[DynamicTestClass]()
dynamicTestClassInstance.output()
It seems to work !
You can't do
def mustMakeA[A](b:String):A = new A(b)
in scala.
A few practical reason. How is scalac supposed to know if A has public constructors and its argument?
However you can use a smarter design, for example, a type class that "knows" how to construct the parameter:
class Message(val value:String)
trait Constructor[A] {
def cons(b:String)
}
implicit class MessageHasConstructor(m:Message) extends Constructor[Message] {
def cons(b:String) = new Message(b)
}
Et voilĂ , now we rewrite our mustMakeA as:
def mustMakeA[A:Constructor](b:String):A = implicitly[Constructor[A]].cons(b)
mustMakeA[Message]("Example") // would give us a `new Message("Example")`
Btw, I didn't test the code, so it might require some tweaking.