Reflection is the correct answer. Other than with @InjectMocks
or the recently removed internal class Whitebox, Mockito doesn't concern itself at all with fields, so you need to handle field access yourself or call setters on your spy.
As for rationale, I haven't seen one, but remember what Mockito does: It offers tooling and neat syntax to record and verify interactions—method calls, to be more specific—by internally creating a dynamic subclass (proxy) that overrides all methods. With fields there's nothing to record or verify, because the JVM just sets the value; working with fields would be a little out of Mockito's scope and introduce a lot of caveats about which fields can be changed (private? static? final?) and what you can do with them (not stub or verify multiple interactions).
Though Mockito doesn't explicitly recommend using getters, they are one of the few seams where you could override/track state accesses, so there's something to be said for using them all across Java for encapsulation's sake. If you can't set and read values like this:
mockitoMockWithFields.fieldA = 42;
return mockitoMockWithFields.fieldB;
Then all you're looking for Mockito to do is to defeat encapsulation or finality; Mockito can't do either natively, even for methods, so it's probably pretty reasonable for you to defeat those yourself or with a different library.