Подтвердить что ты не робот

Сериализация без отражения в скомпилированных классах

Из-за ограничений на JVM клиента я не могу использовать ни один из популярных сериализаторов из-за того, что отражение не поддерживается. Я ищу инструмент, который выполняет манипуляции с байт-кодом, чтобы добиться сериализации, введя методы записи и чтения в уже скомпилированный класс. Мне нужен код java-кода для манипулирования байтом, чтобы связать его с моим кодом для создания процесса.

Я делаю это, создавая код и вводя его в исходный код перед компиляцией для использования моего настраиваемого сериализатора. Я бы хотел избежать этого подхода, поскольку я не хочу, чтобы вы каким-либо образом изменяли исходные файлы.

Я знаю Kryo и другие сериализаторы XML и JSON, но они не соответствуют моим потребностям.

Спасибо.

4b9b3361

Ответ 1

Попробуйте javassist. Это, вероятно, самая простая библиотека генерации байт-кода для вашего конкретного проекта.

Это потому, что вы сможете повторно использовать часть своего текущего генератора кода, поскольку javassist может анализировать некоторые простые формы Java-кода.

Например, вы можете:

CtClass clazz = ...;
CtMethod m = CtNewMethod.make(
    "public void serialize(java.io.DataOutput out) {  out.writeInt(x); }",
     clazz);

Если вы хотите глубоко погрузиться в генерацию байт-кода, вы можете попробовать asm. Asm позволит вам писать байт-код напрямую, но, похоже, это избыток для вашей проблемы.

Реализация с javassist

Вот базовый скелет для этого с 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);
}

Зависимость: org.javassist:javassist:3.19.0-GA

Ответ 2

Для этой цели вы можете использовать мою библиотеку Byte Buddy. Byte Buddy - это библиотека управления байтовым кодом, которая позволяет вам легко добавлять методы в любой существующий класс. Кроме того, он позволяет вводить переопределенный код в файл jar. Таким образом, вы можете попросить Byte Buddy переопределить классы, чтобы добавить необходимые методы. Однако обратите внимание, что добавление методов в класс может изменить его неявную сериализацию uuid.

Если ваши классы не должны загружаться до запуска вашего приложения, Byte Buddy позволяет вам переопределять классы без их загрузки. Для этого вы можете использовать пул типов Byte Buddys.

Ответ 3

Некоторые возможные альтернативы:

  • Если вы можете использовать scala, этот проект выполняет компиляцию генерации временного сериализатора: https://github.com/scala/pickling
  • В этом вопросе stackoverflow указывается на возможность использования aspectJ и обработки аннотаций: AspectJ/Создание методов с использованием отражения во времени компиляции
    BTW, ваши классы не нужно аннотировать, если ваш обработчик аннотации требует обработать "*" все аннотации.
  • Seren (SERialization ENhancer) утверждает, что "улучшает ваши классы, чтобы они намного быстрее сериализовались". Однако, как и многие другие инструменты, он делает это во время загрузки... Возможно, его можно будет адаптировать для создания инструментария времени сборки или предложить создать его создателю.
  • leshy, также выполняет инструментарий времени исполнения. То же самое: адаптируйте его для компиляции времени или предложите это автору.