From 74cfc80b10be0707eb3c7b661cca17e2f222b246 Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Wed, 28 Sep 2022 12:07:21 +0200 Subject: [PATCH] Jakarta - Rewrite Quartz bytecode to jakarta.* packages Fixes #27065 (cherry picked from commit 3a4af3254161a05de855dd41e1c6fcc871b079f0) --- extensions/quartz/deployment/pom.xml | 5 ++ .../quartz/deployment/JakartaEnablement.java | 89 +++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 extensions/quartz/deployment/src/main/java/io/quarkus/quartz/deployment/JakartaEnablement.java diff --git a/extensions/quartz/deployment/pom.xml b/extensions/quartz/deployment/pom.xml index bd80fad38a3d5..7dc4e797cfb5f 100644 --- a/extensions/quartz/deployment/pom.xml +++ b/extensions/quartz/deployment/pom.xml @@ -34,6 +34,11 @@ io.quarkus quarkus-quartz + + org.eclipse.transformer + org.eclipse.transformer + 0.5.0 + io.quarkus diff --git a/extensions/quartz/deployment/src/main/java/io/quarkus/quartz/deployment/JakartaEnablement.java b/extensions/quartz/deployment/src/main/java/io/quarkus/quartz/deployment/JakartaEnablement.java new file mode 100644 index 0000000000000..7bb45dfb9afbc --- /dev/null +++ b/extensions/quartz/deployment/src/main/java/io/quarkus/quartz/deployment/JakartaEnablement.java @@ -0,0 +1,89 @@ +package io.quarkus.quartz.deployment; + +import java.nio.ByteBuffer; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.eclipse.transformer.action.ActionContext; +import org.eclipse.transformer.action.ByteData; +import org.eclipse.transformer.action.impl.ActionContextImpl; +import org.eclipse.transformer.action.impl.ByteDataImpl; +import org.eclipse.transformer.action.impl.ClassActionImpl; +import org.eclipse.transformer.action.impl.SelectionRuleImpl; +import org.eclipse.transformer.action.impl.SignatureRuleImpl; +import org.eclipse.transformer.util.FileUtils; +import org.objectweb.asm.ClassReader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.quarkus.bootstrap.classloading.QuarkusClassLoader; +import io.quarkus.deployment.annotations.BuildProducer; +import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.deployment.builditem.BytecodeTransformerBuildItem; + +/** + * Quartz is compiled using references to classes in the javax packages; + * we need to transform these to fix compatibility with jakarta packages. + * We do this by leveraging the Eclipse Transformer project during Augmentation, so + * that end users don't need to bother. + */ +public class JakartaEnablement { + + private static final List CLASSES_NEEDING_TRANSFORMATION = List.of( + "org.quartz.ExecuteInJTATransaction", + "org.quartz.ee.servlet.QuartzInitializerServlet", + "org.quartz.ee.servlet.QuartzInitializerListener", + "org.quartz.ee.jta.JTAJobRunShell", + "org.quartz.ee.jta.UserTransactionHelper", + "org.quartz.ee.jta.UserTransactionHelper$UserTransactionWithContext", + "org.quartz.xml.XMLSchedulingDataProcessor", + "org.quartz.impl.jdbcjobstore.JTANonClusteredSemaphore"); + + @BuildStep + void transformToJakarta(BuildProducer transformers) { + if (QuarkusClassLoader.isClassPresentAtRuntime("jakarta.transaction.Transaction")) { + JakartaTransformer tr = new JakartaTransformer(); + for (String classname : CLASSES_NEEDING_TRANSFORMATION) { + final BytecodeTransformerBuildItem item = new BytecodeTransformerBuildItem.Builder() + .setCacheable(true) + .setContinueOnFailure(false) + .setClassToTransform(classname) + .setClassReaderOptions(ClassReader.SKIP_DEBUG) + .setInputTransformer(tr::transform) + .build(); + transformers.produce(item); + } + } + } + + private static class JakartaTransformer { + + private final Logger logger; + private final ActionContext ctx; + // We need to prevent the Eclipse Transformer to adjust the "javax" packages. + // Thus why we split the strings. + private static final Map renames = Map.of("javax" + ".transaction", "jakarta.transaction", + "javax" + ".servlet", "jakarta.servlet", + "javax" + ".xml.bind", "jakarta.xml.bind"); + + JakartaTransformer() { + logger = LoggerFactory.getLogger("JakartaTransformer"); + //N.B. we enable only this single transformation of package renames, not the full set of capabilities of Eclipse Transformer; + //this might need tailoring if the same idea gets applied to a different context. + ctx = new ActionContextImpl(logger, + new SelectionRuleImpl(logger, Collections.emptyMap(), Collections.emptyMap()), + new SignatureRuleImpl(logger, renames, null, null, null, null, null, Collections.emptyMap())); + } + + byte[] transform(final String name, final byte[] bytes) { + logger.debug("Jakarta EE compatibility enhancer for Quarkus: transforming " + name); + final ClassActionImpl classTransformer = new ClassActionImpl(ctx); + final ByteBuffer input = ByteBuffer.wrap(bytes); + final ByteData inputData = new ByteDataImpl(name, input, FileUtils.DEFAULT_CHARSET); + final ByteData outputData = classTransformer.apply(inputData); + return outputData.buffer().array(); + } + } + +}