Facing issue while using reflection class concept in scala - scala

I have one main class like this:
class Test {
def exe(first:String, second:String, task:String):String = {
task match {
case "A" => {
val obj = new A(first)
obj.defineSecond(second)
}
case "B" => {
val obj = new B(first)
obj.defineSecond(second)
}
case "C" => {
val obj = new C(first)
obj.defineSecond(second)
}
....so many cases
}
}
}
Instead of writing case in my Test class everytime a new class is added, I tried using the concept of reflection in scala.
Below is what I trying:
val m = ru.runtimeMirror(getClass.getClassLoader)
val classTest = ru.typeOf[Test].typeSymbol.asClass
val cm = m.reflectClass(classTest)
But getting error as "class Test is inner class, use reflectClass on an InstaneMirror to obtain its classMirror".
Can anyone knows how can I can avoid adding cases to my main class everytime a new class is created, instead I can write my main class in a way it will work for every case.

I guess you haven't provided all necessary information in your question. It's written that "class Test is inner class" in your error message but Test is not inner in your code snippet. If you want your runtime-reflection code to be fixed please provide code snippet that reflects actual use case.
Meanwhile you can try a macro (working at compile time)
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
class Test {
def exe(first: String, second: String, task: String): String = macro Test.exeImpl
}
object Test {
def exeImpl(c: blackbox.Context)(first: c.Tree, second: c.Tree, task: c.Tree): c.Tree = {
import c.universe._
val cases = Seq("A", "B", "C").map(name =>
cq"""${Literal(Constant(name))} => {
val obj = new ${TypeName(name)}($first)
obj.defineSecond($second)
}"""
)
q"$task match { case ..$cases }"
}
}
Usage:
class A(s: String) {
def defineSecond(s1: String): String = ""
}
class B(s: String) {
def defineSecond(s1: String): String = ""
}
class C(s: String) {
def defineSecond(s1: String): String = ""
}
new Test().exe("first", "second", "task")
//scalac: "task" match {
// case "A" => {
// val obj = new A("first");
// obj.defineSecond("second")
// }
// case "B" => {
// val obj = new B("first");
// obj.defineSecond("second")
// }
// case "C" => {
// val obj = new C("first");
// obj.defineSecond("second")
// }
//}

Related

How to override variable studentName given in class within changeName variable and new variable is used in userName when I call changeName method?

class Person {
val studentName = "Arpana"
def changeName(id:String, name:String) ={
val studentName = name
useName(id)
}
def useName(id:String) = {
println(s"use name is $id, by $studentName")
}
}
object Person {
def main(args: Array[String]): Unit = {
(new Person).changeName("2", "Shubham")
}
}
I don't want to use var in code, can we do it by keywords, I tried with keywords like super, protected, private, final but didn't work.
In actual I want to apply this in the below code.
abstract class BaseRepository[T <: BaseModel : ClassTag : StriveSerializer] {
self: BaseConnection =>
val tableName: String = implicitly[ClassTag[T]].runtimeClass.getSimpleName
private val serializer = implicitly[StriveSerializer[T]]
private def executeInserts(query: String): Future[Boolean] = Future {
val preparedStatement = self.connection.prepareStatement(query)
preparedStatement.execute()
}
def exist(id: String, name: String): Future[Boolean] = {
val tableName = name
val promise = Promise[Boolean]
queryById(id).onComplete {
case Success(_) => promise.success(true)
case Failure(ex) => promise.failure(ex)
}
promise.future
}
def queryById(id: String): Future[T] = {
val getSql = s"SELECT * FROM $tableName WHERE id == $id;"
executeReads(getSql).map(serializer.fromResultSet)
}
}
I want when i call exist function then table name given in exist function override in queryById method table name .
It seems like a bit of mix of Java and Scala style. I tried to refactor a bit assuming the intention behind the code. Try and see if this achieves what you want to do:
class Person(_id: String, _studentName: String) {
private val id: String = _id
private val studentName: String = _studentName
def useName() = {
println(s"use name is $id, by $studentName")
}
}
object Person extends App {
new Person("2", "Shubham").useName()
}
I think you should use case class For Model
case class Student(id:String,name:String)
def changeId(student:Student, newId:String): Student ={
student.copy(id=newId)
}
val s1 = Student("1","A")
val newS1 = changeId(s1,"2")
I think it okay to use mutable in a class
e.g.
class MySuperService{
var lastHeartbeat: Option[Timestamp] = None
def setLastHeartbeat(ts:Timestamp): Unit ={
lastHeartbeat = Some(ts)
}
}
val mss1 = new MySuperService()
mss1.setLastHeartbeat(???)

