0

I'm trying to call a member from a generic type and here is an original way to run the function

SourceStruct is the object that I want to replace with something like T.

override def process(t: SourceStruct, runtimeContext: RuntimeContext, requestIndexer: RequestIndexer): Unit = {
        val json = new util.HashMap[String, String]()
        json.put("time", t.rating.toString)
        json.put("userId", t.userId.id.toString)
        json.put("itemId", t.itemId.id)

        requestIndexer.add(request)
      }

when I replace the SourceStruct with T, how can I call the t.userId?

override def process(t: T, runtimeContext: RuntimeContext, requestIndexer: RequestIndexer): Unit = {
      val json = new util.HashMap[String, String]()
//      json.put("userId", t.userId.id)
//      json.put("itemId", t.itemId.id)
//      json.put("rating", t.rating.toString)

      val request = Requests
        .indexRequest()
        .index(index)
        .`type`(indexType)
        .source(json)
      requestIndexer.add(request)
    }

thanks in advance

I can get the member by using

typeOf[T].members.collect {
case m: MethodSymbol if m.isCaseAccessor => m
}.toList

but still no clue about the question above


EDIT:

for example:

case class ExampleClass(x: Int, y: Int)
case class ExampleClass2(xx: Int, yy: Int)

then in the process function, how can I assign value to the member

override def process(t: T, ...) = {
    //t.x = 10 or t.xx = 10 ???
}

SOLVED

Convert Any Class to HashMap

Xu Yan
  • 13
  • 4
  • 1
    If you have a `T` how do you expect to call any member from it? It could just be anything, like `Int` or even `Nothing`. If you want specific members of an object, why do you want to make it generic? - You probably only want a subset of types, if so and they are related and you manage all of them probably **subtyping** is all you need, code the method for an interface. If they are not related or you can not modify them, you could use **typeclasses** instead, code method using the functions provided by the abstraction. – Luis Miguel Mejía Suárez Apr 30 '19 at 04:02
  • @LuisMiguelMejíaSuárez Thanks for your response, but subtyping is not what I am looking for. Actually, I don't even know if it's doable. I just add an example in my question – Xu Yan Apr 30 '19 at 05:48
  • What scala version do you use? – talex Apr 30 '19 at 06:00
  • @talex version 2.12.7 – Xu Yan Apr 30 '19 at 06:12
  • In your example fields of `ExampleClass` are read-only. – talex Apr 30 '19 at 06:12
  • @talex Ok, so can I conclude that what I am trying to do, is just not doable? – Xu Yan Apr 30 '19 at 06:14
  • No. Code from my answer assign value just fine. – talex Apr 30 '19 at 06:26
  • If you do not even know the name of the fields, how do you expect to code? What is your algorithm?, your meta-idea? Will always T had two **Int** fields? Will all them have the same structure but different names? You want default values for each type? - Also, if you are using **JSONs** I do not recommend you to write your own procesor, maybe use a library like Circe or Argonaut or Play-JSON. - In any case, the question is still not clear, what exactly you want to do? – Luis Miguel Mejía Suárez Apr 30 '19 at 11:50
  • @LuisMiguelMejíaSuárez, "If you do not even know the name of the fields, how do you expect to code?" I am just wondering if that possible to code without knowing the field. "What is your algorithm?" it's not about algo. "Will always T had two Int fields?", No, the T could have random members, double or custom type maybe. " Will all them have the same structure but different names?" No. – Xu Yan May 05 '19 at 05:00
  • It is possible? Yes, using reflection as talex showed. - IMHO, code is always about algorithms, you had a problem to solve and you had an idea in mind, that is the algorithm. - My question is, what exactly is your problem? And I mean your real problem, not how to call an unknown field. - Reflection has proven to be weak, costly & insecure, and almost always unnecessary. However, without knowing more about your problem, we can not recommend something different.- If you only want to convert any class to a `Map` check Dmytro's link, if you want to create a JSON check the libraries I suggested. – Luis Miguel Mejía Suárez May 05 '19 at 12:05
  • @LuisMiguelMejíaSuárez Thanks for your explanation. Dmytro's link can solve my problem – Xu Yan May 06 '19 at 01:23

2 Answers2

1

Looking at your code it seems you do not want "to call a member in a generic type", it seems you want to transform a case class into HashMap.

Case class to map in Scala

Dmytro Mitin
  • 48,194
  • 3
  • 28
  • 66
0

Here is little snippet

  case class Foo(bar: String)

  val f: Object = Foo("a")

  val barField = f.getClass.getDeclaredField("bar")

  barField.setAccessible(true)
  val value = barField.get(f).asInstanceOf[String]

  print(value)

to assign values use

 barField.set(f, "new value")
talex
  • 17,973
  • 3
  • 29
  • 66
  • I just added an example and hope it makes the question clear. The process function has no knowledge in the Generic function T so I can't use asInstanceOf[String], also can't make my custom class as an interface. – Xu Yan Apr 30 '19 at 05:52
  • Added code which show how to assign value. If you don't know type of field you still can read value, but it will be hard to assign it because you have to have value of correct type. – talex Apr 30 '19 at 05:55
  • case class Foo(bar: String, boo: String) val f = Foo("a", "b") val barField = f.getClass.getDeclaredField(???) I dont know the "bar" in this part, then how can I get the barField ? – Xu Yan Apr 30 '19 at 07:05
  • You can have list of all fields via `f.getClass.getDeclaredFields()` – talex Apr 30 '19 at 07:15