Scala HashMap with typed entries - scala

I'm not sure if i got the topic right. I'll try to describe the problem.
I have one common field trait. StringField and IntField extend this class:
trait BaseField[T] {
def name = "field"
var owner : FieldContainer
var value : T
def set(value : T) {
this.value = value
this.owner.fields.put(name, this)
}
}
class StringField extends BaseField[String]
class IntField extends BaseField[Int]
How do i implement the FieldContainer class? What i want is to match the FieldTypes later on:
val fieldContainer = {...init code here...}
fieldContainer.fields foreach {
field -> {
field match {
case f: StringField => println("String")
case f: IntField => println("Int")
case _ => println("Unknown")
}
}
}
This is my FieldContainer (so far)
trait FieldContainer {
private metaFields : HashMap[String, Any] = new HashMap[String, Any]
def fields : HashMap[String, Any] = this.metaFields
}
And i use it in that way:
class Pizza extends FieldContainer {
object name extends StringField(this) {
override def name = "pizza_name"
}
object pieces extends IntField(this) {
override def name = "pieces_count"
}
}

Fields don't need to know their owners.
class BaseField[T](initValue: T, val name: String = "field") {
private[this] var _value: T = initValue
def apply() = _value
def update(v: T) { _value = v }
override def toString(): String = name + "(" + apply() + ")"
}
class StringField(initValue: String, name: String = "field") extends BaseField[String](initValue, name)
class IntField(initValue: Int, name: String = "field") extends BaseField[Int](initValue, name)
trait FieldContainer {
protected def addField[C <: BaseField[_]](field: C): C = {
_fields += (field.name -> field)
field
}
protected def stringField(initValue: String, name: String): StringField =
addField(new StringField(initValue, name))
protected def intField(initValue: Int, name: String): IntField =
addField(new IntField(initValue, name))
private var _fields : Map[String, Any] = Map[String, Any]()
def fields : Map[String, Any] = _fields
}
Objects (singletons) initialized when first accessed, so you should use val instead of object for fields:
class Pizza extends FieldContainer {
val name = stringField("", "pizza_name")
val pieces = intField(0, "pieces_count")
val mass: BaseField[Double] = addField(new BaseField[Double](0, "mass"))
}
Usage:
scala> val p = new Pizza()
p: Pizza = Pizza#8c61644
scala> p.fields
res0: Map[String,Any] = Map(pizza_name -> pizza_name(), pieces_count -> pieces_count(0), mass -> mass(0.0))
scala> p.name() = "new name"
scala> p.pieces() = 10
scala> p.mass() = 0.5
scala> p.fields
res4: Map[String,Any] = Map(pizza_name -> pizza_name(new name), pieces_count -> pieces_count(10), mass -> mass(0.5))
scala> p.name()
res5: String = new name
scala> p.pieces()
res6: Int = 10
scala> p.mass
res7: BaseField[Double] = mass(0.5)

Related

No Implicit arguments of Type: Any

I followed this article to create union types. The articles has few answers about the Primitive type but my scenario is an extension to it.
So, I am trying to define a method which takes Map[String, A] where A is the set of allowed type.
This is my class of union types:
sealed trait SupportedType[A]
object SupportedType {
implicit val byteBufferColumn : SupportedType[ByteBuffer] = new SupportedType[ByteBuffer] {}
implicit val longColumn : SupportedType[java.lang.Long] = new SupportedType[java.lang.Long] {}
implicit val byteArrayColumn : SupportedType[Array[Byte]] = new SupportedType[Array[Byte]] {}
implicit val stringColumn : SupportedType[String] = new SupportedType[String] {}
}
This is my method I defined:
def upsert[A: SupportedType](key: T, values: Map[String, A], timestamp: Long, ttl: Duration): Future[Unit]
This is how I am calling the method:
dataStore.upsert(
cacheKey,
Map(
itColumn -> ByteBuffer.wrap(Utils.compress(iti.toByteArray)),
cacheWriteTimeColumn -> writeTime.toEpochMilli
),
writeTime.toEpochMilli,
ttl
)
error: No implicit arguments of type: SupportedType[Any]
My guess is writeTime.toEpochMilli returns java.long type and as you can see in SupportedType, I tried to define java.lang.Long but thats not working.
Any help would be appreciated.
You can use the magnet pattern in combination to a typeclass like this:
import scala.language.implicitConversions
trait ColumnValue {
def serialize(): String
}
object ColumnValue {
trait SupportedType[A] {
def toColumn(a: A): ColumnValue
}
object SupportedType {
implicit final val stringSupportedType: SupportedType[String] =
new SupportedType[String] {
override def toColumn(str: String): ColumnValue =
new ColumnValue {
override def serialize(): String =
"\"" + str + "\""
}
}
implicit final val intSupportedType: SupportedType[Int] =
new SupportedType[Int] {
override def toColumn(int: Int): ColumnValue =
new ColumnValue {
override def serialize(): String =
int.toString
}
}
implicit final val booleanSupportedType: SupportedType[Boolean] =
new SupportedType[Boolean] {
override def toColumn(bool: Boolean): ColumnValue =
new ColumnValue {
override def serialize(): String =
if (bool) "1" else "0"
}
}
implicit final def listSupportedType[A](implicit ev: SupportedType[A]): SupportedType[List[A]] =
new SupportedType[List[A]] {
override def toColumn(list: List[A]): ColumnValue =
new ColumnValue {
override def serialize(): String =
list.map(a => ev.toColumn(a).serialize()).mkString("[", ",", "]")
}
}
}
def apply[A](a: A)(implicit ev: SupportedType[A]): ColumnValue =
ev.toColumn(a)
implicit def supportedType2Column[A : SupportedType](a: A): ColumnValue =
apply(a)
}
You may create some helper functions to reduce some of the boilerplate.
Which can be used like this:
final case class Table(data: Map[String, ColumnValue]) {
def upsert(values: Map[String, ColumnValue]): Table =
copy(this.data ++ values)
}
object Table {
val empty: Table =
Table(data = Map.empty)
}
val result = Table.empty.upsert(Map(
"a" -> "foo",
"b" -> 10,
"c" -> List(true, false, true)
))
See the code running here.

