1 2 Previous Next 17 Replies Latest reply on Jul 18, 2007 4:37 AM by alesj

    ClassInfo being serializable

    alesj

      As http://jira.jboss.com/jira/browse/JBMICROCONT-128 states, ClassInfo is holding reference to TypeInfoFactory.

      Solutions:
      (a) making TypeInfoFactory transient - lazy constructing on deserialization
      (b) making TypeInfoFactory serializable

      Can (a) be done in reasonable way?

      I've taken (b) approach.

      Making TypeInfoFactory means making WeakTypeCache serializable.

      Is this legit:

      public abstract class WeakTypeCache<T> implements Serializable
      {
       private static final long serialVersionUID = 7314636572425329549L;
      
       /** The cache */
       private transient Map<ClassLoader, Map<String, T>> cache;
      
       private Map<ClassLoader, Map<String, T>> getCache()
       {
       if (cache == null)
       cache = new WeakHashMap<ClassLoader, Map<String,T>>();
       return cache;
       }
      
       ...
      
       private synchronized Map<String, T> getClassLoaderCache(ClassLoader cl)
       {
       Map<ClassLoader, Map<String, T>> cache = getCache();
       Map<String, T> result = cache.get(cl);
       if (result == null)
       {
       result = new WeakValueHashMap<String, T>();
       cache.put(cl, result);
       }
       return result;
       }
      }
      


      I've added 'new' WeakClassCache (similar to existing in commons) for JavassistTypeInfoFactoryImpl to extend.

      public abstract class WeakClassCache extends WeakTypeCache<Object>
      {
       private static final long serialVersionUID = 2352263033415675186L;
      
       protected Object instantiate(ParameterizedType type)
       {
       throw new UnsupportedOperationException("No such method in WeakClassCache from JBoss-Commons.");
       }
      
       protected void generate(ParameterizedType type, Object result)
       {
       throw new UnsupportedOperationException("No such method in WeakClassCache from JBoss-Commons.");
       }
      }
      


      After doing this I'm able to get ClassInfoTestSuite running for Introspection test cases, but I get new failures for Javassist:
      - CtClass not being serializable in JavassistInheritableAnnotationHolder
      - javassist AnnotationImpl not being serializable
      - ...

        • 1. Re: ClassInfo being serializable

          No. You don't want an instance of TypeInfoFactory for every type
          which is what will happen if you implement (b).

          That will lead to multiple caches each with their own versions of the 'same" object.
          What a waste of memory.

          The IntrospectionTypeInfoFactoryImpl is already a singleton if you look at it
          properly. The singleton is held in the wrapper IntrospectionTypeInfoFactory
          for exactly the reason that even if two people construct their own,
          you don't want multiple versions of the data. They share the data.

          The solution should just involve reconnecting to that singleton (from the reflect
          implementation of ClassInfo) during deserialization.

          You should just disable the serialization tests for the javassist versions
          and it to its outstanding jira tasks.

          • 2. Re: ClassInfo being serializable
            alesj

             

            "adrian@jboss.org" wrote:

            What a waste of memory.

            :-)

            "adrian@jboss.org" wrote:

            The solution should just involve reconnecting to that singleton (from the reflect
            implementation of ClassInfo) during deserialization.

            I've introduced a new 'helper' which knows how to provide the three already existing helpers ClassInfoImpl needs - TypeInfoFactory, ClassInfoHelper and AnnotationHelper.
            In the case of Introspection all three are implemented in one class: IntrospectionTypeInfoFactoryImpl.

            I've just added IntrospectionDelegateHolder so that IntrospectionTypeInfoFactory remains almost the same, just impl TypeInfoFactory.
            "adrian@jboss.org" wrote:

            You should just disable the serialization tests for the javassist versions
            and it to its outstanding jira tasks.

            Done.
            Yet to update tasks.

            • 3. Re: ClassInfo being serializable

              I don't understand this new helper?

              Modified: projects/microcontainer/trunk/container/src/main/org/jboss/reflect/plugins/ClassInfoImpl.java
              ===================================================================
              --- projects/microcontainer/trunk/container/src/main/org/jboss/reflect/plugins/ClassInfoImpl.java 2007-07-11 14:58:35 UTC (rev 63972)
              +++ projects/microcontainer/trunk/container/src/main/org/jboss/reflect/plugins/ClassInfoImpl.java 2007-07-11 15:16:44 UTC (rev 63973)
              @@ -26,6 +26,9 @@
               import java.util.Collection;
               import java.util.HashMap;
               import java.util.Map;
              +import java.io.ObjectInputStream;
              +import java.io.IOException;
              +import java.io.ObjectOutputStream;
              
               import org.jboss.reflect.spi.ClassInfo;
               import org.jboss.reflect.spi.ConstructorInfo;
              @@ -108,27 +111,86 @@
               protected PackageInfo packageInfo;
              
               /** The class info helper */
              - protected ClassInfoHelper classInfoHelper;
              + protected transient ClassInfoHelper classInfoHelper;
              
               /** The type info factory */
              - protected TypeInfoFactory typeInfoFactory;
              + protected transient TypeInfoFactory typeInfoFactory;
              
               /** The attachments */
               private transient TypeInfoAttachments attachments;
              
              + /** The serialization helper */
              + private SerializationHelper serializationHelper;
              


              I don't really understand why you are serializing any state
              except the annotatedElement.

              All you need to do is rehook into the typeinfo factory using some package
              protected method and recreate the other state during deserialization
              (most of it can be left to be initialized lazily?)

              public void readObject(...)
              {
               super.readObject(...);
               typeInfoFactory = new IntrospectionTypeInfoFactory(...);
               classInfoHelper = typeInfoFactory.getClassInfoHelper();
               // etc.
              }
              


              In fact, a much more trivial mechanism would be to use "readResolve"

              Object readResolve()
              {
               IntrospectionTypeInfoFactory factory = new IntrospectionTypeInfoFactory();
               return factory.getTypeInfo(annotatedElement);
              }
              


              Then you aren't creating multiple ClassInfo objects during deserialization,
              especially if they are already present in the cache.

              • 4. Re: ClassInfo being serializable

                You should probably also include a static reference for a singleton TypeInfoFactory
                somewhere to avoid the continous object construction for lots of serialization.

                • 5. Re: ClassInfo being serializable
                  alesj

                  I guess we are talking about ClassInfoImpl.

                  I don't understand this new helper?

                  All you need to do is rehook into the typeinfo factory using some package
                  protected method and recreate the other state during deserialization
                  (most of it can be left to be initialized lazily?)


                  What about non-serializable references to ClassInfoHelper and AnnotationHelper?
                  How do you (de)serialize those?



                  Object readResolve()
                  {
                   IntrospectionTypeInfoFactory factory = new IntrospectionTypeInfoFactory();
                   return factory.getTypeInfo(annotatedElement);
                  }
                  


                  Then you aren't creating multiple ClassInfo objects during deserialization,
                  especially if they are already present in the cache.


                  This looks like an optimal solution.
                  If you are in the same Classloader then there is no new ClassInfo instance creation, since _we_ been serialized, so _we_ exist in cache. :-)

                  • 6. Re: ClassInfo being serializable
                    alesj

                     

                    "adrian@jboss.org" wrote:
                    You should probably also include a static reference for a singleton TypeInfoFactory
                    somewhere to avoid the continous object construction for lots of serialization.


                    Making IntrospectionTypeInfoFactory and JavassistTypeInfoFactory also available as singletons?

                    • 7. Re: ClassInfo being serializable
                      alesj

                       

                      public void readObject(...)
                      {
                       super.readObject(...);
                       typeInfoFactory = new IntrospectionTypeInfoFactory(...);
                       classInfoHelper = typeInfoFactory.getClassInfoHelper();
                       // etc.
                      }
                      

                      "alesj" wrote:

                      What about non-serializable references to ClassInfoHelper and AnnotationHelper?
                      How do you (de)serialize those?


                      IntrospectionTypeInfoFactory currently only knows about TypeInfoFactory.
                      So no ClassInfoHelper from there. ;-)
                      Exposing IntrospectionTypeInfoFactory as other helpers?

                      • 8. Re: ClassInfo being serializable

                         

                        "alesj" wrote:

                        IntrospectionTypeInfoFactory currently only knows about TypeInfoFactory.
                        So no ClassInfoHelper from there. ;-)
                        Exposing IntrospectionTypeInfoFactory as other helpers?


                        Why? The helpers are implementation details for lazy loading of information.
                        Javassist doesn't need that since it already implements it internally.

                        In fact, a lot of the reflection classes do as well already in recent versions of the JDK.
                        That's one of the reasons why reflection has gotten much faster over the years,
                        but it still isn't as fast as the javassist version in my testing. ;-)

                        Also we can make the javassist stuff even faster if we can come up with an api
                        that links the classloading, aop (javassist) and classinfo
                        byte code loading together.


                        • 9. Re: ClassInfo being serializable
                          alesj

                           

                          "adrian@jboss.org" wrote:

                          Object readResolve()
                          {
                           IntrospectionTypeInfoFactory factory = new IntrospectionTypeInfoFactory();
                           return factory.getTypeInfo(annotatedElement);
                          }
                          


                          I don't want to introduce Introspection detail to ClassInfoImpl which currently doesn't know anything about introspection package.

                          And the annotatedElement in this case is always of Type instance?
                          I'll add a check before anyway.

                          • 10. Re: ClassInfo being serializable
                            alesj

                             

                            "alesj" wrote:

                            And the annotatedElement in this case is always of Type instance?
                            I'll add a check before anyway.


                            Or I can use the @Deprecated getType() method. :-)

                            • 11. Re: ClassInfo being serializable

                              What does ClassInfoImpl have to do with it?
                              You do it in the subclass ReflectClassInfoImpl.

                              • 12. Re: ClassInfo being serializable
                                alesj

                                 

                                "adrian@jboss.org" wrote:
                                What does ClassInfoImpl have to do with it?
                                You do it in the subclass ReflectClassInfoImpl.


                                Yup, that would work. :-)

                                How come this doesn't effect other subclasses of ClassInfoImpl - ArrayInfoImpl, EnumInfoImpl, InterfaceInfoImpl, AnnotationInfoImpl?
                                They don't need typeInfoFactory, classInfoHelper, annotationHelper after deserialization?

                                • 13. Re: ClassInfo being serializable

                                  None of them makes any direct use of reflection, so a reflection specific subclass
                                  has never been necessary before.
                                  But you'll probably need to introduce a Reflection* subclass for
                                  each to make the serialization work, i.e. add readResolve() into the introspection factory.

                                  • 14. Re: ClassInfo being serializable
                                    alesj

                                     

                                    "adrian@jboss.org" wrote:

                                    But you'll probably need to introduce a Reflection* subclass for
                                    each to make the serialization work,

                                    I did a quick change - moved readResolve() from ClassInfoImpl to ReflectClassInfoImpl.
                                    How come all the tests still work?
                                    Not covering all the corner cases?

                                    "adrian@jboss.org" wrote:

                                    i.e. add readResolve() into the introspection factory.

                                    What about if I add a super class for all Reflection* subclases with readResolve there?

                                    1 2 Previous Next