How use guave cache loader in F polymorphic code

I have a service, that returns joke from official example:
final case class JokeError(e: Throwable) extends RuntimeException
def impl[F[_] : Sync](C: Client[F]): Jokes[F] = new Jokes[F] {
val dsl = new Http4sClientDsl[F] {}
import dsl._
def get: F[Jokes.Joke] = {
C.expect[Joke](GET(uri"https://icanhazdadjoke.com/"))
.adaptError { case t => JokeError(t) }
}
}
But I want cache first requested joke (just by constant key, this doesn't matter) with guava cache:
object Jokes {
def apply[F[_]](implicit ev: Jokes[F]): Jokes[F] = ev
final case class Joke(joke: String) extends AnyRef
object Joke {
implicit val jokeDecoder: Decoder[Joke] = deriveDecoder[Joke]
implicit def jokeEntityDecoder[F[_]: Sync]: EntityDecoder[F, Joke] =
jsonOf
implicit val jokeEncoder: Encoder[Joke] = deriveEncoder[Joke]
implicit def jokeEntityEncoder[F[_]: Applicative]: EntityEncoder[F, Joke] =
jsonEncoderOf
}
final case class JokeError(e: Throwable) extends RuntimeException
def impl[F[_]: Sync](C: Client[F]): Jokes[F] = new Jokes[F]{
val cacheLoader : CacheLoader[String, Joke] = new CacheLoader[String, Joke] {
override def load(key: String): Joke = {
import dsl._
val joke: F[Joke] = C.expect[Joke](GET(uri"https://icanhazdadjoke.com/"))
.adaptError{ case t => JokeError(t)}
//? F[Joke] => Joke
null
}
}
val cache = CacheBuilder.newBuilder().build(cacheLoader)
val dsl = new Http4sClientDsl[F]{}
def get: F[Jokes.Joke] = {
//it's ok?
cache.get("constant").pure[F]
}
}
}
As you can see, cacheLoader requires "materialized" value F[Joke] => Joke. And cache return pure value without F
How can I use this cache in F polymorpic code?
You're basically asking how to run code polymorphic in F, to do so you need an Effect constraint to your F.
Also instead of using pure, you would need to use delay, since getting a value from the cache is a side effect.
val cacheLoader : CacheLoader[String, Joke] = new CacheLoader[String, Joke] {
override def load(key: String): Joke = {
import dsl._
val joke: F[Joke] = C.expect[Joke](GET(uri"https://icanhazdadjoke.com/"))
.adaptError{ case t => JokeError(t)}
// This is a side effect, but can't avoid it due to the way the API is designed
joke.toIO.unsafeRunSync()
}
}
val cache = CacheBuilder.newBuilder().build(cacheLoader)
val dsl = new Http4sClientDsl[F]{}
def get: F[Jokes.Joke] = {
// This is okay :)
Sync[F].delay(cache.get("constant"))
}
As an aside, if you want to use something that interoperates really well with http4s, I strongly recommend mules. Check it out here:
https://github.com/ChristopherDavenport/mules

Serialization in Scala

Im trying to understand basics of serialization in Scala. When i run the first example below I get the following output on the last line: res1: A.Mao = A$$anonfun$main$1$Mao$1#78e67e0a
#SerialVersionUID(1L)
class Poo(val aa:Int) extends Serializable {
override def toString() = "Hola"
}
#SerialVersionUID(1L)
class Mao(val hi: Poo) extends Serializable
def serialize() = {
val test = new Mao(new Poo(1))
try{
val fout = new FileOutputStream("c:\\misc\\address.ser");
val oos = new ObjectOutputStream(fout);
oos.writeObject(test);
oos.close();
System.out.println("Done");
}catch {
case ex => ex.printStackTrace();
}
}
serialize()
def ReadObjectFromFile[A](filename: String)(implicit m:scala.reflect.Manifest[A]): A = {
val input = new ObjectInputStream(new FileInputStream(filename))
val obj = input.readObject()
obj match {
case x if m.erasure.isInstance(x) => x.asInstanceOf[A]
case _ => sys.error("Type not what was expected when reading from file")
}
}
ReadObjectFromFile[Mao]("c:\\misc\\address.ser")
If I change the example and use case classes instead things works as expected with the output
res1: A.Mao = Mao(Hola)
case class Poo(val aa:Int) {
override def toString() = "Hola"
}
case class Mao(val hi: Poo)
def serialize() = {
val test = new Mao(new Poo(1))
try{
val fout = new FileOutputStream("c:\\misc\\address.ser");
val oos = new ObjectOutputStream(fout);
oos.writeObject(test);
oos.close();
System.out.println("Done");
}catch {
case ex => ex.printStackTrace();
}
}
def ReadObjectFromFile[A](filename: String)(implicit m:scala.reflect.Manifest[A]): A = {
val input = new ObjectInputStream(new FileInputStream(filename))
val obj = input.readObject()
obj match {
case x if m.erasure.isInstance(x) => x.asInstanceOf[A]
case _ => sys.error("Type not what was expected when reading from file")
}
}
ReadObjectFromFile[Mao]("c:\\misc\\address.ser")
So my questions are:
What do I need to do to get class to give the same output as case class?
Why does case class work without adding any explicit information about serialization?
This has nothing to do with the de/serialization (which seems correct) - it's just the way the result is displayed:
Scala REPL (and Worksheets) use the value's toString method to display it. Case classes override the default toString() method, therefore the output is displayed nicely (as expected). For non-case classes, the defeault implementation of Object.toString() is called, and results in the class name and address that you see.
You can implement toString for the non-case class too, to get the same result:
class Mao(val hi: Poo) extends Serializable {
override def toString = s"Mao($hi)"
}
// program prints:
// Done
// Mao(Hola)

Scala Macros: Accessing members with quasiquotes

I'm trying to implement an implicit materializer as described here: http://docs.scala-lang.org/overviews/macros/implicits.html
I decided to create a macro that converts a case class from and to a String using quasiquotes for prototyping purposes. For example:
case class User(id: String, name: String)
val foo = User("testid", "foo")
Converting foo to text should result in "testid foo" and vice versa.
Here is the simple trait and its companion object I have created:
trait TextConvertible[T] {
def convertTo(obj: T): String
def convertFrom(text: String): T
}
object TextConvertible {
import language.experimental.macros
import QuasiTest.materializeTextConvertible_impl
implicit def materializeTextConvertible[T]: TextConvertible[T] = macro materializeTextConvertible_impl[T]
}
and here is the macro:
object QuasiTest {
import reflect.macros._
def materializeTextConvertible_impl[T: c.WeakTypeTag](c: Context): c.Expr[TextConvertible[T]] = {
import c.universe._
val tpe = weakTypeOf[T]
val fields = tpe.declarations.collect {
case field if field.isMethod && field.asMethod.isCaseAccessor => field.asMethod.accessed
}
val strConvertTo = fields.map {
field => q"obj.$field"
}.reduce[Tree] {
case (acc, elem) => q"""$acc + " " + $elem"""
}
val strConvertFrom = fields.zipWithIndex map {
case (field, index) => q"splitted($index)"
}
val quasi = q"""
new TextConvertible[$tpe] {
def convertTo(obj: $tpe) = $strConvertTo
def convertFrom(text: String) = {
val splitted = text.split(" ")
new $tpe(..$strConvertFrom)
}
}
"""
c.Expr[TextConvertible[T]](quasi)
}
}
which generates
{
final class $anon extends TextConvertible[User] {
def <init>() = {
super.<init>();
()
};
def convertTo(obj: User) = obj.id.$plus(" ").$plus(obj.name);
def convertFrom(text: String) = {
val splitted = text.split(" ");
new User(splitted(0), splitted(1))
}
};
new $anon()
}
The generated code looks fine, but yet I get the error value id in class User cannot be accessed in User in compilation while trying to use the macro.
I suspect I am using a wrong type for fields. I tried field.asMethod.accessed.name, but it results in def convertTo(obj: User) = obj.id .$plus(" ").$plus(obj.name ); (note the extra spaces after id and name), which naturally results in the error value id is not a member of User.
What am I doing wrong?
Ah, figured it out almost immediately after sending my question.
I changed the lines
val fields = tpe.declarations.collect {
case field if field.isMethod && field.asMethod.isCaseAccessor => field.asMethod.accessed
}
to
val fields = tpe.declarations.collect {
case field if field.isMethod && field.asMethod.isCaseAccessor => field.name
}
which solved the problem.
The field you get with accessed.name has a special suffix attached to it, to avoid naming conflicts.
The special suffix is scala.reflect.api.StandardNames$TermNamesApi.LOCAL_SUFFIX_STRING, which has the value, you guessed it, a space char.
This is quite evil, of course.

avoid explicit cast at scala's dynamic types

I add variables with Dynamic from scala 2.10.0-RC1 like this:
import language.dynamics
import scala.collection.mutable.HashMap
object Main extends Dynamic {
private val map = new HashMap[String, Any]
def selectDynamic(name: String): Any = {return map(name)}
def updateDynamic(name:String)(value: Any) = {map(name) = value}
}
val fig = new Figure(...) // has a method number
Main.figname = fig
Now, if I want to access Main.figname.number it doesn't work, because the compiler thinks it's of type Any.
But it's also Main.figname.isInstanceOf[Figure] == true, so it's Any and Figure, but doesn't have Figures abilities. Now I can cast it like, Main.figname.asInstanceOf[Figure].number and it works! This is ugly! And I can't present this to my domain users (I'd like to build a internal DSL.)
Note: If I use instead of Any the supertype of Figure it doesn't work either.
Is this a bug in scala 2.10, or a feature?
It is quite logical. You are explicitly returning instances of Any. A workaround would be to have instances of Dynamic all along:
import language.dynamics
import scala.collection.mutable.HashMap
import scala.reflect.ClassTag
trait DynamicBase extends Dynamic {
def as[T:ClassTag]: T
def selectDynamic[T](name: String): DynamicBase
def updateDynamic(name:String)(value: Any)
}
class ReflectionDynamic( val self: Any ) extends DynamicBase with Proxy {
def as[T:ClassTag]: T = { implicitly[ClassTag[T]].runtimeClass.asInstanceOf[Class[T]].cast( self ) }
// TODO: cache method lookup for faster access + handle NoSuchMethodError
def selectDynamic[T](name: String): DynamicBase = {
val ref = self.asInstanceOf[AnyRef]
val clazz = ref.getClass
clazz.getMethod(name).invoke( ref ) match {
case dyn: DynamicBase => dyn
case res => new ReflectionDynamic( res )
}
}
def updateDynamic( name: String )( value: Any ) = {
val ref = self.asInstanceOf[AnyRef]
val clazz = ref.getClass
// FIXME: check parameter type, and handle overloads
clazz.getMethods.find(_.getName == name+"_=").foreach{ meth =>
meth.invoke( ref, value.asInstanceOf[AnyRef] )
}
}
}
object Main extends DynamicBase {
def as[T:ClassTag]: T = { implicitly[ClassTag[T]].runtimeClass.asInstanceOf[Class[T]].cast( this ) }
private val map = new HashMap[String, DynamicBase]
def selectDynamic[T](name: String): DynamicBase = { map(name) }
def updateDynamic(name:String)(value: Any) = {
val dyn = value match {
case dyn: DynamicBase => dyn
case _ => new ReflectionDynamic( value )
}
map(name) = dyn
}
}
Usage:
scala> class Figure {
| val bla: String = "BLA"
| }
defined class Figure
scala> val fig = new Figure() // has a method number
fig: Figure = Figure#6d1fa2
scala> Main.figname = fig
Main.figname: DynamicBase = Figure#6d1fa2
scala> Main.figname.bla
res40: DynamicBase = BLA
All instances are wrapped in a Dynamic instance.
We can recover the actual type using the as method which performs a dynamic cast.
scala> val myString: String = Main.figname.bla.as[String]
myString: String = BLA
You can add any extensions or custom functionalities to Any or any predefined value classes. You can define an implicit value class like this:
implicit class CustomAny(val self: Any) extends AnyVal {
def as[T] = self.asInstanceOf[T]
}
Usage:
scala> class Figure {
| val xyz = "xyz"
| }
defined class Figure
scala> val fig = new Figure()
fig: Figure = Figure#73dce0e6
scala> Main.figname = fig
Main.figname: Any = Figure#73dce0e6
scala> Main.figname.as[Figure].xyz
res8: String = xyz
The implicit value class is not costly like like regular class. It will be optimised in compile time and it will be equivalent to a method call on a static object, rather than a method call on a newly instantiated object.
You can find more info on implicit value class here.