Maintain order in .groupBy() operation of Scala collection

I have the following code snippet:
object Main1 extends App {
sealed trait XYZ
{
def id : String
}
class Test() extends XYZ {
override def id: String = "Test"
}
class ABC() extends XYZ {
override def id: String = "ABC"
}
val a: List[XYZ] = List(new Test(), new ABC())
val b: Map[String, List[XYZ]] = a.groupBy(_.id)
println(b)
val c: List[XYZ] = List(new ABC(), new Test())
val d: Map[String, List[XYZ]] = c.groupBy(_.id)
println(d)
}
The output is as follows:
Map(Test -> List(Main1$Test#7dc5e7b4), ABC -> List(Main1$ABC#1ee0005))
Map(Test -> List(Main1$Test#3d012ddd), ABC -> List(Main1$ABC#6f2b958e))
How can I maintain the order in the result like in the input collection?
If you are not limited to use immutable collections only then it can be easily done with mutable.LinkedHashMap:
import scala.collection.mutable
import scala.collection.mutable.ArrayBuffer
object Main1 extends App {
sealed trait XYZ
{
def id : String
}
class Test() extends XYZ {
override def id: String = "Test"
}
class ABC() extends XYZ {
override def id: String = "ABC"
}
val a: List[XYZ] = List(new Test(), new ABC())
val b: mutable.LinkedHashMap[String, ArrayBuffer[XYZ]] = a.foldLeft(mutable.LinkedHashMap.empty[String, ArrayBuffer[XYZ]]) { (m, x) =>
m.getOrElseUpdate(x.id, new ArrayBuffer[XYZ]) += x
m
}
println(b)
val c: List[XYZ] = List(new ABC(), new Test())
val d: mutable.LinkedHashMap[String, ArrayBuffer[XYZ]] = c.foldLeft(mutable.LinkedHashMap.empty[String, ArrayBuffer[XYZ]]) { (m, x) =>
m.getOrElseUpdate(x.id, new ArrayBuffer[XYZ]) += x
m
}
println(d)
}
Output maintains the order of the input collection:
LinkedHashMap(Test -> ArrayBuffer(com.github.plokhotnyuk.jsoniter_scala.examples.Main1$Test#56cbfb61), ABC -> ArrayBuffer(com.github.plokhotnyuk.jsoniter_scala.examples.Main1$ABC#1134affc))
LinkedHashMap(ABC -> ArrayBuffer(com.github.plokhotnyuk.jsoniter_scala.examples.Main1$ABC#1b0375b3), Test -> ArrayBuffer(com.github.plokhotnyuk.jsoniter_scala.examples.Main1$Test#2f7c7260))

Apply a function to an object with generic type in Scala

I have this code
import scala.reflect.ClassTag
case class Data[T: ClassTag](list: List[T]) {
}
trait Transformation {
type T
type U
def transform(data: Data[T]) : Data[U]
}
class FromInt2String extends Transformation {
override type T = Int
override type U = String
override def transform(data: Data[T]) = new Data(List("1", "2", "3"))
}
class FromString2Int extends Transformation {
override type T = String
override type U = Int
override def transform(data: Data[T]) = new Data(List(1, 2, 3))
}
object Test extends App {
override def main(args: Array[String]) {
val data = new Data(List(1, 2, 3))
val int2String = new FromInt2String()
val data2 = int2String.transform(data)
val string2Int = new FromString2Int()
val data3 = string2Int.transform(data2)
val transformations = List(int2String, string2Int)
val data4 = transformations.foldLeft(data)((data, transformation) => {
transformation.transform(data)
})
}
}
The problem is in the foldLeft method. I can't do it because the type isn't compatible but I need to apply all the transforms in my initial object data
Any ideas how to do it?
Thanks
I've solved it using shapeless and this post
import scala.reflect.ClassTag
import shapeless._
object andThen extends Poly2 {
implicit def functions[A, B, C] = at[A => B, B => C](_ andThen _)
}
case class Data[T: ClassTag](list: List[T]) {
}
trait Transformation {
type T
type U
def transform(data: Data[T]) : Data[U]
}
class FromInt2String extends Transformation {
override type T = Int
override type U = String
override def transform(data: Data[T]) = new Data(List("1s", "2s", "3s"))
}
class FromString2Int extends Transformation {
override type T = String
override type U = Int
override def transform(data: Data[T]) = new Data(List(4, 5, 6))
}
object Test extends App {
override def main(args: Array[String]) {
val data = new Data(List(1, 2, 3))
println(data)
val int2String = new FromInt2String()
val data2 = int2String.transform(data)
println(data2)
val string2Int = new FromString2Int()
val data3 = string2Int.transform(data2)
println(data3)
val transformations = int2String.transform _ :: string2Int.transform _ :: HNil
val functions = transformations.reduceLeft(andThen)
val data4 = functions(data)
println(data4)
}
}
Thanks to all of you that help me

How to get a name of a class member?

I want to be able to do something like this:
prepare form:
val formDescription = formBuilder(_.textField[User](_.firstName)
.textField[User](_.lastName)
).build
showForm(formDescription)
extract data from user filled form, using User:
//contains data of a form submitted by a user:
val formData: Map[String, String] = getFormData
val newUser = User(id = randomUuid, firstName = formData.extract[User](_.firstName))
One solution I see is to use a dynamic proxy that extends provided class and remembers what was invoked on him:
def getFieldName[T:Manifest](foo: T => Any) = {
val clazz = implicitly[Manifest[T]].erasure
val proxy = createDynamicProxy(clazz)
foo(proxy)
proxy.lastInvokedMethodName
}
Is there a better way to do it? Is there any lib that implements it already?
This reflective approach takes a case class and invokes its companion apply, calling getField and fetching default args if the field is not in the data.
import scala.reflect.runtime.{currentMirror => cm, universe => uni}
import uni._
def fromXML(xml: Node): Option[PluginDescription] = {
def extract[A]()(implicit tt: TypeTag[A]): Option[A] = {
// extract one field
def getField(field: String): Option[String] = {
val text = (xml \\ field).text.trim
if (text == "") None else Some(text)
}
val apply = uni.newTermName("apply")
val module = uni.typeOf[A].typeSymbol.companionSymbol.asModule
val ts = module.moduleClass.typeSignature
val m = (ts member apply).asMethod
val im = cm reflect (cm reflectModule module).instance
val mm = im reflectMethod m
def getDefault(i: Int): Option[Any] = {
val n = uni.newTermName("apply$default$" + (i+1))
val m = ts member n
if (m == NoSymbol) None
else Some((im reflectMethod m.asMethod)())
}
def extractArgs(pss: List[List[Symbol]]): List[Option[Any]] =
pss.flatten.zipWithIndex map (p => getField(p._1.name.encoded) orElse getDefault(p._2))
val args = extractArgs(m.paramss)
if (args exists (!_.isDefined)) None
else Some(mm(args.flatten: _*).asInstanceOf[A])
}
// check the top-level tag
xml match {
case <plugin>{_*}</plugin> => extract[PluginDescription]()
case _ => None
}
}
The idea was to do something like:
case class User(id: Int = randomUuid, firstName: String, lastName: String)
val user = extract[User]()
That's my own solution:
package utils
import javassist.util.proxy.{MethodHandler, MethodFilter, ProxyFactory}
import org.specs2.mutable._
import javassist.util.proxy.Proxy
import java.lang.reflect.{Constructor, Method}
class DynamicProxyTest extends Specification with MemberNameGetter {
"Dynamic proxy" should {
"extract field name" in {
memberName[TestClass](_.a) must ===("a")
memberName[TestClass](_.i) must ===("i")
memberName[TestClass](_.b) must ===("b")
memberName[TestClass](_.variable) must ===("variable")
memberName[TestClass](_.value) must ===("value")
memberName[TestClass](_.method) must ===("method")
}
}
}
trait MemberNameGetter {
def memberName[T: Manifest](foo: T => Any) = {
val mf = manifest[T]
val clazz = mf.erasure
val proxyFactory = new ProxyFactory
proxyFactory.setSuperclass(clazz)
proxyFactory.setFilter(new MethodFilter {
def isHandled(p1: Method) = true
})
val newClass = proxyFactory.createClass()
var lastInvokedMethod: String = null
val mh = new MethodHandler {
def invoke(p1: Any, p2: Method, p3: Method, p4: Array[AnyRef]) = {
lastInvokedMethod = p2.getName
p3.invoke(p1, p4: _*)
}
}
val constructor = defaultConstructor(newClass)
val parameters = defaultConstructorParameters(constructor)
// val proxy = constructor.newInstance("dsf", new Integer(0))
val proxy2 = constructor.newInstance(parameters: _*)
proxy2.asInstanceOf[Proxy].setHandler(mh)
foo(proxy2.asInstanceOf[T])
lastInvokedMethod
}
private def defaultConstructor(c: Class[_]) = c.getConstructors.head
private def defaultConstructorParameters(constructor: Constructor[_]) = {
val parameterTypes = constructor.getParameterTypes
parameterTypes.map{
case Integer.TYPE => Integer.valueOf(0)
case _ => null
}
}
}
case class TestClass(a: String, i: Int, b: Boolean) {
var variable = "asdf"
val value = "asdfasdfasd"
def method = "method"
}
val mh = new MethodHandler {
def invoke(p1: Any, p2: Method, p3: Method, p4: Array[AnyRef]) = {
lastInvokedMethod = p2.getName
p3.invoke(p1, p4: _*)
}
}
val constructor = defaultConstructor(newClass)
val parameters = defaultConstructorParameters(constructor)
// val proxy = constructor.newInstance("dsf", new Integer(0))
val proxy2 = constructor.newInstance(parameters: _*)
proxy2.asInstanceOf[Proxy].setHandler(mh)
foo(proxy2.asInstanceOf[T])
lastInvokedMethod
}
private def defaultConstructor(c: Class[_]) = c.getConstructors.head
private def defaultConstructorParameters(constructor: Constructor[_]) = {
val parameterTypes = constructor.getParameterTypes
parameterTypes.map{
case Integer.TYPE => Integer.valueOf(0)
case java.lang.Double.TYPE => java.lang.Double.valueOf(0)
case java.lang.Long.TYPE => java.lang.Long.valueOf(0)
case java.lang.Boolean.TYPE => java.lang.Boolean.FALSE
case _ => null
}
}
}
case class TestClass(a: String, i: Int, b: Boolean) {
var variable = "asdf"
val value = "asdfasdfasd"
def method = "method"
}

Is it possible to chain methods from different traits?

I have the following code:
class Parameterizable{
var map: Map[String, String] = new scala.collection.immutable.HashMap()
def put(entry: Tuple2[String, String]) = {
map = map + entry; this
}
}
class Query() extends Parameterizable{
override def toString = {
map.isEmpty match{
case true => ""
case false => "?" + map.map{case (key, value) => key + "=" + value}.mkString("&")
}
}
}
trait PageParameter extends Parameterizable{
def page(page: Int) = put(("page" -> page.toString))
def pageSize(pageSize: Int) = put(("pagesize" -> pageSize.toString))
}
trait DateParameter extends Parameterizable{
def fromDate(date: java.util.Date) = put(("fromdate" -> (date.getTime()/1000L).toString()))
def toDate(date: java.util.Date) = put(("todate" -> (date.getTime()/1000L).toString()))
}
//and other similar traits
I would like to do something like:
class ExtendedQuery extends Query with PageParameter with DateParameter
val query = new ExtendedQuery
query.page(4).pageSize(5).fromDate(new java.util.Date)
or:
query.and().page(4).and().pageSize(5).and().fromDate(new java.util.Date)
Is it possible in Scala?
You can declare the methods as returning this.type and then return this from them:
trait PageParameter extends Parameterizable{
def page(page: Int) : this.type = { put(("page" -> page.toString)); this }
def pageSize(pageSize: Int): this.type = { put(("pagesize" -> pageSize.toString)); this }
}
At the use-site, you can then chain the calls as you wanted. See this example:
scala> trait Wibble {
| def foo : this.type = { println("foo"); this }
| }
defined trait Wibble
scala> trait Wobble extends Wibble {
| def bar: this.type = { println("bar"); this }
| }
defined trait Wobble
scala> trait Wubble extends Wibble {
| def baz: this.type = { println("baz"); this }
| }
defined trait Wubble
Now I can test it
scala> new Wibble with Wobble with Wubble
res0: java.lang.Object with Wibble with Wobble with Wubble = $anon$1#937e20
scala> res0.bar.baz.foo
bar
baz
foo
res1: res0.type = $anon$1#937e20