From 0055c551d7310af19e28782aa69a657f5b2e3364 Mon Sep 17 00:00:00 2001 From: 1luik <8632787+n1luik@user.noreply.gitee.com> Date: Tue, 16 Dec 2025 23:44:55 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E4=BF=AE=E5=A4=8D#3103?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../taobao/arthas/compiler/GetZipFile.java | 113 ++++++++++++++++++ .../compiler/PackageInternalsFinder.java | 82 +++++++++---- 2 files changed, 174 insertions(+), 21 deletions(-) create mode 100644 memorycompiler/src/main/java/com/taobao/arthas/compiler/GetZipFile.java diff --git a/memorycompiler/src/main/java/com/taobao/arthas/compiler/GetZipFile.java b/memorycompiler/src/main/java/com/taobao/arthas/compiler/GetZipFile.java new file mode 100644 index 00000000000..1a052614759 --- /dev/null +++ b/memorycompiler/src/main/java/com/taobao/arthas/compiler/GetZipFile.java @@ -0,0 +1,113 @@ +package com.taobao.arthas.compiler; + +import javax.lang.model.element.Modifier; +import javax.lang.model.element.NestingKind; +import javax.tools.JavaFileObject; +import java.io.*; +import java.net.URI; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; +import java.util.stream.Stream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipException; +import java.util.zip.ZipFile; + +public class GetZipFile extends ZipFile { + + public GetZipFile(String name) throws IOException { + super(name); + } + + public GetZipFile(File file, int mode) throws IOException { + super(file, mode); + } + + public GetZipFile(File file) throws ZipException, IOException { + super(file); + } + + public Stream stream() { + Enumeration entries = super.entries(); + List entryList = new ArrayList<>(); + while (entries.hasMoreElements()) { + entryList.add(entries.nextElement()); + } + return entryList.stream(); + } + + public class ZipJavaFileObject implements JavaFileObject { + private final String className; + private final URI uri; + private final ZipEntry file; + + public ZipJavaFileObject(String className, URI uri, ZipEntry file) { + this.uri = uri; + this.className = className; + this.file = file; + } + + public URI toUri() { + return uri; + } + + public InputStream openInputStream() throws IOException { + return GetZipFile.this.getInputStream(file); + } + + public OutputStream openOutputStream() { + throw new UnsupportedOperationException(); + } + + public String getName() { + return this.className; + } + + public Reader openReader(boolean ignoreEncodingErrors) { + throw new UnsupportedOperationException(); + } + + public CharSequence getCharContent(boolean ignoreEncodingErrors) { + throw new UnsupportedOperationException(); + } + + public Writer openWriter() throws IOException { + throw new UnsupportedOperationException(); + } + + public long getLastModified() { + return 0; + } + + public boolean delete() { + throw new UnsupportedOperationException(); + } + + public Kind getKind() { + return Kind.CLASS; + } + + public boolean isNameCompatible(String simpleName, Kind kind) { + return Kind.CLASS.equals(getKind()) + && this.className.endsWith(simpleName); + } + + public NestingKind getNestingKind() { + throw new UnsupportedOperationException(); + } + + public Modifier getAccessLevel() { + throw new UnsupportedOperationException(); + } + + public String getClassName() { + return this.className; + } + + + public String toString() { + return this.getClass().getName() + "[" + this.toUri() + "]"; + } + } +} diff --git a/memorycompiler/src/main/java/com/taobao/arthas/compiler/PackageInternalsFinder.java b/memorycompiler/src/main/java/com/taobao/arthas/compiler/PackageInternalsFinder.java index 917c8cc9275..b54ccf987de 100644 --- a/memorycompiler/src/main/java/com/taobao/arthas/compiler/PackageInternalsFinder.java +++ b/memorycompiler/src/main/java/com/taobao/arthas/compiler/PackageInternalsFinder.java @@ -23,10 +23,7 @@ import javax.tools.JavaFileObject; import java.io.File; import java.io.IOException; -import java.net.JarURLConnection; -import java.net.URI; -import java.net.URL; -import java.net.URLDecoder; +import java.net.*; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -36,8 +33,12 @@ import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Consumer; import java.util.jar.JarEntry; +import java.util.jar.JarFile; import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipException; public class PackageInternalsFinder { private final ClassLoader classLoader; @@ -88,32 +89,71 @@ private List processJar(String packageName, URL packageFolderURL // ignore } // 保底 - return fuse(packageFolderURL); + return fuse(packageFolderURL, packageName); } - private List fuse(URL packageFolderURL) { + private List fuse(URL packageFolderURL, String packageName) { List result = new ArrayList(); try { String jarUri = packageFolderURL.toExternalForm().substring(0, packageFolderURL.toExternalForm().lastIndexOf("!/")); - JarURLConnection jarConn = (JarURLConnection) packageFolderURL.openConnection(); - String rootEntryName = jarConn.getEntryName(); - - if (rootEntryName != null) { - //可能为 null(自己没有类文件时) - int rootEnd = rootEntryName.length() + 1; + URLConnection urlConnection = packageFolderURL.openConnection(); + int rootEnd = 0; + Enumeration entryEnum; + if (urlConnection instanceof JarURLConnection){ + try { + JarURLConnection jarConn = (JarURLConnection) urlConnection; + String rootEntryName = jarConn.getEntryName(); + //可能为 null(自己没有类文件时) + if (rootEntryName != null) { + rootEnd = rootEntryName.length() + 1; + entryEnum = jarConn.getJarFile().entries(); + } else { + return result; + } - Enumeration entryEnum = jarConn.getJarFile().entries(); - while (entryEnum.hasMoreElements()) { - JarEntry jarEntry = entryEnum.nextElement(); - String name = jarEntry.getName(); - if (name.startsWith(rootEntryName) && name.indexOf('/', rootEnd) == -1 && name.endsWith(CLASS_FILE_EXTENSION)) { - URI uri = URI.create(jarUri + "!/" + name); - String binaryName = name.replaceAll("/", "."); - binaryName = binaryName.replaceAll(CLASS_FILE_EXTENSION + "$", ""); + while (entryEnum.hasMoreElements()) { + JarEntry jarEntry = entryEnum.nextElement(); + String name = jarEntry.getName(); + if (name.startsWith(rootEntryName) && name.indexOf('/', rootEnd) == -1 && name.endsWith(CLASS_FILE_EXTENSION)) { + URI uri = URI.create(jarUri + "!/" + name); + String binaryName = name.replaceAll("/", "."); + binaryName = binaryName.replaceAll(CLASS_FILE_EXTENSION + "$", ""); - result.add(new CustomJavaFileObject(binaryName, uri)); + result.add(new CustomJavaFileObject(binaryName, uri)); + } + } + } catch (Exception e) { + throw new RuntimeException("Failed to open " + packageFolderURL + " as a jar file", e); + } + }else { + //是否可以在硬盘上找到对应的文件 + try { + File file = new File(new URI(jarUri)); + if (file.exists()) { + //可能是文件或目录 + if (file.isDirectory()) { + result.addAll(processDir(packageName, file)); + } else { + try { + GetZipFile zipFile = new GetZipFile(file); + zipFile.stream().forEach(e -> { + String name = e.getName(); + if (name.startsWith(packageName) && name.endsWith(CLASS_FILE_EXTENSION)) { + URI uri = URI.create(jarUri + "!/" + name); + String binaryName = name.replaceAll("/", "."); + binaryName = binaryName.replaceAll(CLASS_FILE_EXTENSION + "$", ""); + + result.add(zipFile.new ZipJavaFileObject(binaryName, uri, e)); + } + }); + }catch (ZipException e) { + // ignore + } + } } + }catch (SecurityException e) { + throw new RuntimeException("Failed to open " + packageFolderURL + " as a jar file", e); } } } catch (Exception e) { From dc9d8fe5d299250e8ed0863be570d725180da8f2 Mon Sep 17 00:00:00 2001 From: 1luik <8632787+n1luik@user.noreply.gitee.com> Date: Tue, 16 Dec 2025 23:53:34 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E4=BF=AE=E5=A4=8D#3103?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/taobao/arthas/compiler/PackageInternalsFinder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/memorycompiler/src/main/java/com/taobao/arthas/compiler/PackageInternalsFinder.java b/memorycompiler/src/main/java/com/taobao/arthas/compiler/PackageInternalsFinder.java index b54ccf987de..e293bff0fde 100644 --- a/memorycompiler/src/main/java/com/taobao/arthas/compiler/PackageInternalsFinder.java +++ b/memorycompiler/src/main/java/com/taobao/arthas/compiler/PackageInternalsFinder.java @@ -98,10 +98,10 @@ private List fuse(URL packageFolderURL, String packageName) { String jarUri = packageFolderURL.toExternalForm().substring(0, packageFolderURL.toExternalForm().lastIndexOf("!/")); URLConnection urlConnection = packageFolderURL.openConnection(); - int rootEnd = 0; Enumeration entryEnum; if (urlConnection instanceof JarURLConnection){ try { + int rootEnd = 0; JarURLConnection jarConn = (JarURLConnection) urlConnection; String rootEntryName = jarConn.getEntryName(); //可能为 null(自己没有类文件时) From 244fea515ad9c4cd9e027e8b3265d731ad6cef13 Mon Sep 17 00:00:00 2001 From: 1luik <8632787+n1luik@user.noreply.gitee.com> Date: Wed, 17 Dec 2025 12:14:26 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E4=BF=AE=E5=A4=8D#3103?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../compiler/PackageInternalsFinder.java | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/memorycompiler/src/main/java/com/taobao/arthas/compiler/PackageInternalsFinder.java b/memorycompiler/src/main/java/com/taobao/arthas/compiler/PackageInternalsFinder.java index e293bff0fde..f138e580792 100644 --- a/memorycompiler/src/main/java/com/taobao/arthas/compiler/PackageInternalsFinder.java +++ b/memorycompiler/src/main/java/com/taobao/arthas/compiler/PackageInternalsFinder.java @@ -129,7 +129,23 @@ private List fuse(URL packageFolderURL, String packageName) { }else { //是否可以在硬盘上找到对应的文件 try { - File file = new File(new URI(jarUri)); + URI uri1 = new URI(jarUri); + // 获取 authority(host:port) + path + query + fragment + StringBuilder sb = new StringBuilder(); + if (uri1.getAuthority() != null) { + sb.append(uri1.getAuthority()); + } + if (uri1.getPath() != null) { + sb.append(uri1.getPath()); + } + if (uri1.getQuery() != null) { + sb.append('?').append(uri1.getQuery()); + } + if (uri1.getFragment() != null) { + sb.append('#').append(uri1.getFragment()); + } + + File file = new File(sb.toString()); if (file.exists()) { //可能是文件或目录 if (file.isDirectory()) {