lfk
lfk

Reputation: 2633

Getting field name as string

I have a trait that overrides toString to print the values of all fields:

/**
  * Interface for classes that provide application configuration.
  */
trait Configuration {
  /** abstract fields defined here. e.g., **/
  def dbUrl: String

  /**
    * Returns a list of fields to be excluded by [[toString]]
    */
  protected def toStringExclude: Seq[String]

  /**
    * Returns a String representation of this object that prints the values for all configuration fields.
    */
  override def toString: String = {
    val builder = new StringBuilder
    val fields = this.getClass.getDeclaredFields
    for (f <- fields) {
      if (!toStringExclude.contains(f.getName)) {
        f.setAccessible(true)
        builder.append(s"${f.getName}: ${f.get(this)}\n")
      }
    }
    builder.toString.stripSuffix("\n")
  }
}

A concrete class currently looks like this:

class BasicConfiguration extends Configuration {
  private val config = ConfigFactory.load

  override val dbUrl: String = config.getString("app.dbUrl")

  /**
    * @inheritdoc
    */
  override protected def toStringExclude: Seq[String] = Seq("config")
}

The problem is, if config were renamed at some point, the IDE would miss "config" in toStringExclude as it's just a string. So I'm trying to find a way to get the name of a field as a string, like getFieldName(config).

Upvotes: 1

Views: 354

Answers (2)

Alexey Romanov
Alexey Romanov

Reputation: 170745

Using https://github.com/dwickern/scala-nameof,

import com.github.dwickern.macros.NameOf._

class BasicConfiguration extends Configuration {
  private val config = ConfigFactory.load

  override val dbUrl: String = config.getString("app.dbUrl")

  /**
    * @inheritdoc
    */
  override protected def toStringExclude: Seq[String] = Seq(nameOf(config))
}

Upvotes: 1

Lasf
Lasf

Reputation: 2582

I don't like this and I wouldn't do this but here's this:

class BasicConfiguration extends Configuration {

  private val config = ConfigFactory.load

  override val dbUrl: String = config.getString("app.dbUrl")

  private val excludeFields: Set[Any] = Set(config)

  override protected val toStringExclude: Seq[String] = {
    this.getClass
      .getDeclaredFields
      .filter(field => Try(field.get(this)).fold(_ => false, a => excludeFields.contains(a)))
      .map(_.getName)
      .toList
  }

}

Upvotes: 1

Related Questions