aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.editorconfig24
-rw-r--r--Changes.md12
-rw-r--r--README.md2
-rw-r--r--build.xml2
-rw-r--r--javassist.jarbin794135 -> 794715 bytes
-rw-r--r--pom.xml145
-rw-r--r--src/main/javassist/CtClass.java4
-rw-r--r--src/main/javassist/CtClassType.java3
-rw-r--r--src/main/javassist/bytecode/BootstrapMethodsAttribute.java103
-rw-r--r--src/main/javassist/bytecode/CodeAttribute.java149
-rw-r--r--src/main/javassist/bytecode/MethodParametersAttribute.java9
-rw-r--r--src/main/javassist/compiler/MemberResolver.java25
-rw-r--r--src/main/javassist/convert/TransformNewClass.java3
-rw-r--r--src/main/javassist/expr/NewExpr.java15
-rw-r--r--src/test/javassist/Bench.java3
-rw-r--r--src/test/javassist/JvstTest.java3
-rw-r--r--src/test/javassist/JvstTest2.java3
-rw-r--r--src/test/javassist/JvstTest3.java3
-rw-r--r--src/test/javassist/JvstTest4.java3
-rw-r--r--src/test/javassist/JvstTest5.java60
-rw-r--r--src/test/javassist/JvstTestRoot.java4
-rw-r--r--src/test/javassist/SuperCallCase.java38
-rw-r--r--src/test/javassist/bytecode/BytecodeTest.java39
-rw-r--r--src/test/javassist/bytecode/InsertGap0.java3
-rw-r--r--src/test/resources/Java21InnerClassWithoutParameters$InnerClass.classbin0 -> 495 bytes
-rw-r--r--src/test/resources/Java21InnerClassWithoutParameters.classbin0 -> 358 bytes
-rw-r--r--src/test/test4/InvokeDynCopyDest.java11
-rw-r--r--src/test/test4/InvokeDynCopySrc.java17
-rw-r--r--tutorial/tutorial.html2
29 files changed, 538 insertions, 147 deletions
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 00000000..fcc91261
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,24 @@
+# https://editorconfig.org/
+
+root = true
+
+[*]
+charset = utf-8
+end_of_line = lf
+insert_final_newline = true
+
+tab_width = 8
+indent_size = 2
+ij_continuation_indent_size = 4
+indent_style = space
+
+trim_trailing_whitespace = true
+
+
+[*.{java,j}]
+indent_size = 4
+ij_continuation_indent_size = 8
+
+
+[*.md]
+trim_trailing_whitespace = false
diff --git a/Changes.md b/Changes.md
index b82ddd37..83c4964b 100644
--- a/Changes.md
+++ b/Changes.md
@@ -1,5 +1,17 @@
### Changes
+### version 3.30.2 on December 25, 2023
+
+* GitHub PR #473, 475, 476
+
+#### version 3.30.1 on December 17, 2023
+
+* GitHub Issue #471
+
+#### version 3.30 on December 17, 2023
+
+* GitHub PR #434, 448, 463 (Issue #462), 466, 467, 468, 469, 470,
+
#### version 3.29.2 on September 14, 2022
- GitHub Issue #427.
diff --git a/README.md b/README.md
index eb6ff330..c21f8382 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
Java bytecode engineering toolkit
### [Javassist version 3](http://www.javassist.org)
-Copyright (C) 1999-2022 by Shigeru Chiba, All rights reserved.
+Copyright (C) 1999-2023 by Shigeru Chiba, All rights reserved.
Javassist (JAVA programming ASSISTant) makes Java bytecode manipulation
simple. It is a class library for editing bytecodes in Java; it enables Java
diff --git a/build.xml b/build.xml
index df1ba25b..6fec7edf 100644
--- a/build.xml
+++ b/build.xml
@@ -6,7 +6,7 @@
<project name="javassist" default="jar" basedir=".">
- <property name="dist-version" value="javassist-3.29.2-GA"/>
+ <property name="dist-version" value="javassist-3.30.2-GA"/>
<property environment="env"/>
<property name="target.jar" value="javassist.jar"/>
diff --git a/javassist.jar b/javassist.jar
index 33370bc8..0fbf8ed5 100644
--- a/javassist.jar
+++ b/javassist.jar
Binary files differ
diff --git a/pom.xml b/pom.xml
index a604e166..d13fee29 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,40 +1,32 @@
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
+
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
+ <version>3.30.2-GA</version>
<packaging>bundle</packaging>
+ <name>Javassist</name>
<description>
- Javassist (JAVA programming ASSISTant) makes Java bytecode manipulation
- simple. It is a class library for editing bytecodes in Java.
+ Javassist (JAVA programming ASSISTant) makes Java bytecode manipulation
+ simple. It is a class library for editing bytecodes in Java.
</description>
- <version>3.29.2-GA</version>
- <name>Javassist</name>
- <url>http://www.javassist.org/</url>
+ <url>https://www.javassist.org/</url>
+ <inceptionYear>1999</inceptionYear>
- <properties>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- </properties>
- <organization>
- <name>Shigeru Chiba, www.javassist.org</name>
- </organization>
-
- <issueManagement>
- <system>JIRA</system>
- <url>https://jira.jboss.org/jira/browse/JASSIST/</url>
- </issueManagement>
<licenses>
<!-- this is the license under which javassist is usually distributed
-->
<license>
<name>MPL 1.1</name>
- <url>http://www.mozilla.org/MPL/MPL-1.1.html</url>
+ <url>https://www.mozilla.org/en-US/MPL/1.1/</url>
</license>
<!-- this is the license under which javassist is distributed when
- it is bundled with JBoss
+ it is bundled with JBoss
-->
<license>
<name>LGPL 2.1</name>
- <url>http://www.gnu.org/licenses/lgpl-2.1.html</url>
+ <url>https://www.gnu.org/licenses/lgpl-2.1.html</url>
</license>
<!-- this is the license under which javassist can be distributed.
-->
@@ -44,6 +36,13 @@
</license>
</licenses>
+ <organization>
+ <name>Shigeru Chiba, www.javassist.org</name>
+ </organization>
+ <issueManagement>
+ <system>JIRA</system>
+ <url>https://jira.jboss.org/jira/browse/JASSIST/</url>
+ </issueManagement>
<scm>
<connection>scm:git:git@github.com:jboss-javassist/javassist.git</connection>
<developerConnection>scm:git:git@github.com:jboss-javassist/javassist.git</developerConnection>
@@ -56,7 +55,7 @@
<name>Shigeru Chiba</name>
<email>chiba@javassist.org</email>
<organization>The Javassist Project</organization>
- <organizationUrl>http://www.javassist.org/</organizationUrl>
+ <organizationUrl>https://www.javassist.org/</organizationUrl>
<roles>
<role>project lead</role>
</roles>
@@ -68,7 +67,7 @@
<name>Andrew Dinn</name>
<email>adinn@redhat.com</email>
<organization>JBoss</organization>
- <organizationUrl>http://www.jboss.org/</organizationUrl>
+ <organizationUrl>https://www.jboss.org/</organizationUrl>
<roles>
<role>contributing developer</role>
</roles>
@@ -80,30 +79,28 @@
<name>Kabir Khan</name>
<email>kabir.khan@jboss.com</email>
<organization>JBoss</organization>
- <organizationUrl>http://www.jboss.org/</organizationUrl>
+ <organizationUrl>https://www.jboss.org/</organizationUrl>
<roles>
<role>contributing developer</role>
</roles>
<timezone>0</timezone>
</developer>
-
+
<developer>
<id>scottmarlow</id>
<name>Scott Marlow</name>
<email>smarlow@redhat.com</email>
<organization>JBoss</organization>
- <organizationUrl>http://www.jboss.org/</organizationUrl>
+ <organizationUrl>https://www.jboss.org/</organizationUrl>
<roles>
<role>contributing developer</role>
</roles>
<timezone>-5</timezone>
</developer>
-
-
</developers>
<distributionManagement>
- <!--
+ <!--
You need entries in your .m2/settings.xml like this:
<servers>
<server>
@@ -117,9 +114,9 @@
<password>password</password>
</server>
</servers>
-
+
To deploy a snapshot, you need to run
-
+
mvn deploy -Dversion=3.x.y-SNAPSHOT
To deploy a release you need to change the version to 3.x.y-GA and run
@@ -137,6 +134,26 @@
<url>https://repository.jboss.org/nexus/content/repositories/snapshots/</url>
</snapshotRepository>
</distributionManagement>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>[4.13.1,)</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.hamcrest</groupId>
+ <artifactId>hamcrest-all</artifactId>
+ <version>1.3</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
<build>
<sourceDirectory>src/main/</sourceDirectory>
<testSourceDirectory>src/test/</testSourceDirectory>
@@ -204,21 +221,45 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.2.0</version>
- <configuration>
- <attach>true</attach>
+ <configuration>
+ <attach>true</attach>
<excludePackageNames>javassist.compiler:javassist.convert:javassist.scopedpool:javassist.bytecode.stackmap</excludePackageNames>
<bottom><![CDATA[<i>Javassist, a Java-bytecode translator toolkit.<br>
-Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.</i>]]></bottom>
+Copyright (C) ${project.inceptionYear}- Shigeru Chiba. All Rights Reserved.</i>]]></bottom>
<show>public</show>
<nohelp>true</nohelp>
<doclint>none</doclint>
<source>8</source>
- </configuration>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-enforcer-plugin</artifactId>
+ <version>3.4.1</version>
+ <executions>
+ <execution>
+ <id>enforces</id>
+ <goals>
+ <goal>enforce</goal>
+ </goals>
+ <configuration>
+ <rules>
+ <!-- official docs: https://maven.apache.org/enforcer/enforcer-rules/index.html -->
+ <requireMavenVersion>
+ <version>3.2.5</version>
+ </requireMavenVersion>
+ <requireJavaVersion>
+ <version>11</version>
+ </requireJavaVersion>
+ </rules>
+ </configuration>
+ </execution>
+ </executions>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
- <version>3.3.0</version>
+ <version>5.1.9</version>
<executions>
<execution>
<id>bundle-manifest</id>
@@ -237,7 +278,7 @@ Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.</i>]]></bottom>
<instructions>
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
<Bundle-Version>${project.version}</Bundle-Version>
- <Import-Package>!com.sun.jdi.*</Import-Package>
+ <Import-Package>!com.sun.jdi.*</Import-Package>
<Export-Package>!com.sun.jdi.*,javassist.*;version="${project.version}"</Export-Package>
</instructions>
</configuration>
@@ -247,17 +288,17 @@ Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.</i>]]></bottom>
</build>
<profiles>
<!-- profile for releasing to sonatype repo
- exercise with mvn -PcentralRelease
+ exercise with mvn -PcentralRelease
-->
<profile>
<id>centralRelease</id>
<!-- obviously we need to use the Sonatype staging repo for upload -->
<distributionManagement>
- <repository>
- <id>sonatype-releases-repository</id>
- <name>Sonatype Releases Repository</name>
- <url>https://oss.sonatype.org/service/local/staging/deploy/maven2</url>
- </repository>
+ <repository>
+ <id>sonatype-releases-repository</id>
+ <name>Sonatype Releases Repository</name>
+ <url>https://oss.sonatype.org/service/local/staging/deploy/maven2</url>
+ </repository>
</distributionManagement>
<!-- we need to be able to sign the jars we install -->
<build>
@@ -265,6 +306,7 @@ Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.</i>]]></bottom>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
+ <version>3.1.0</version>
<configuration>
<passphrase>${gpg.passphrase}</passphrase>
<useAgent>${gpg.useAgent}</useAgent>
@@ -283,8 +325,8 @@ Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.</i>]]></bottom>
</build>
</profile>
<!-- profiles to add tools jar containing com.sun.jdi code
- needed by sample code
- -->
+ needed by sample code
+ -->
<profile>
<id>default-tools</id>
<activation>
@@ -318,19 +360,4 @@ Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.</i>]]></bottom>
</dependencies>
</profile>
</profiles>
- <dependencies>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>[4.13.1,)</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.hamcrest</groupId>
- <artifactId>hamcrest-all</artifactId>
- <version>1.3</version>
- <scope>test</scope>
- </dependency>
- </dependencies>
</project>
-
diff --git a/src/main/javassist/CtClass.java b/src/main/javassist/CtClass.java
index 24f4e25f..3b73f8ac 100644
--- a/src/main/javassist/CtClass.java
+++ b/src/main/javassist/CtClass.java
@@ -69,7 +69,7 @@ public abstract class CtClass {
/**
* The version number of this release.
*/
- public static final String version = "3.29.2-GA";
+ public static final String version = "3.30.2-GA";
private int linesCount = 0;
@@ -82,7 +82,7 @@ public abstract class CtClass {
*/
public static void main(String[] args) {
System.out.println("Javassist version " + CtClass.version);
- System.out.println("Copyright (C) 1999-2022 Shigeru Chiba."
+ System.out.println("Copyright (C) 1999-2023 Shigeru Chiba."
+ " All Rights Reserved.");
}
diff --git a/src/main/javassist/CtClassType.java b/src/main/javassist/CtClassType.java
index 22b873a6..f4345e0a 100644
--- a/src/main/javassist/CtClassType.java
+++ b/src/main/javassist/CtClassType.java
@@ -1763,8 +1763,7 @@ class CtClassType extends CtClass {
int pos = it.insertEx(initializer.get());
it.insert(initializer.getExceptionTable(), pos);
int maxstack = codeAttr.getMaxStack();
- if (maxstack < stacksize)
- codeAttr.setMaxStack(stacksize);
+ codeAttr.setMaxStack(maxstack + stacksize);
}
private int makeFieldInitializer(Bytecode code, CtClass[] parameters)
diff --git a/src/main/javassist/bytecode/BootstrapMethodsAttribute.java b/src/main/javassist/bytecode/BootstrapMethodsAttribute.java
index 94a0481f..0fd04cf8 100644
--- a/src/main/javassist/bytecode/BootstrapMethodsAttribute.java
+++ b/src/main/javassist/bytecode/BootstrapMethodsAttribute.java
@@ -2,6 +2,7 @@ package javassist.bytecode;
import java.io.DataInputStream;
import java.io.IOException;
+import java.util.Arrays;
import java.util.Map;
public class BootstrapMethodsAttribute extends AttributeInfo {
@@ -35,6 +36,26 @@ public class BootstrapMethodsAttribute extends AttributeInfo {
* <code>bootstrap_arguments</code>.
*/
public int[] arguments;
+
+ /**
+ * Makes a copy. Class names are replaced according to the
+ * * given <code>Map</code> object.
+ *
+ * @param srcCp the constant pool table from the source
+ * @param destCp the constant pool table used bt new copy
+ * @param classnames pairs of replaced and substituted class names.
+ *
+ * @return new BootstrapMethod
+ */
+ protected BootstrapMethod copy(ConstPool srcCp, ConstPool destCp, Map<String,String> classnames) {
+ int newMethodRef = srcCp.copy(methodRef, destCp, classnames);
+ int[] newArguments = new int[arguments.length];
+
+ for (int i = 0; i < arguments.length; i++)
+ newArguments[i] = srcCp.copy(arguments[i], destCp, classnames);
+
+ return new BootstrapMethod(newMethodRef, newArguments);
+ }
}
BootstrapMethodsAttribute(ConstPool cp, int n, DataInputStream in)
@@ -51,25 +72,8 @@ public class BootstrapMethodsAttribute extends AttributeInfo {
*/
public BootstrapMethodsAttribute(ConstPool cp, BootstrapMethod[] methods) {
super(cp, tag);
- int size = 2;
- for (int i = 0; i < methods.length; i++)
- size += 4 + methods[i].arguments.length * 2;
-
- byte[] data = new byte[size];
- ByteArray.write16bit(methods.length, data, 0); // num_bootstrap_methods
- int pos = 2;
- for (int i = 0; i < methods.length; i++) {
- ByteArray.write16bit(methods[i].methodRef, data, pos);
- ByteArray.write16bit(methods[i].arguments.length, data, pos + 2);
- int[] args = methods[i].arguments;
- pos += 4;
- for (int k = 0; k < args.length; k++) {
- ByteArray.write16bit(args[k], data, pos);
- pos += 2;
- }
- }
- set(data);
+ set(convertMethodsToBytes(methods));
}
/**
@@ -113,12 +117,67 @@ public class BootstrapMethodsAttribute extends AttributeInfo {
BootstrapMethod[] methods = getMethods();
ConstPool thisCp = getConstPool();
for (int i = 0; i < methods.length; i++) {
- BootstrapMethod m = methods[i];
- m.methodRef = thisCp.copy(m.methodRef, newCp, classnames);
- for (int k = 0; k < m.arguments.length; k++)
- m.arguments[k] = thisCp.copy(m.arguments[k], newCp, classnames);
+ methods[i] = methods[i].copy(thisCp, newCp, classnames);
}
return new BootstrapMethodsAttribute(newCp, methods);
}
+
+ /**
+ * add bootstrap method from given <code>ConstPool</code> and <code>BootstrapMethod</code>,
+ * and add it to the specified index. Class names are replaced according to the
+ * given <code>Map</code> object.
+ *
+ * <p>
+ * if the index less than 0 or large than the origin method length, then throw <code>RuntimeException</code>;<br>
+ * if the index large or equals to 0 and less or equals to the origin method length,
+ * then replace the origin method with the new <code>BootstrapMethod srcBm</code> ;<br>
+ * if the index equals to the origin method length, then append the new <code>BootstrapMethod srcBm</code> at
+ * the origin methods tail.
+ * </p>
+ *
+ * @param srcCp the constant pool table of source.
+ * @param srcBm the bootstrap method of source
+ * @param index the new method index on bootstrap methods
+ * @param classnames pairs of replaced and substituted
+ * class names.
+ */
+ public void addMethod(ConstPool srcCp, BootstrapMethod srcBm, int index, Map<String,String> classnames) {
+ BootstrapMethod[] methods = getMethods();
+
+ if (index < 0 || index > methods.length) {
+ throw new RuntimeException("index out of range");
+ }
+
+ if (index == methods.length) {
+ BootstrapMethod[] newBmArray = new BootstrapMethod[methods.length + 1];
+ System.arraycopy(methods, 0, newBmArray, 0, methods.length);
+ methods = newBmArray;
+ }
+
+ methods[index] = srcBm.copy(srcCp, getConstPool(), classnames);
+ set(convertMethodsToBytes(methods));
+ }
+
+ private static byte[] convertMethodsToBytes(BootstrapMethod[] methods) {
+ int size = 2;
+ for (int i = 0; i < methods.length; i++)
+ size += 4 + methods[i].arguments.length * 2;
+
+ byte[] data = new byte[size];
+ ByteArray.write16bit(methods.length, data, 0); // num_bootstrap_methods
+ int pos = 2;
+ for (int i = 0; i < methods.length; i++) {
+ ByteArray.write16bit(methods[i].methodRef, data, pos);
+ ByteArray.write16bit(methods[i].arguments.length, data, pos + 2);
+ int[] args = methods[i].arguments;
+ pos += 4;
+ for (int k = 0; k < args.length; k++) {
+ ByteArray.write16bit(args[k], data, pos);
+ pos += 2;
+ }
+ }
+
+ return data;
+ }
}
diff --git a/src/main/javassist/bytecode/CodeAttribute.java b/src/main/javassist/bytecode/CodeAttribute.java
index 98479b21..cf8806ef 100644
--- a/src/main/javassist/bytecode/CodeAttribute.java
+++ b/src/main/javassist/bytecode/CodeAttribute.java
@@ -16,6 +16,8 @@
package javassist.bytecode;
+import javassist.*;
+
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
@@ -76,8 +78,7 @@ public class CodeAttribute extends AttributeInfo implements Opcode {
* class names.
*/
private CodeAttribute(ConstPool cp, CodeAttribute src, Map<String,String> classnames)
- throws BadBytecode
- {
+ throws BadBytecode, NotFoundException, CannotCompileException {
super(cp, tag);
maxStack = src.getMaxStack();
@@ -139,6 +140,10 @@ public class CodeAttribute extends AttributeInfo implements Opcode {
}
catch (BadBytecode e) {
throw new RuntimeCopyException("bad bytecode. fatal?");
+ } catch (NotFoundException e) {
+ throw new RuntimeException(e);
+ } catch (CannotCompileException e) {
+ throw new RuntimeException(e);
}
}
@@ -324,7 +329,7 @@ public class CodeAttribute extends AttributeInfo implements Opcode {
*
* @param smt the stack map table added to this code attribute.
* If it is null, a new stack map is not added.
- * Only the old stack map is removed.
+ * Only the old stack map is removed.
*/
public void setAttribute(StackMapTable smt) {
AttributeInfo.remove(attributes, StackMapTable.tag);
@@ -366,11 +371,11 @@ public class CodeAttribute extends AttributeInfo implements Opcode {
*/
private byte[] copyCode(ConstPool destCp, Map<String,String> classnames,
ExceptionTable etable, CodeAttribute destCa)
- throws BadBytecode
- {
+ throws BadBytecode, NotFoundException, CannotCompileException {
int len = getCodeLength();
byte[] newCode = new byte[len];
destCa.info = newCode;
+
LdcEntry ldc = copyCode(this.info, 0, len, this.getConstPool(),
newCode, destCp, classnames);
return LdcEntry.doit(newCode, ldc, etable, destCa);
@@ -378,9 +383,8 @@ public class CodeAttribute extends AttributeInfo implements Opcode {
private static LdcEntry copyCode(byte[] code, int beginPos, int endPos,
ConstPool srcCp, byte[] newcode,
- ConstPool destCp, Map<String,String> classnameMap)
- throws BadBytecode
- {
+ ConstPool destCp, Map<String,String> classnameMap)
+ throws BadBytecode, NotFoundException, CannotCompileException {
int i2, index;
LdcEntry ldcEntry = null;
@@ -429,6 +433,7 @@ public class CodeAttribute extends AttributeInfo implements Opcode {
case INVOKEDYNAMIC :
copyConstPoolInfo(i + 1, code, srcCp, newcode, destCp,
classnameMap);
+ copyBootstrapMethod(srcCp, destCp, i + 1, code, newcode, classnameMap);
newcode[i + 3] = 0;
newcode[i + 4] = 0;
break;
@@ -448,6 +453,134 @@ public class CodeAttribute extends AttributeInfo implements Opcode {
return ldcEntry;
}
+ /**
+ * Copy the Bootstrap method of the specified index referenced in the source <code>InvokeDynamic</code> directive
+ * to the specified index in the destination Boostrap Attribute.<br>
+ * if the Bootstrap Attribute does not exist in the destination class, create a new Bootstrap Attribute; <br>
+ * if the destination Bootstrap Method already exists at the specified index method,
+ * the method at that position will be overwritten, otherwise it will be added
+ * at the end of the destination Bootstrap method.
+ *
+ * @param srcCp the constant pool table of source
+ * @param destCp the constant pool table of destination
+ * @param codeIndex the index of the invoke dynamic first parameter in code array
+ * @param srcCode the code array of source
+ * @param newCode the code array of destination
+ * @param classnameMap pairs of replaced and substituted class names.
+ *
+ * @throws NotFoundException this exception thrown when the class
+ * cannot be found in the default <code>ClassPool</code>
+ * @throws CannotCompileException this exception thrown from the method
+ * {@link #copyInvokeStaticMethod(CtClass, ConstPool,
+ * BootstrapMethodsAttribute.BootstrapMethod, CtClass, Map)}
+ */
+ private static void copyBootstrapMethod(ConstPool srcCp, ConstPool destCp, int codeIndex, byte[] srcCode,
+ byte[] newCode, Map<String,String> classnameMap)
+ throws NotFoundException, CannotCompileException {
+ ClassPool classPool = ClassPool.getDefault();
+ CtClass srcCc = classPool.get(srcCp.getClassName());
+ CtClass destCc = classPool.get(destCp.getClassName());
+ ClassFile srcCf = srcCc.getClassFile();
+ ClassFile destCf = destCc.getClassFile();
+ BootstrapMethodsAttribute srcBma = (BootstrapMethodsAttribute)
+ srcCf.getAttribute(BootstrapMethodsAttribute.tag);
+
+ // if source class does not have bootstrap attribute then stop copy
+ if (srcBma == null) {
+ return;
+ }
+
+ BootstrapMethodsAttribute destBma = (BootstrapMethodsAttribute)
+ destCf.getAttribute(BootstrapMethodsAttribute.tag);
+
+ int srcCpIndex = ((srcCode[codeIndex] & 0xff) << 8) | (srcCode[codeIndex + 1] & 0xff);
+ int destCpIndex = ((newCode[codeIndex] & 0xff) << 8) | (newCode[codeIndex + 1] & 0xff);
+ int srcBmIndex = srcCp.getInvokeDynamicBootstrap(srcCpIndex);
+ int destBmIndex = destCp.getInvokeDynamicBootstrap(destCpIndex);
+
+ // if source class does not have bootstrap attribute, then create bootstrap attribute
+ if (destBma == null) {
+ destBma = new BootstrapMethodsAttribute(destCp,
+ new BootstrapMethodsAttribute.BootstrapMethod[0]);
+ destCf.addAttribute(destBma);
+ }
+
+ BootstrapMethodsAttribute.BootstrapMethod srcBm = srcBma.getMethods()[srcBmIndex];
+ destBma.addMethod(srcCp, srcBm, destBmIndex, classnameMap);
+
+ copyInvokeStaticMethod(srcCc, srcCp, srcBm, destCc, classnameMap);
+ }
+
+ /**
+ * Copy the static methods referenced by the bootstrap method in this class (such as some lambda methods).<br>
+ * If the source method exists in the destination class, it will be ignored.
+ *
+ * @param srcCc source class
+ * @param srcCp constant pool table of source class
+ * @param srcBm source method to be copied
+ * @param destCc destination class
+ * @param classnameMap irs of replaced and substituted class names.
+ *
+ * @throws CannotCompileException thrown by {@link CtNewMethod#copy(CtMethod, CtClass, ClassMap)}
+ * or{@link CtClass#addMethod(CtMethod)}
+ */
+ private static void copyInvokeStaticMethod(CtClass srcCc, ConstPool srcCp,
+ BootstrapMethodsAttribute.BootstrapMethod srcBm, CtClass destCc,
+ Map<String, String> classnameMap) throws CannotCompileException {
+ for (int argument : srcBm.arguments) {
+ ConstInfo constInfo = srcCp.getItem(argument);
+
+ if (!(constInfo instanceof MethodHandleInfo)) continue;
+
+ MethodHandleInfo methodHandleInfo = (MethodHandleInfo) constInfo;
+ if (ConstPool.REF_invokeStatic != methodHandleInfo.refKind) continue;
+
+ String methodRefClassName = srcCp.getMethodrefClassName(methodHandleInfo.refIndex);
+ if (methodRefClassName == null || !methodRefClassName.equals(srcCc.getName())) continue;
+
+ String staticMethodName = srcCp.getMethodrefName(methodHandleInfo.refIndex);
+ String staticMethodSignature = srcCp.getMethodrefType(methodHandleInfo.refIndex);
+ CtMethod srcMethod = getStaticCtMethod(srcCc, staticMethodName, staticMethodSignature);
+
+ if (!checkStaticMethodExisted(destCc, staticMethodName, staticMethodSignature)) {
+ ClassMap classMap = new ClassMap();
+ classMap.putAll(classnameMap);
+
+ CtMethod ctMethod = CtNewMethod.copy(srcMethod, destCc, classMap);
+ destCc.addMethod(ctMethod);
+ }
+ }
+ }
+
+ private static CtMethod getStaticCtMethod(CtClass ctClass, String staticMethodName, String staticMethodSignature) {
+ CtMethod srcMethod = null;
+ for (CtMethod declaredMethod : ctClass.getDeclaredMethods()) {
+ if (Modifier.isStatic(declaredMethod.getModifiers())
+ && declaredMethod.getName().equals(staticMethodName)
+ && declaredMethod.getSignature().equals(staticMethodSignature)) {
+ srcMethod = declaredMethod;
+ break;
+ }
+ }
+
+ if (srcMethod == null) {
+ throw new RuntimeException("Can not found static method:" + staticMethodName);
+ }
+ return srcMethod;
+ }
+
+ private static boolean checkStaticMethodExisted(CtClass ctClass, String staticMethodName, String staticMethodSignature) {
+ for (CtMethod declaredMethod : ctClass.getDeclaredMethods()) {
+ if (Modifier.isStatic(declaredMethod.getModifiers())
+ && declaredMethod.getName().equals(staticMethodName)
+ && declaredMethod.getSignature().equals(staticMethodSignature)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
private static void copyConstPoolInfo(int i, byte[] code, ConstPool srcCp,
byte[] newcode, ConstPool destCp,
Map<String,String> classnameMap) {
diff --git a/src/main/javassist/bytecode/MethodParametersAttribute.java b/src/main/javassist/bytecode/MethodParametersAttribute.java
index b9c252a9..f78f6c72 100644
--- a/src/main/javassist/bytecode/MethodParametersAttribute.java
+++ b/src/main/javassist/bytecode/MethodParametersAttribute.java
@@ -32,7 +32,8 @@ public class MethodParametersAttribute extends AttributeInfo {
byte[] data = new byte[names.length * 4 + 1];
data[0] = (byte)names.length;
for (int i = 0; i < names.length; i++) {
- ByteArray.write16bit(cp.addUtf8Info(names[i]), data, i * 4 + 1);
+ String name = names[i];
+ ByteArray.write16bit(name == null ? 0 : cp.addUtf8Info(name), data, i * 4 + 1);
ByteArray.write16bit(flags[i], data, i * 4 + 3);
}
@@ -61,7 +62,8 @@ public class MethodParametersAttribute extends AttributeInfo {
* @param i the position of the parameter.
*/
public String parameterName(int i) {
- return getConstPool().getUtf8Info(name(i));
+ int index = name(i);
+ return index == 0 ? null : getConstPool().getUtf8Info(index);
}
/**
@@ -87,7 +89,8 @@ public class MethodParametersAttribute extends AttributeInfo {
String[] names = new String[s];
int[] flags = new int[s];
for (int i = 0; i < s; i++) {
- names[i] = cp.getUtf8Info(name(i));
+ int index = name(i);
+ names[i] = index == 0 ? null : cp.getUtf8Info(index);
flags[i] = accessFlags(i);
}
diff --git a/src/main/javassist/compiler/MemberResolver.java b/src/main/javassist/compiler/MemberResolver.java
index 2ccb0ff7..3b0cc012 100644
--- a/src/main/javassist/compiler/MemberResolver.java
+++ b/src/main/javassist/compiler/MemberResolver.java
@@ -130,9 +130,7 @@ public class MemberResolver implements TokenId {
if (onlyExact)
maybe = null;
- else
- if (maybe != null)
- return maybe;
+ //else maybe super class has more precise match
int mod = clazz.getModifiers();
boolean isIntf = Modifier.isInterface(mod);
@@ -143,8 +141,11 @@ public class MemberResolver implements TokenId {
if (pclazz != null) {
Method r = lookupMethod(pclazz, methodName, argTypes,
argDims, argClassNames, onlyExact);
- if (r != null)
- return r;
+ if (r != null) {
+ if (maybe == null || maybe.notmatch > r.notmatch) {
+ maybe = r;
+ }
+ }
}
}
}
@@ -156,8 +157,11 @@ public class MemberResolver implements TokenId {
Method r = lookupMethod(intf, methodName,
argTypes, argDims, argClassNames,
onlyExact);
- if (r != null)
- return r;
+ if (r != null) {
+ if (maybe == null || maybe.notmatch > r.notmatch) {
+ maybe = r;
+ }
+ }
}
if (isIntf) {
@@ -166,8 +170,11 @@ public class MemberResolver implements TokenId {
if (pclazz != null) {
Method r = lookupMethod(pclazz, methodName, argTypes,
argDims, argClassNames, onlyExact);
- if (r != null)
- return r;
+ if (r != null) {
+ if (maybe == null || maybe.notmatch > r.notmatch) {
+ maybe = r;
+ }
+ }
}
}
}
diff --git a/src/main/javassist/convert/TransformNewClass.java b/src/main/javassist/convert/TransformNewClass.java
index 83f2a0cc..56738a10 100644
--- a/src/main/javassist/convert/TransformNewClass.java
+++ b/src/main/javassist/convert/TransformNewClass.java
@@ -56,9 +56,6 @@ final public class TransformNewClass extends Transformer {
if (c == NEW) {
index = iterator.u16bitAt(pos + 1);
if (cp.getClassInfo(index).equals(classname)) {
- if (iterator.byteAt(pos + 3) != DUP)
- throw new CannotCompileException(
- "NEW followed by no DUP was found");
if (newClassIndex == 0)
newClassIndex = cp.addClassInfo(newClassName);
diff --git a/src/main/javassist/expr/NewExpr.java b/src/main/javassist/expr/NewExpr.java
index 863f4db5..e45a4c54 100644
--- a/src/main/javassist/expr/NewExpr.java
+++ b/src/main/javassist/expr/NewExpr.java
@@ -193,6 +193,14 @@ public class NewExpr extends Expr {
*/
int codeSize = canReplace();
int end = pos + codeSize;
+ //check isStoreBeforeInit ,such as : new xx/xx ; dup;[astoreN];invokespecial xx/xx;
+ int beforeStoreOp = 0;
+ int preOp = iterator.byteAt(currentPos - 1);
+ if (iterator.byteAt(newPos + 3) == Opcode.DUP
+ && (preOp >= Opcode.ASTORE_0
+ && preOp <= Opcode.ASTORE_3) && currentPos - newPos == 5) {
+ beforeStoreOp = preOp;
+ }
for (int i = pos; i < end; ++i)
iterator.writeByte(NOP, i);
@@ -230,7 +238,12 @@ public class NewExpr extends Expr {
if (codeSize > 3) // if the original code includes DUP.
bytecode.addAload(retVar);
- replace0(pos, bytecode, bytecodeSize);
+ if (beforeStoreOp >= Opcode.ASTORE_0) {
+ bytecode.addOpcode(beforeStoreOp);
+ replace0(pos - 1, bytecode, bytecodeSize + 1);
+ } else {
+ replace0(pos, bytecode, bytecodeSize);
+ }
}
catch (CompileError e) { throw new CannotCompileException(e); }
catch (NotFoundException e) { throw new CannotCompileException(e); }
diff --git a/src/test/javassist/Bench.java b/src/test/javassist/Bench.java
index b7b8b27e..1892b383 100644
--- a/src/test/javassist/Bench.java
+++ b/src/test/javassist/Bench.java
@@ -5,9 +5,6 @@ import javassist.expr.*;
import javassist.compiler.*;
public class Bench extends JvstTestRoot {
- public Bench(String name) {
- super(name);
- }
public void testProceed() throws Exception {
CtClass cc = sloader.get("test.BenchProceed");
diff --git a/src/test/javassist/JvstTest.java b/src/test/javassist/JvstTest.java
index 3ed16827..ecbf91f7 100644
--- a/src/test/javassist/JvstTest.java
+++ b/src/test/javassist/JvstTest.java
@@ -20,9 +20,6 @@ public class JvstTest extends JvstTestRoot {
java9 = javassist.bytecode.ClassFile.MAJOR_VERSION
>= javassist.bytecode.ClassFile.JAVA_9;
}
- public JvstTest(String name) {
- super(name);
- }
public void testConfig() {
// is the value of PATH correct?
diff --git a/src/test/javassist/JvstTest2.java b/src/test/javassist/JvstTest2.java
index 5d01961d..334282d5 100644
--- a/src/test/javassist/JvstTest2.java
+++ b/src/test/javassist/JvstTest2.java
@@ -14,9 +14,6 @@ import test2.DefineClassCapability;
@SuppressWarnings({"rawtypes","unused"})
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class JvstTest2 extends JvstTestRoot {
- public JvstTest2(String name) {
- super(name);
- }
public void testInsertAt() throws Exception {
CtClass cc = sloader.get("test2.InsertAt");
diff --git a/src/test/javassist/JvstTest3.java b/src/test/javassist/JvstTest3.java
index c065170c..2f9ffcd5 100644
--- a/src/test/javassist/JvstTest3.java
+++ b/src/test/javassist/JvstTest3.java
@@ -7,9 +7,6 @@ import test3.*;
@SuppressWarnings({"rawtypes","unchecked","unused"})
public class JvstTest3 extends JvstTestRoot {
- public JvstTest3(String name) {
- super(name);
- }
public void testAnnotation() throws Exception {
CtClass cc = sloader.get("test3.AnnoTest");
diff --git a/src/test/javassist/JvstTest4.java b/src/test/javassist/JvstTest4.java
index 259451b9..e00c332a 100644
--- a/src/test/javassist/JvstTest4.java
+++ b/src/test/javassist/JvstTest4.java
@@ -16,9 +16,6 @@ import javassist.expr.*;
@SuppressWarnings({"rawtypes","unchecked","unused"})
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class JvstTest4 extends JvstTestRoot {
- public JvstTest4(String name) {
- super(name);
- }
public void testInsertLocalVars() throws Exception {
CtClass cc = sloader.get("test4.LocalVars");
diff --git a/src/test/javassist/JvstTest5.java b/src/test/javassist/JvstTest5.java
index 4a370632..dce27ab1 100644
--- a/src/test/javassist/JvstTest5.java
+++ b/src/test/javassist/JvstTest5.java
@@ -1,6 +1,10 @@
package javassist;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
import java.lang.reflect.TypeVariable;
import javassist.bytecode.AccessFlag;
@@ -9,6 +13,8 @@ import javassist.bytecode.AttributeInfo;
import javassist.bytecode.ClassFile;
import javassist.bytecode.ConstPool;
import javassist.bytecode.InnerClassesAttribute;
+import javassist.bytecode.MethodInfo;
+import javassist.bytecode.MethodParametersAttribute;
import javassist.bytecode.NestHostAttribute;
import javassist.bytecode.NestMembersAttribute;
import javassist.expr.ExprEditor;
@@ -19,9 +25,6 @@ import junit.framework.Assert;
@SuppressWarnings({"rawtypes","unchecked","unused"})
public class JvstTest5 extends JvstTestRoot {
- public JvstTest5(String name) {
- super(name);
- }
public void testDollarClassInStaticMethod() throws Exception {
CtClass cc = sloader.makeClass("test5.DollarClass");
@@ -161,7 +164,7 @@ public class JvstTest5 extends JvstTestRoot {
CtClass cc = sloader.makeClass("test5.JIRA256");
ClassFile ccFile = cc.getClassFile();
ConstPool constpool = ccFile.getConstPool();
-
+
AnnotationsAttribute attr = new AnnotationsAttribute(constpool, AnnotationsAttribute.visibleTag);
javassist.bytecode.annotation.Annotation entityAnno
= new javassist.bytecode.annotation.Annotation("test5.Entity", constpool);
@@ -176,7 +179,7 @@ public class JvstTest5 extends JvstTestRoot {
assertTrue(o.getClass().getName().equals("test5.JIRA256"));
java.lang.annotation.Annotation[] annotations = o.getClass().getDeclaredAnnotations();
- assertEquals(1, annotations.length);
+ assertEquals(1, annotations.length);
}
public void testJIRA250() throws Exception {
@@ -593,4 +596,51 @@ public class JvstTest5 extends JvstTestRoot {
}
catch (CannotCompileException e) {}
}
+
+ public void testGithubIssue462Java21WithoutParameters() throws IOException {
+
+ //This is a class file compiled by Java-21
+ //javac Java21InnerClassWithoutParameters.java
+ //public class Java21InnerClassWithoutParameters {
+ // class InnerClass implements Runnable {
+ // public void run() {
+ // }
+ // }
+ //}
+ String classFileName = "./Java21InnerClassWithoutParameters$InnerClass.class";
+ ClassLoader classLoader = getClass().getClassLoader();
+ File classFile = new File(classLoader.getResource(classFileName).getFile());
+
+ CtClass cc = sloader.makeClass(new FileInputStream(classFile));
+ cc.getClassFile().compact();
+
+ ClassFile cf = cc.getClassFile2();
+ ConstPool cp = cf.getConstPool();
+
+ MethodInfo minfo = cf.getMethod("<init>");
+ MethodParametersAttribute attr
+ = (MethodParametersAttribute)minfo.getAttribute(MethodParametersAttribute.tag);
+ assertEquals(1, attr.size());
+ assertNull(attr.parameterName(0));
+ }
+
+ public void testSuperCall() throws Exception {
+ String javacResult = new BearKeeper().javacResult();
+ assertEquals("Man feed(Bear)", javacResult);
+
+ CtClass cc = sloader.get("javassist.BearKeeper");
+ CtMethod cm = CtMethod.make(
+ "public String javassistResult() {return super.feed(new javassist.Bear());}",
+ cc);
+ cc.addMethod(cm);
+ cc.setModifiers(Modifier.PUBLIC);
+ cc.writeFile();
+ Object obj = make(cc.getName());
+ Method m = obj.getClass().getMethod("javassistResult");
+ Object javassistResult = m.invoke(obj);
+
+ //before this fix
+ //expected:<Man feed(Bear)> but was:<Keeper feed(Animal)>
+ assertEquals(javacResult, javassistResult);
+ }
}
diff --git a/src/test/javassist/JvstTestRoot.java b/src/test/javassist/JvstTestRoot.java
index 69f4a6ae..923af666 100644
--- a/src/test/javassist/JvstTestRoot.java
+++ b/src/test/javassist/JvstTestRoot.java
@@ -13,10 +13,6 @@ public class JvstTestRoot extends TestCase {
ClassPool sloader, dloader;
Loader cloader;
- public JvstTestRoot(String name) {
- super(name);
- }
-
protected void print(String msg) {
System.out.println(msg);
}
diff --git a/src/test/javassist/SuperCallCase.java b/src/test/javassist/SuperCallCase.java
new file mode 100644
index 00000000..8d5ea9e7
--- /dev/null
+++ b/src/test/javassist/SuperCallCase.java
@@ -0,0 +1,38 @@
+package javassist;
+
+class Animal {
+}
+
+class Bear extends Animal {
+}
+
+
+/**
+ * Base class has a method with precise type.
+ */
+class Man {
+ String feed(Bear bear) {
+ return "Man feed(Bear)";
+ }
+}
+
+/**
+ * Derived class has a method which has same name with base class's and more imprecise type.
+ */
+class Keeper extends Man {
+ String feed(Animal animal) {
+ return "Keeper feed(Animal)";
+ }
+}
+
+/**
+ * Derived class has a method which call super method with precise type.
+ */
+class BearKeeper extends Keeper {
+ public BearKeeper() {
+ }
+
+ String javacResult() {
+ return super.feed(new Bear());
+ }
+}
diff --git a/src/test/javassist/bytecode/BytecodeTest.java b/src/test/javassist/bytecode/BytecodeTest.java
index eac420bc..68e3b2c2 100644
--- a/src/test/javassist/bytecode/BytecodeTest.java
+++ b/src/test/javassist/bytecode/BytecodeTest.java
@@ -6,6 +6,7 @@ import junit.framework.*;
import javassist.*;
import javassist.bytecode.annotation.*;
import javassist.bytecode.SignatureAttribute.*;
+import test4.InvokeDynCopyDest;
@SuppressWarnings("unused")
public class BytecodeTest extends TestCase {
@@ -461,19 +462,19 @@ public class BytecodeTest extends TestCase {
public void testSignatureChange() throws Exception {
changeMsig("<S:Ljava/lang/Object;>(TS;[TS;)Ljava/lang/Object", "java/lang/Object",
- "<S:Ljava/lang/Objec;>(TS;[TS;)Ljava/lang/Object", "java/lang/Objec");
+ "<S:Ljava/lang/Objec;>(TS;[TS;)Ljava/lang/Object", "java/lang/Objec");
changeMsig("<S:Ljava/lang/Object;>(TS;[TS;)TT;", "java/lang/Object",
- "<S:Ljava/lang/Objec;>(TS;[TS;)TT;", "java/lang/Objec");
+ "<S:Ljava/lang/Objec;>(TS;[TS;)TT;", "java/lang/Objec");
changeMsig("<S:Ljava/lang/Object;>(TS;[TS;)Ljava/lang/Object2;", "java/lang/Object",
- "<S:Ljava/lang/Objec;>(TS;[TS;)Ljava/lang/Object2;", "java/lang/Objec");
+ "<S:Ljava/lang/Objec;>(TS;[TS;)Ljava/lang/Object2;", "java/lang/Objec");
changeMsig("<S:Ljava/lang/Object;>(TS;[TS;)Ljava/lang/Objec;", "java/lang/Object",
- "<S:Ljava/lang/Object2;>(TS;[TS;)Ljava/lang/Objec;", "java/lang/Object2");
+ "<S:Ljava/lang/Object2;>(TS;[TS;)Ljava/lang/Objec;", "java/lang/Object2");
changeMsig2("<S:Ljava/lang/Object;>(TS;[TS;)TT;", "java/lang/Object",
- "<S:Ljava/lang/Objec;>(TS;[TS;)TT;", "java/lang/Objec");
+ "<S:Ljava/lang/Objec;>(TS;[TS;)TT;", "java/lang/Objec");
changeMsig2("<S:Ljava/lang/Object;>(TS;[TS;)Ljava/lang/Object2;", "java/lang/Object",
- "<S:Ljava/lang/Objec;>(TS;[TS;)Ljava/lang/Object2;", "java/lang/Objec");
+ "<S:Ljava/lang/Objec;>(TS;[TS;)Ljava/lang/Object2;", "java/lang/Objec");
changeMsig2("<S:Ljava/lang/Object;>(TS;[TS;)Ljava/lang/Objec;", "java/lang/Object",
- "<S:Ljava/lang/Object2;>(TS;[TS;)Ljava/lang/Objec;", "java/lang/Object2");
+ "<S:Ljava/lang/Object2;>(TS;[TS;)Ljava/lang/Objec;", "java/lang/Object2");
String sig = "<T:Ljava/lang/Exception;>LPoi$Foo<Ljava/lang/String;>;LBar;LBar2;";
String res = "<T:Ljava/lang/Exception;>LPoi$Foo<Ljava/lang/String2;>;LBar;LBar2;";
changeMsig(sig, "java/lang/String", res, "java/lang/String2");
@@ -683,7 +684,7 @@ public class BytecodeTest extends TestCase {
assertFalse(fi1.equals(fi3));
assertFalse(fi1.equals(ci1));
assertFalse(fi1.equals(null));
-
+
LongInfo li1 = new LongInfo(12345L, n++);
LongInfo li2 = new LongInfo(12345L, n++);
LongInfo li3 = new LongInfo(-12345L, n++);
@@ -834,6 +835,28 @@ public class BytecodeTest extends TestCase {
assertEquals("(I)V", cPool2.getUtf8Info(cPool2.getMethodTypeInfo(mtIndex)));
}
+ public void testInvokeDynamicWithCopy() throws Exception {
+ CtClass srcCc = loader.get("test4.InvokeDynCopySrc");
+ CtClass destCc = loader.get("test4.InvokeDynCopyDest");
+
+ // copy source constructor to dest
+ for (CtConstructor constructor : destCc.getConstructors()) {
+ for (CtConstructor srcClassConstructor : srcCc.getConstructors()) {
+ if (constructor.getSignature().equalsIgnoreCase(srcClassConstructor.getSignature())) {
+ constructor.setBody(srcClassConstructor, null);
+ }
+ }
+ }
+
+ // set dest class method body by source class
+ destCc.getDeclaredMethod("getString").setBody(srcCc.getDeclaredMethod("getString"), new ClassMap());
+
+ Object destObj = (new Loader(loader)).loadClass(destCc.getName()).getConstructor().newInstance();
+
+ // if don't copy bootstrap method and static lambda method it will throw exception when invoke
+ assertEquals("hello", destObj.getClass().getMethod("getString").invoke(destObj));
+ }
+
public static Test suite() {
TestSuite suite = new TestSuite("Bytecode Tests");
suite.addTestSuite(BytecodeTest.class);
diff --git a/src/test/javassist/bytecode/InsertGap0.java b/src/test/javassist/bytecode/InsertGap0.java
index 425f12d7..9e94e593 100644
--- a/src/test/javassist/bytecode/InsertGap0.java
+++ b/src/test/javassist/bytecode/InsertGap0.java
@@ -159,9 +159,6 @@ final class Gap0Example2 {
@SuppressWarnings({"rawtypes","unchecked","unused"})
public final class InsertGap0 extends JvstTestRoot {
- public InsertGap0(String name) {
- super(name);
- }
public void testExample() throws Throwable {
ClassPool pool = ClassPool.getDefault();
diff --git a/src/test/resources/Java21InnerClassWithoutParameters$InnerClass.class b/src/test/resources/Java21InnerClassWithoutParameters$InnerClass.class
new file mode 100644
index 00000000..c1c6cab5
--- /dev/null
+++ b/src/test/resources/Java21InnerClassWithoutParameters$InnerClass.class
Binary files differ
diff --git a/src/test/resources/Java21InnerClassWithoutParameters.class b/src/test/resources/Java21InnerClassWithoutParameters.class
new file mode 100644
index 00000000..a6208c52
--- /dev/null
+++ b/src/test/resources/Java21InnerClassWithoutParameters.class
Binary files differ
diff --git a/src/test/test4/InvokeDynCopyDest.java b/src/test/test4/InvokeDynCopyDest.java
new file mode 100644
index 00000000..003c7c53
--- /dev/null
+++ b/src/test/test4/InvokeDynCopyDest.java
@@ -0,0 +1,11 @@
+package test4;
+
+public class InvokeDynCopyDest {
+ public InvokeDynCopyDest() {
+ System.out.println("my output:" + getString());
+ }
+
+ public String getString() {
+ return "dest";
+ }
+}
diff --git a/src/test/test4/InvokeDynCopySrc.java b/src/test/test4/InvokeDynCopySrc.java
new file mode 100644
index 00000000..83291f7b
--- /dev/null
+++ b/src/test/test4/InvokeDynCopySrc.java
@@ -0,0 +1,17 @@
+package test4;
+
+import java.util.function.Supplier;
+
+public class InvokeDynCopySrc {
+ public InvokeDynCopySrc() {
+ System.out.println("source class:" + getString());
+ }
+
+ public String getString() {
+ Supplier<String> stringSupplier = () -> {
+ return "hello";
+ };
+
+ return stringSupplier.get();
+ }
+}
diff --git a/tutorial/tutorial.html b/tutorial/tutorial.html
index b8110390..27571da5 100644
--- a/tutorial/tutorial.html
+++ b/tutorial/tutorial.html
@@ -1092,7 +1092,7 @@ They have the same set of methods and fields.
<p>Javassist provides a convenient class for reloading a class at runtime.
For more information, see the API documentation of
-<code>javassist.tools.HotSwapper</code>.
+<code>javassist.util.HotSwapper</code>.
<p><br>