diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/generator/ProcessorRegistry.java b/generator/src/main/java/com/reajason/javaweb/memshell/generator/ProcessorRegistry.java index 8f278e69..2c29890b 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/generator/ProcessorRegistry.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/generator/ProcessorRegistry.java @@ -17,11 +17,11 @@ public final class ProcessorRegistry { private static final List>> BUILDER_PROCESSORS = Arrays.asList( new ListenerBuilderModifier(), new ValveBuilderModifier(), - new JakartaBuilderModifier(), new DebugOffBuilderModifier() ); private static final List> BYTE_PROCESSORS = Arrays.asList( + new JakartaPostProcessor(), new JettyHandlerPostProcessor(), new ShrinkPostProcessor() ); diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/generator/processors/JakartaBuilderModifier.java b/generator/src/main/java/com/reajason/javaweb/memshell/generator/processors/JakartaBuilderModifier.java deleted file mode 100644 index cb83b2fe..00000000 --- a/generator/src/main/java/com/reajason/javaweb/memshell/generator/processors/JakartaBuilderModifier.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.reajason.javaweb.memshell.generator.processors; - -import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper; -import com.reajason.javaweb.memshell.config.ShellConfig; -import com.reajason.javaweb.memshell.config.ShellToolConfig; -import com.reajason.javaweb.memshell.generator.Processor; -import net.bytebuddy.dynamic.DynamicType; - -/** - * @author ReaJason - * @since 2025/12/7 - */ -public class JakartaBuilderModifier implements Processor> { - - @Override - public DynamicType.Builder process(DynamicType.Builder builder, ShellConfig shellConfig, ShellToolConfig shellToolConfig) { - if (shellConfig.isJakarta()) { - builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE); - } - return builder; - } -} diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/generator/processors/JakartaPostProcessor.java b/generator/src/main/java/com/reajason/javaweb/memshell/generator/processors/JakartaPostProcessor.java new file mode 100644 index 00000000..dc493172 --- /dev/null +++ b/generator/src/main/java/com/reajason/javaweb/memshell/generator/processors/JakartaPostProcessor.java @@ -0,0 +1,16 @@ +package com.reajason.javaweb.memshell.generator.processors; + +import com.reajason.javaweb.asm.ClassRenameUtils; +import com.reajason.javaweb.memshell.config.ShellConfig; +import com.reajason.javaweb.memshell.config.ShellToolConfig; +import com.reajason.javaweb.memshell.generator.Processor; + +public class JakartaPostProcessor implements Processor { + @Override + public byte[] process(byte[] input, ShellConfig shellConfig, ShellToolConfig shellToolConfig) { + if (shellConfig.isJakarta()) { + return ClassRenameUtils.relocateJakarta(input); + } + return input; + } +} diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/generator/processors/ListenerBuilderModifier.java b/generator/src/main/java/com/reajason/javaweb/memshell/generator/processors/ListenerBuilderModifier.java index c2a188e2..897fc631 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/generator/processors/ListenerBuilderModifier.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/generator/processors/ListenerBuilderModifier.java @@ -17,6 +17,7 @@ import net.bytebuddy.description.modifier.Visibility; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.dynamic.DynamicType; import net.bytebuddy.implementation.FixedValue; +import net.bytebuddy.implementation.StubMethod; import net.bytebuddy.matcher.ElementMatchers; import static net.bytebuddy.matcher.ElementMatchers.named; @@ -46,12 +47,9 @@ public class ListenerBuilderModifier implements Processor TypeDescription typeDefinition, String newClassName) { MethodList methods = typeDefinition.getDeclaredMethods(); - if (methods.filter(ElementMatchers.named("getResponseFromRequest") - .and(ElementMatchers.takesArguments(Object.class)) - .and(ElementMatchers.returns(Object.class))) - .isEmpty()) { - throw new GenerationException("[public Object getResponseFromRequest(Object request)] method not found" + - " make sure arg and return type is Object.class"); + if (methods.filter(named("getResponseFromRequest").and(takesArguments(1))).isEmpty()) { + throw new GenerationException("please add [getResponseFromRequest(Object request)] method," + + " the method body will be auto adapted for multi server"); } else { builder = builder .visit(MethodCallReplaceVisitorWrapper.newInstance( @@ -59,13 +57,11 @@ public class ListenerBuilderModifier implements Processor .visit(Advice.to(implInterceptor).on(named("getResponseFromRequest"))); } - if (methods.filter(named("getFieldValue") - .and(takesArguments(Object.class, String.class))) - .isEmpty()) { + if (methods.filter(named("getFieldValue").and(takesArguments(Object.class, String.class))).isEmpty()) { builder = builder.defineMethod("getFieldValue", Object.class, Visibility.PUBLIC, Ownership.STATIC) .withParameters(Object.class, String.class) .throwing(Exception.class) - .intercept(FixedValue.nullValue()) + .intercept(StubMethod.INSTANCE) .visit(Advice.to(ShellCommonUtil.GetFieldValueInterceptor.class).on(named("getFieldValue"))); } return builder; diff --git a/generator/src/test/java/com/reajason/javaweb/memshell/generator/ListenerGeneratorTest.java b/generator/src/test/java/com/reajason/javaweb/memshell/generator/ListenerGeneratorTest.java index 20a56475..4972f42e 100644 --- a/generator/src/test/java/com/reajason/javaweb/memshell/generator/ListenerGeneratorTest.java +++ b/generator/src/test/java/com/reajason/javaweb/memshell/generator/ListenerGeneratorTest.java @@ -28,12 +28,6 @@ class ListenerGeneratorTest { } } - public static class J { - public HttpServletResponse getResponseFromRequest(HttpServletRequest request) { - return null; - } - } - public static class FakeRequest { public Object response = "i'm a good boy"; } @@ -44,12 +38,6 @@ class ListenerGeneratorTest { Assertions.assertThrows(GenerationException.class, () -> ListenerBuilderModifier.modifier(builder, Tomcat.ListenerInterceptor.class, TypeDescription.ForLoadedType.of(Object.class), "hello.world")); } - @Test - void testGetResponseFromRequestSignatureError() { - DynamicType.Builder builder = new ByteBuddy().redefine(J.class); - Assertions.assertThrows(GenerationException.class, () -> ListenerBuilderModifier.modifier(builder, Tomcat.ListenerInterceptor.class, TypeDescription.ForLoadedType.of(J.class), "hello.world")); - } - @Test @SneakyThrows void test() { diff --git a/memshell-party-common/src/main/java/com/reajason/javaweb/asm/ClassRenameUtils.java b/memshell-party-common/src/main/java/com/reajason/javaweb/asm/ClassRenameUtils.java index 56ff8d7a..acfcda90 100644 --- a/memshell-party-common/src/main/java/com/reajason/javaweb/asm/ClassRenameUtils.java +++ b/memshell-party-common/src/main/java/com/reajason/javaweb/asm/ClassRenameUtils.java @@ -1,5 +1,6 @@ package com.reajason.javaweb.asm; +import org.jetbrains.annotations.NotNull; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Opcodes; @@ -14,12 +15,7 @@ import org.objectweb.asm.commons.SimpleRemapper; public class ClassRenameUtils { public static byte[] renameClass(byte[] classBytes, String newName) { - ClassReader reader = null; - try { - reader = new ClassReader(classBytes); - } catch (Exception e) { - throw new RuntimeException("invalid class bytes"); - } + ClassReader reader = getClassReader(classBytes); String oldClassName = reader.getClassName(); String newClassName = newName.replace('.', '/'); ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); @@ -29,12 +25,7 @@ public class ClassRenameUtils { } public static byte[] relocateClass(byte[] classBytes, String relocateClassPackage, String relocatePrefix) { - ClassReader reader = null; - try { - reader = new ClassReader(classBytes); - } catch (Exception e) { - throw new RuntimeException("invalid class bytes"); - } + ClassReader reader = getClassReader(classBytes); String oldClassName = relocateClassPackage.replace('.', '/'); String newClassName = relocatePrefix.replace('.', '/'); ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_MAXS); @@ -51,4 +42,32 @@ public class ClassRenameUtils { reader.accept(adapter, 0); return writer.toByteArray(); } + + public static byte[] relocateJakarta(byte[] classBytes) { + ClassReader reader = getClassReader(classBytes); + ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_MAXS); + ClassRemapper adapter = new ClassRemapper(writer, new Remapper(Opcodes.ASM9) { + @Override + public String map(String typeName) { + if (typeName.startsWith("javax/servlet/") + || typeName.startsWith("javax/websocket/")) { + return typeName.replaceFirst("javax", "jakarta"); + } else { + return typeName; + } + } + }); + reader.accept(adapter, 0); + return writer.toByteArray(); + } + + private static @NotNull ClassReader getClassReader(byte[] classBytes) { + ClassReader reader = null; + try { + reader = new ClassReader(classBytes); + } catch (Exception e) { + throw new RuntimeException("invalid class bytes"); + } + return reader; + } }