java - Serialización sin reflexión en clases compiladas.
serialization code-generation (3)
Algunas posibles alternativas:
- Si puede usar scala, este proyecto compila la generación del serializador de tiempo: https://github.com/scala/pickling
- Esta pregunta de stackoverflow señala la posibilidad de usar aspectJ y el procesamiento de anotaciones: AspectJ / Generar métodos usando la reflexión en tiempo de compilación
Por cierto, sus clases no necesitan ser anotadas si su procesador de anotaciones pretende procesar "*" todas las anotaciones. - Seren (SERialization ENhancer) afirma que "mejora tus clases para que sean más rápidas de serializar". Sin embargo, al igual que muchas otras herramientas, lo hace en el momento de la carga ... Podría ser posible adaptarlo para hacer una instrumentación de tiempo de compilación, o sugerirle eso a su creador.
- leshy , también hace instrumentación en tiempo de ejecución. Lo mismo: adaptarlo al tiempo de compilación o sugerirlo al autor.
Debido a la limitación en la JVM del cliente, no puedo usar ninguno de los serializadores populares debido a que la reflexión no es compatible. Estoy buscando una herramienta que realice la manipulación de códigos de bytes para lograr la serialización mediante la inyección de métodos de escritura y lectura en la clase ya compilada. Necesito el código java de manipulación de código de bytes para enlazarlo con mi código para el proceso de construcción.
He estado haciendo esto generando código e inyectándolo en el código fuente antes de compilar para usar mi serializador personalizado. Me gustaría evitar este enfoque, ya que no quiero modificar los archivos de origen de ninguna manera.
Soy consciente de Kryo y otros serializadores XML y JSON, pero no coinciden con mis necesidades.
Gracias.
Prueba javassist . Probablemente sea la biblioteca de generación de código de bytes más sencilla para su proyecto en particular.
Esto se debe a que podrá reutilizar parte de su generador de código actual, ya que javassist puede analizar algunas formas simples de código Java.
Por ejemplo puedes hacer:
CtClass clazz = ...;
CtMethod m = CtNewMethod.make(
"public void serialize(java.io.DataOutput out) { out.writeInt(x); }",
clazz);
Si desea profundizar en la generación de código de bytes, puede probar asm . Asm le permitirá escribir código de bytes directamente, pero parece ser una exageración para su tipo de problema.
Implementación con javassist
Aquí está el esqueleto base para hacer esto con javassist:
Path inputDir = Paths.get("target/classes");
Path outputDir = Paths.get("target/classes2");
ClassPool classPool = new ClassPool(true);
classPool.appendClassPath(inputDir.toString());
// get all class names from a certain directory
String[] classNames = Files.walk(inputDir)
.filter(p -> (!Files.isDirectory(p)) && p.toString().endsWith(".class"))
.map(p -> inputDir.relativize(p).toString())
.map(s -> s.substring(0, s.length() - 6).replace(File.separatorChar, ''.''))
.toArray(size -> new String[size]);
for (String className : classNames) {
CtClass clazz = classPool.get(className);
// add further filtering to select the classes you want.
// ex: "public void serializer(java.io.DataOutput out) { out.writeInt(x); } }"
String serializerBody = generateSerializer(clazz);
clazz.addMethod(CtNewMethod.make(serializerBody, clazz));
// ex: "public void deserializer(java.io.DataInput in) { x = in.readInt(); } }";
String deserializerBody = generateDeserializer(clazz);
clazz.addMethod(CtNewMethod.make(deserializerBody, clazz));
// save the modified class
clazz.setModifiers(clazz.getModifiers() & ~Modifier.ABSTRACT);
byte[] bytes = clazz.toBytecode();
Path outFile = outputDir.resolve(className.replace(''.'', ''/'') + ".class");
Files.createDirectories(outFile.getParent());
Files.write(outFile, bytes);
}
Dependencia: org.javassist:javassist:3.19.0-GA
Puedes usar mi biblioteca Byte Buddy para este propósito. Byte Buddy es una biblioteca de manipulación de códigos de bytes y le permite agregar métodos fácilmente a cualquier clase existente. Además, le permite inyectar código redefinido en un archivo jar . De esta manera, puede pedir a Byte Buddy que redefina las clases para agregar los métodos necesarios. Sin embargo, tenga en cuenta que agregar métodos a una clase podría cambiar su uuid de serialización implícita.
Si no se deben cargar las clases hasta que se inicie la aplicación, Byte Buddy le permite redefinir las clases sin cargarlas. Para esto, puedes usar el tipo de pool de Byte Buddys.