Search code examples
javaserializationclassloader

Java: (Partial) Serialization of classes (not objects!)


I am currently working on a task to package a component and its dependencies together and makes a stand-alone component out of it that has all needed stuff included.

I have the situation that I might have user-defined classes which I need to include in this component, too.

I am looking for a way to serialize them in a slim/smart way. These classes have a inheritance hierarchy for instance:

FrameWorkSuper
--------------
UserSuper 
UserClass

Is there a way to serialize only the User-defined part of a class to keep the footprint small? Anything that originates from the framework is definitely in the final component included. Thus I want to serialize and load later only the user-defined part of the whole in a way that the class gets that the framework part is also in the package.

Is there a way to achieve that or any recommendation for this task that I should use?


Solution

  • I think what you want to do is transfer the actual byte code of the user-defined classes.

    1. If you do not have the byte code of the classes and just the source code, you need to compile it first. I suggest using JavaCompiler.
      • Since it is a little tedious to compile everything to disk and then read it to a byte array again, you might want to use your own FileManager and JavaFileObject implementations, I can provide details on this step if necessary.
    2. Once you have the byte code of your class, send it to wherever you want it to be (file, database, remote site).
    3. When "deserializing" (as others noted, serialization is not really the right term), load the byte code from wherever you have it.
    4. Create a custom classloader which gets the byte code of all the classes and override its findClass method to something like

      // first try our cache of loaded classes
      if (loadedClasses.containsKey(name)) {
          return loadedClasses.get(name);
      }
      
      // that didn't work, maybe the class was compiled but not yet loaded
      if (compiledClasses.containsKey(name)) {
          // get the representation from the cache
          InMemoryClassJavaFileObject inMemoryRepresentation = compiledClasses.get(name);
          // let our parent define the class
          Class<?> clazz = defineClass(name, inMemoryRepresentation.getData(), 0, inMemoryRepresentation.getData().length);
          // and store it in the cache for later retrieval
          loadedClasses.put(name, clazz);
          return clazz;
      }
      

      Note that you do not need to create InMemoryClassJavaFileObject, you can simply use a byte array.

    5. Do achieve the above, you will need to obtain the fully qualified name of a class from its byte code. Either deliver that information separately or use this method

    That gives you access to the class itself on the remote site: you can create instances and use their methods.