You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@river.apache.org by Mark Brouwer <ma...@marbro.org> on 2013/03/12 17:33:03 UTC
Re: Latest Java release causes runtime exception
Hi Dennis,
As I had some time to fix my own code as result of the change in the
serialized form of j.u.l.Level I had to look a bit better what has been
going on with j.u.l.Level and how to solve it. As a result I implemented
a more robust solution than that currently in trunk, more about that later.
On 2/22/13 5:38 PM, Dennis Reedy wrote:
> After a couple of go arounds discussing this in Jira, I recalled what you said here, and adding support for the 'localizedLevelName' in the com.sun.jini.logging.Levels$LevelData class seems to do the trick. So my original suggestion to create a CustomLevel as a way to deal with this is being rolled back. The original approach of creating a *real* level that introduces no runtime requirements for River classes in a JVM that reads LogRecords that have either Levels.HANDLED and Levels.FAILED remains.
>
Looking in most recent source code for JDK 1.7 and 1.6 it seems quite
clear that the field localizedLevelName should have been declared
transient, as there is no particular need to carry it around in the
serialized form. JDK 1.8 ea doesn't contain these changes yet, so the
Levels class worked without problems over there.
Do you have a bug id for http://bugs.sun.com/ for this issue, because to
prevent from duplicate reports I tried to search it. But that search
function in Sun/Oracle bug database is severely broken for quite a while
now.
However I have to correct my statement that Oracle breached the
serialized contract for j.u.l.Level. If the field localizedLevelName was
an intentional change it should have been documented with the @serial
tag, but according to section 5.6.2 of the the serialization
specification
(http://docs.oracle.com/javase/7/docs/platform/serialization/spec/version.html#6678)
adding a field is a compatible change and therefore the code in
com.sun.jini.logging.Levels shouldn't have failed. Although mentioned as
an incompatible change removing a field in a later version of a class
should not break deserialization with an older version either as in such
a case the default value is just assigned (although the state of the
object might be broken).
The real problems lies with c.s.j.l.Levels.LevelData as the class
c.s.j.l.Levels.ClassReplacingObjectOutputStream makes through the
writeClassDescriptor method the ObjectOutputStream 'believe' that
LevelData is effectively a Level instance. The class descriptor is
therefore in case of the latest JDK 1.6. and 1.7 telling there are 4
fields available in Level. LevelData is only able to provide 3 of these
(reading the 4th field through reflection doesn't seem to fail). I
analyzed the byte stream of what was serialized and although it was
mentioned there are 4 fields only values for 3 of them were actually
provided. Deserialization therefore failed because the class descriptor
is really expecting 4 values in the stream while there are only 3, hence
the EOF execption (in this particular case).
The solution is that LevelData must *really* mimic the serialized form
of the Level class. This can be accomplished by controlling the
serialized fields for LevelData by setting serialPersistentFields:
/** Fields from {@link Level} that needs to be serialized. */
private static final ObjectStreamField[] serialPersistentFields =
ObjectStreamClass.lookup(Level.class).getFields();
By implementing the following writeObject method on LevelData, the
values for the know fields of Level can be provides. This code will be
able to handle further evolution of the Level class as well:
/**
* Controls the writing of the actual fields to mimic those
* available in {@link Level}.
*/
private void writeObject(java.io.ObjectOutputStream out)
throws IOException
{
ObjectOutputStream.PutField putFields = out.putFields();
for (int i = 0 ; i < serialPersistentFields.length ; i++) {
ObjectStreamField field = serialPersistentFields[i];
if (field.getName().equals("name")) {
putFields.put(field.getName(), name);
}
else if (field.getName().equals("resourceBundleName")) {
putFields.put(field.getName(), resourceBundleName);
}
else if (field.getName().equals("value")) {
putFields.put(field.getName(), value);
}
// if a field name is unknown it looks like the Level class
// evolved, but we are in no position to provide a
// meaningful value, so therefore don't provide a value as
// the putField object already has the default values set
// for all fields as returned by serialPersistentFields
}
out.writeFields();
}
https://issues.apache.org/jira/browse/RIVER-416 contains a patch against
the trunk that could be applied, as well as the complete source code. My
j.u.l.Levels implementation was based on the initial submission from Sun
to Apache so it lacks the reformatting that was done in a previous
submit. I'm not closely monitoring what has changed with regard to the
project conventions, but I still assume the coding style in place is the
same as effective within Sun. I can even remember some fierce
discussions about tabs versus spaces in the beginning but as I see there
are still tabs and spaces that stayed the same too ;-)
IMHO maintaining the some coding style would ease in taking and giving
of code between various codebases out there in the field.
The above solution has been tested on various JDKs, I did verify the
actual objects created (all real instances of Level) and analyzed the
serialized byte streams and this does really does seems to do the trick.
At least I found it an interesting journey through the serialization
specification ...
Regards,
--
Mark Brouwer
Re: Latest Java release causes runtime exception
Posted by Dennis Reedy <de...@gmail.com>.
Mark,
Apologies for leaving an answer to your question below blank, I didn't catch it until now.
> Do you have a bug id for http://bugs.sun.com/ for this issue, because to prevent from duplicate reports I tried to search it. But that search function in Sun/Oracle bug database is severely broken for quite a while now.
No, I do not have a bug id for this, feel free to create a report.
Thanks again for the additional robustness in your patch.
Regards
Dennis
Re: Latest Java release causes runtime exception
Posted by Dennis Reedy <de...@gmail.com>.
On Mar 12, 2013, at 1233PM, Mark Brouwer wrote:
>
>
> https://issues.apache.org/jira/browse/RIVER-416 contains a patch against the trunk that could be applied, as well as the complete source code. My j.u.l.Levels implementation was based on the initial submission from Sun to Apache so it lacks the reformatting that was done in a previous submit. I'm not closely monitoring what has changed with regard to the project conventions, but I still assume the coding style in place is the same as effective within Sun. I can even remember some fierce discussions about tabs versus spaces in the beginning but as I see there are still tabs and spaces that stayed the same too ;-)
> IMHO maintaining the some coding style would ease in taking and giving of code between various codebases out there in the field.
I dont agree with the maintaining the current coding style, at times I find much of the code base to be unreadable (until it is formatted). Many of the conventions just dont seem to make sense anymore. For example, line length of 80 characters. Perhaps this made sense when out display resolution was 640x780, (recall the conventions were last updated in 1999), but not for today. I dont even want to start the discussion on tabs vs spaces (I use spaces).
>
> The above solution has been tested on various JDKs, I did verify the actual objects created (all real instances of Level) and analyzed the serialized byte streams and this does really does seems to do the trick. At least I found it an interesting journey through the serialization specification ...
The approach I had provided also was tested on various JDKs. However, I'm glad to accept your patch
Thanks
Dennis