SUGGESTED FIX
The fix for that bug is in the XMLEncoder class in which it uses a per instance NameGenerator, internal persistence delegate access in Meta data is syncronized and the biggest fix is in the new ReflectionUtils class - most of the methods and structures are from Statement. Syncronized access is done to the method cache and it will be collected when memory becomes low.
There is also a considerable amount of refactoring:
- Consolidation of 4 implementations of "capitalize" into 1 in NameGenerator.
- Replaced package private IdentityHashtable with java.util.IdentityHashMap.
- Consolidated reflection utilities into ReflectionUtils
- Removed a lot of one line methods.
There is only one issue: now that Statement.instanceName doesn't use the name generator, debugging output will not provide as much detail upon failure. This is a small issue and only really affects annonymous inner classes. I spent the entire day trying to figure this one out using ThreadLocal and other means and I couldn't find a thead safe way to resolve this. Since this is mostly for debugging, a better solution would be to implement logging.
###@###.### 2003-09-19
|
EVALUATION
I ran the test case on a dual processor machine and I'm getting the deadlock. I modified Statement.getMethod() to be synchronized and it seemed to have fixed the problem but I'm sure it has affected performance. Since multi-threaded access to the XMLEncoder is an unconventional way of using the encoder I don't think that this is the proper solution since it may penalize other more conventional users of this API.
Perhaps the best way to address this problem is to provide a function that will enable thread safety using a flag.
I still haven't investigated the NPE.
###@###.### 2003-06-25
The NPE is still part of the same synchronization bug. This problem went away when the getMethod, setCaching and isCaching methods are synchronized.
Will fix for Tiger.
###@###.### 2003-08-07
AFter discussing this issue with the original architect, we should get rid of the setCaching private method and leave caching on all the time.
###@###.### 2003-09-09
Implemented the solution with a syncronized getMethod and the test case will exectute correctly - most of the time. 1/5 it will fail because of an IllegalAccessException:
Caused by: java.lang.IllegalAccessException: Can not call newInstance() on the Class for java.lang.Class
at java.lang.Class.newInstance0(Class.java:273)
at java.lang.Class.newInstance(Class.java:261)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:324)
at java.beans.Statement.invoke(Statement.java:441)
at java.beans.Expression.getValue(Expression.java:101)
at java.beans.Encoder.getValue(Encoder.java:84)
The scope of this bug will broaden to fix all multi-threaded issues with the encoder rather than the one presented in the test case. Spectifically, NameGenerator.clear and instanceName is not thread safe.
###@###.### 2003-09-12
|