1

I have a framework used exclusively for testing that sets fields at runtime. The purpose is to set up test cases. Looking forward to upgrading to Java 14+ records I am noticing that existing utilities such as ReflectionTestUtils.setField and PropertyAccessorFactory.forDirectFieldAccess which work on normal private final fields, do not work for record fields.

Is this a limitation of the JVM, or is a limitation of these utilities?

Naman
  • 27,789
  • 26
  • 218
  • 353
Joseph K. Strauss
  • 4,683
  • 1
  • 23
  • 40
  • 2
    It's a limitation of these utilities. Record fields are final, that means that they can not be modified after they have been set. If you need a record with different values, create a new record. – Johannes Kuhn Feb 09 '22 at 07:38

1 Answers1

5

Since modifying the private final fields of a record is intentionally unsupported, it’s not a limitation of the JVM or Java execution environment, so relying on the ability to modify such fields is a limitation of these utilities.

The documentation of setAccessible says:

This method cannot be used to enable write access to a non-modifiable final field. The following fields are non-modifiable:

  • static final fields declared in any class or interface
  • final fields declared in a hidden class
  • final fields declared in a record

The original intent of supporting to write a final instance field via access override, was to allow fixing the object state after cloning or deserializing. Neither is necessary for a record.

  • Deserializing a record instance will invoke its constructor, so the constructor can apply all necessary validation and fixes before the final fields are assigned.

  • Creating a shallow clone of a record has no point at all. For all other copying purposes, you can read all of its components, as each field has a corresponding accessor method, adapt them, and pass the adapted values to the always existing canonical constructor.

Holger
  • 285,553
  • 42
  • 434
  • 765
  • Please clarify. Answer states "is intentionally not supported", and also "it's not a limitation of the JVM or Java execution environment". These statements seem contradictory. – Joseph K. Strauss Feb 11 '22 at 15:39
  • 2
    A limitation would be a missing feature, but here, the environment works exactly as intended. You can be sure that changing `record` fields after construction will never be supported. – Holger Feb 11 '22 at 16:06
  • I was using limitation in the sense of a limitation imposed by the JVM. Thanks for the clarification. – Joseph K. Strauss Feb 11 '22 at 16:18