Skip to content
Anjunar/ DOCS

Fields

Fields come in two sets: declared on the class, and everything visible through the hierarchy. Each knows its resolved type and reads and writes without access checks.

Lookup

findField and findDeclaredField

findField searches the whole hierarchy, private fields included; findDeclaredField only the class itself. Both return null when nothing matches.

scala
class User(private var id: Long, val name: String) val user = TypeResolver.resolve(classOf[User]) val name = user.findField("name") println(name.fieldType.fullName) // java.lang.String println(user.fields.map(_.name).mkString(", ")) // id, name
Scala

Which parameters become fields

A val or var parameter always becomes a private field with accessor methods. A plain constructor parameter becomes a field only if the class uses it outside the constructor.

class A(val x: Int)
Field x and method x().
class A(var x: Int)
Field x, methods x() and x_$eq(int).
class A(x: Int) { def twice = x * 2 }
Field x, because twice reads it.
class A(x: Int) extends B(x)
No field; x only reaches the super constructor.
Hiding

The most specific field wins

When a subclass declares a field with the name of a superclass field, fields lists only the subclass's. The hidden ones stay reachable through hidden, and their annotations are merged into annotations.

java
public class Base { @Deprecated protected String label = "base"; } public class Child extends Base { private String label = "child"; }
scala
val field = TypeResolver.resolve(classOf[Child]).findField("label") println(field.owner.name) // Child println(field.hidden.map(_.owner.name).mkString(", ")) // Base println(field.findAnnotation(classOf[Deprecated]) != null) // true
Access

get and set

Both make the field accessible first, so private fields work without extra steps. A final field can be read but its value should not be written.

scala
val ada = new User(1L, "Ada") val id = TypeResolver.resolve(classOf[User]).findDeclaredField("id") id.set(ada, 2L) println(id.get(ada)) // 2
Fields bypass your logic

Writing a field skips the setter and everything in it. For values that go through validation or events, use a property (bean or annotated) and its setter.