-1

I want to be able to get the string representation of an objects property name, not the properties value, so that I can compare it with a variables value inside a conditional statement.

case class CustomObj(name: T)
case class PropertyObj(property: String)

val custObj = CustomObj("Chris")
val propObj = PropertyObj("name")

if(propObj.property.equals(custObj. /* the property name as a String, so "name", not the value ("Chris"*/)) {
    // do something
}

How can I access what is essentially the key of the property on the CustomObj?

Chris
  • 785
  • 10
  • 24
  • Why exactly do you need this? Do you need to check if an object has a property? If so, why? Have you considered using a **Map** instead? – Luis Miguel Mejía Suárez Jan 23 '20 at 14:09
  • The object that stores the `stringValue` can be "assigned" to any of the `CustomObj`s properties. I'm purposefully omitting further details because I have to. The why doesn't really matter for me, this is the requirements of the implementation, so I need to do it this way. I'll update it slightly to make it clearer. – Chris Jan 23 '20 at 14:12
  • if a property was a key-value pair, I want the string representation of the key, I don't want the value. – Chris Jan 23 '20 at 14:15
  • 6
    @Chris "the why" actually _does_ matter very much here, because what you are trying to do here looks like a very wrong approach, but it is impossible to suggest a better one without knowing the actual goal you are trying to achieve. Have you heard of [XY problem](https://en.wikipedia.org/wiki/XY_problem)? – Dima Jan 23 '20 at 14:21
  • @Chris If you need to check if an object has a property of some name where the name is a dynamic string, you have to use reflection. That is a somewhat common requirement in **Java** code, so I am sure you can find more information. Remember you can use **java** reflection in **scala** and that **scala** reflection is somewhat more complex, so I would recommend you to first try with java one. – Luis Miguel Mejía Suárez Jan 23 '20 at 14:45
  • @LuisMiguelMejíaSuárez Okay, I will try your suggestion. Thanks for the help – Chris Jan 23 '20 at 14:47

2 Answers2

4

Try productElementNames like so

case class CustomObj(name: String)
case class PropertyObj(property: String)

val custObj = CustomObj("Chris")
val propObj = PropertyObj("name")

if (custObj.productElementNames.toList.headOption.contains(propObj.property)) { ... } else { ... }

Addressing the comment, based on Krzysztof, try shapeless solution

import shapeless._
import shapeless.ops.record._

def firstPropertyNameOf[P <: Product, L <: HList](p: P)(implicit
    gen: LabelledGeneric.Aux[P, L],
    toMap: ToMap[L]): Option[String] = {
  toMap(gen.to(p)).map{ case (k: Symbol, _) => k.name }.toList.headOption
}

firstPropertyNameOf(custObj).contains(propObj.property)   // res1: Boolean = true
Mario Galic
  • 47,285
  • 6
  • 56
  • 98
4

I will assume you don't know the type of custObj at compile time. Then you'll have to use runtime reflection in Scala 2.12.

scala> case class CustomObj(name: String)
defined class CustomObj

scala> val custObj: Any = CustomObj("Chris")
custObj: Any = CustomObj(Chris)

scala> import scala.reflect.runtime.currentMirror
import scala.reflect.runtime.currentMirror

scala> val sym = currentMirror.classSymbol(custObj.getClass)
sym: reflect.runtime.universe.ClassSymbol = class CustomObj

scala> val props = sym.info.members.collect{ case m if m.isMethod && m.asMethod.isCaseAccessor => m.name.toString }
props: Iterable[String] = List(name)

scala> if (props.exists(_ == "name")) println("ok")
ok
Jasper-M
  • 14,966
  • 2
  • 26
  • 37