Pawel,
I agree that the current reflection approach is unwieldy and otherwise
problematic.
Regarding a language solution, though, I don't see how to avoid making
a mess of the definite assignment/unassignment semantics for final
fields. (Of course deserialization itself effectively subverts that
DA at runtime, and reflection DU, but at least the language is
unaware.) It's hard to say much without a specific proposal. But I
think that a language solution that includes detailed knowledge of
serialization semantics[*] would be highly undesirable, not only for
language purity reasons but also so that any needed evolution of those
library semantics is not locked with evolution of the language spec.
I could imagine some general way to let a (private) method be declared
to have constructor-like final field setting ability. But readObject
methods couldn't be required to have constructor-like DA semantics,
because a OIS.defaultReadObject invocation reflectively sets non-
transient final instance fields. So it would need to have constructor-
like DU semantics but not DA-- again, seems messy. And practically
speaking, I suspect that even a workable proposal would likely be
deemed too esoteric to fit within the necessarily-constrained budgets
for future language changes (that's only personal speculation).
So I think that the best hope is an improved reflective library
solution. Thinking out loud: say, a factory method that looks up a
field in the immediate caller's class with no permission requirement,
throws unchecked NoSuchFieldError instead of NoSuchFieldException, and
produces an object that can be used to set the field even if it's
final. Might be nice if the object were type-parameterized, but that
would rule out actually using java.lang.reflect.Field-- could be sort
of like the java.util.concurrent.atomic.Atomic*FieldUpdater APIs
(hmm...). It would not address your string lookup issue (field
literals would be helpful), but I doubt that the performance overhead
of the reflective field set is much of a concern. Note that, as far
as I know, pursuing something like this is not in current JDK plans.
Cheers,
-- Peter
[*] As described in the RFEs referenced below, the problem is more
nuanced than just with "transient" fields, such as if the serializable
class declares serialPersistentFields and/or uses the GetField API.
On Nov 29, 2009, at 5:12 PM, Pawel Veselov wrote:
Hi Peter,
not at all, I was late on replying to all the answers I've got myself.
Anyway, my thoughts around this were that I wouldn't consider it
reasonable to put that much, and that kind of code around re-
instantiation of final transient fields, at least for the sheer sake
of them being final. Reflection means referencing fields using
string values, and also places significant overhead in the
instructions that need to be executed (comparing to what it took to
create an object), the code that needs to be written (makes for poor
templating), and the kind of the operations that need to be
performed (needing security access, reflection itself is a shady
operation for a high level user code).
However, I don't really see any good way out of this situation, as
final fields are guaranteed instantiation during object
construction, but there is effectively no limit on how it can get
assigned, and what other objects would it use during such.
I would think that it would be reasonable to then allow the
readObject() to re-assign final transient fields under the same
rules that currently apply to setting final fields by constructors.
I understand that this is as bad of an idea, because readObject()
can be called by other means, however, this can be made into a
compiler warning, or something, and throw some VM errors if a final
field is ever modified outside of the instantiation or
deserialization process. I know this is somewhat lame, but I'm not
the VM engineer :) But I still believe that the current state of
things with final and transient modifiers is somewhat troublesome.
Thanks,
Pawel.
On Sun, Nov 29, 2009 at 1:05 PM, Peter Jones <p...@roundroom.net>
wrote:
Pawel,
Sorry for the late followup, but you might also want to read these
RFEs:
http://bugs.sun.com/view_bug.do?bug_id=6379948
http://bugs.sun.com/view_bug.do?bug_id=6252102
-- Peter
On Nov 9, 2009, at 6:54 PM, David Holmes - Sun Microsystems wrote:
Pawel,
Pawel Veselov said the following on 11/10/09 07:30:
it again caught my attention, and I though that may be there is
something that can be done about this.
The issue is obvious -- having 'final transient' instance fields
makes little sense if the object is ever serialized.
Logically, there may be perfect reasoning behind making an instance
field final, as well as transient, in which case there is then no
mechanism to reinitialize this field on object deserialization.
Not quite true. This problem - that final fields can only be set
during true construction and not during the pseudo-construction that
occurs during deserialization - has been realized for a long time.
As part of the Java 5 update we (I think it was done JSR-133) put in
place the mechanism whereby you can use reflection to set a final
field provided that setAccessible(true) has been invoked for that
field. This is of course a limited solution as you must have the
security capability to invoke setAccessible(true).
JSR-133 also addresses the Java Memory Model issues concerning
deserialization of objects with final fields - see Section 17.5.3 of
the Java Language Specification. (The notion of a "freeze action" on
a final field was in part motivated by the deserialization issue).
David Holmes
It seems that it would be nice if either the final fields were
initialized in a separate block that would be executed on
deserialization, or if readObject() could set them. After all you
can have a code block that sets the final fields. Not sure how
feasible that is, but IMHO, that is a short coming.
--
With best of best regards
Pawel S. Veselov
--
With best of best regards
Pawel S. Veselov