Scala Reflection : Given a getter Symbol, what is the easiest way to find the corresponding setter Symbol?

StackOverflow https://stackoverflow.com/questions/22105234

  •  18-10-2022
  •  | 
  •  

Question

Short version: Given a getter Symbol I would like to find the corresponding setter Symbol.

Long version:

Below is a little utility class for Scala Reflection.

I plan to use this class to deep copy Hibernate Entities (subclasses of the abstract class UUIDEntity).

I divide the deep copy into two parts, 1) value copy each object in the object graph 2) connect the isolated copies to form a cloned object graph. This question only deals with the first part.

Let root be an Entity.

First, I want to create a value copy of root, let's call this copy. Value copy means that I only fill up the value fields in the copy (see definition of value fields below).

This should happen in the getValueCopy method.

There is val copy but its fields are still empty after creating it with val copy= constructorMirror.apply()

So I need to copy the fields from root into copy. For this I need to get the setters and getters of the fields (more precisely, value fields which are fields that refer to value classes like Int, String, Long etc.).

So far I managed to find the getters for value fields (valueGetters), however, my problem is that I want to find the corresponding setters. But I don't really know what is the best way to pair up the setters with the getters?

Is using the method names the only way to go? That is what I would naively do but my feeling tells me that there must be a better way.

Any suggestions are welcome. Thanks for reading.

import scala.reflect.runtime.universe._
import java.util
import model.UUIDEntity
import scala.collection.JavaConversions._
import scala.collection.mutable


case class ReflectionOfEntity(root:AnyRef) {
 // require(root.isInstanceOf[UUIDEntity[_]])  
  val rtmMirror                   =runtimeMirror(getClass.getClassLoader)
  val instanceMirror : InstanceMirror =rtmMirror.reflect(root)
  val classSymbol    : ClassSymbol    =rtmMirror.reflect(root).symbol
  val classMirror    : ClassMirror    =rtmMirror.reflectClass(classSymbol)

  val theType        : Type           =rtmMirror.reflect(root).symbol.toType


  val methods        : Iterable[MethodSymbol]=
    theType.declarations.filter(_.isMethod).map(_.asMethod)

  val constructorSymbol:MethodSymbol=methods.filter{m=>m.isConstructor && m.paramss.flatten.
    isEmpty}.headOption.
    getOrElse(throw new RuntimeException("no parameterless constructor in root!") )

  val constructorMirror: MethodMirror = classMirror.reflectConstructor(constructorSymbol)


  val valueGetters:Iterable[Symbol]=theType.members.filter{
    case ms:MethodSymbol=>ms.isGetter && isValueType(ms.returnType)
    case _ => false
  }

  def isValueType(tpe:Type)=
    List(typeOf[String],typeOf[AnyVal],typeOf[java.lang.Long]).exists{tpe <:< _}

  def getValueCopy= {
    val copy= constructorMirror.apply()
    val copyR=ReflectionOfEntity(copy)
    //valueGetters.foreach()
    copy
  }
}
Was it helpful?

Solution

MethodSymbol exposes isCaseAccessor, isGetter, isSetter, accessed for the field and setter for the setter.

I could use the practice if code is needed, but probably not.

Am I looking at different ScalaDoc than you? Sometimes it's hard to know where to look.

Edit: actually it's on TermSymbolApi.

Update:

scala> class C(var i: Int, var s: String)
defined class C

scala> typeOf[C].declarations.filter(s => s.isMethod && s.asMethod.isGetter && s.asMethod.setter != NoSymbol)
res10: Iterable[reflect.runtime.universe.Symbol] = SynchronizedOps(method i, method s)

scala> .map { s => val m = s.asMethod ; (m, m.setter) }
res11: Iterable[(reflect.runtime.universe.MethodSymbol, reflect.runtime.universe.Symbol)] = List((method i,method i_=), (method s,method s_=))
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top