diff options
| author | Luck <git@lucko.me> | 2021-05-27 23:27:38 +0100 |
|---|---|---|
| committer | Luck <git@lucko.me> | 2021-05-30 21:51:37 +0100 |
| commit | f5bb628319d57c8d1ed26e1673d9f781cc939f83 (patch) | |
| tree | dabba3da9c6bc37447d6eacfd42eddb30e6fd2d2 | |
| parent | 767995e05d46b416292a713756782f939b16f61f (diff) | |
| download | spark-f5bb628319d57c8d1ed26e1673d9f781cc939f83.tar.gz spark-f5bb628319d57c8d1ed26e1673d9f781cc939f83.tar.bz2 spark-f5bb628319d57c8d1ed26e1673d9f781cc939f83.zip | |
Extract class sources (plugin/mod names) and include in data payload
32 files changed, 684 insertions, 36 deletions
diff --git a/build.gradle b/build.gradle index b95d239..0e9389d 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ allprojects { group = 'me.lucko' - version = '1.5-SNAPSHOT' + version = '1.6-SNAPSHOT' configurations { compileClasspath // Fabric-loom needs this for remap jar for some reason @@ -13,7 +13,7 @@ subprojects { apply plugin: 'idea' ext { - pluginVersion = '1.5.2' + pluginVersion = '1.6.0' pluginDescription = 'spark is a performance profiling plugin/mod for Minecraft clients, servers and proxies.' } diff --git a/spark-bukkit/src/main/java/me/lucko/spark/bukkit/BukkitClassSourceLookup.java b/spark-bukkit/src/main/java/me/lucko/spark/bukkit/BukkitClassSourceLookup.java new file mode 100644 index 0000000..a87be6f --- /dev/null +++ b/spark-bukkit/src/main/java/me/lucko/spark/bukkit/BukkitClassSourceLookup.java @@ -0,0 +1,52 @@ +/* + * This file is part of spark. + * + * Copyright (c) lucko (Luck) <luck@lucko.me> + * Copyright (c) contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package me.lucko.spark.bukkit; + +import me.lucko.spark.common.util.ClassSourceLookup; + +import org.bukkit.plugin.java.JavaPlugin; + +import java.lang.reflect.Method; + +public class BukkitClassSourceLookup extends ClassSourceLookup.ByClassLoader { + private static final Class<?> PLUGIN_CLASS_LOADER; + private static final Method GET_PLUGIN_METHOD; + + static { + try { + PLUGIN_CLASS_LOADER = Class.forName("org.bukkit.plugin.java.PluginClassLoader"); + GET_PLUGIN_METHOD = PLUGIN_CLASS_LOADER.getDeclaredMethod("getPlugin"); + GET_PLUGIN_METHOD.setAccessible(true); + } catch (ReflectiveOperationException e) { + throw new ExceptionInInitializerError(e); + } + } + + @Override + public String identify(ClassLoader loader) throws ReflectiveOperationException { + if (PLUGIN_CLASS_LOADER.isInstance(loader)) { + JavaPlugin plugin = (JavaPlugin) GET_PLUGIN_METHOD.invoke(loader); + return plugin.getName(); + } + return null; + } +} + diff --git a/spark-bukkit/src/main/java/me/lucko/spark/bukkit/BukkitSparkPlugin.java b/spark-bukkit/src/main/java/me/lucko/spark/bukkit/BukkitSparkPlugin.java index 970c4b4..e746d60 100644 --- a/spark-bukkit/src/main/java/me/lucko/spark/bukkit/BukkitSparkPlugin.java +++ b/spark-bukkit/src/main/java/me/lucko/spark/bukkit/BukkitSparkPlugin.java @@ -29,6 +29,7 @@ import me.lucko.spark.common.platform.PlatformInfo; import me.lucko.spark.common.sampler.ThreadDumper; import me.lucko.spark.common.tick.TickHook; import me.lucko.spark.common.tick.TickReporter; +import me.lucko.spark.common.util.ClassSourceLookup; import net.kyori.adventure.platform.bukkit.BukkitAudiences; @@ -160,6 +161,11 @@ public class BukkitSparkPlugin extends JavaPlugin implements SparkPlugin { } @Override + public ClassSourceLookup createClassSourceLookup() { + return new BukkitClassSourceLookup(); + } + + @Override public PlatformInfo getPlatformInfo() { return new BukkitPlatformInfo(getServer()); } diff --git a/spark-bungeecord/src/main/java/me/lucko/spark/bungeecord/BungeeCordClassSourceLookup.java b/spark-bungeecord/src/main/java/me/lucko/spark/bungeecord/BungeeCordClassSourceLookup.java new file mode 100644 index 0000000..e601f87 --- /dev/null +++ b/spark-bungeecord/src/main/java/me/lucko/spark/bungeecord/BungeeCordClassSourceLookup.java @@ -0,0 +1,52 @@ +/* + * This file is part of spark. + * + * Copyright (c) lucko (Luck) <luck@lucko.me> + * Copyright (c) contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package me.lucko.spark.bungeecord; + +import me.lucko.spark.common.util.ClassSourceLookup; + +import net.md_5.bungee.api.plugin.PluginDescription; + +import java.lang.reflect.Field; + +public class BungeeCordClassSourceLookup extends ClassSourceLookup.ByClassLoader { + private static final Class<?> PLUGIN_CLASS_LOADER; + private static final Field DESC_FIELD; + + static { + try { + PLUGIN_CLASS_LOADER = Class.forName("net.md_5.bungee.api.plugin.PluginClassloader"); + DESC_FIELD = PLUGIN_CLASS_LOADER.getDeclaredField("desc"); + DESC_FIELD.setAccessible(true); + } catch (ReflectiveOperationException e) { + throw new ExceptionInInitializerError(e); + } + } + + @Override + public String identify(ClassLoader loader) throws ReflectiveOperationException { + if (PLUGIN_CLASS_LOADER.isInstance(loader)) { + PluginDescription desc = (PluginDescription) DESC_FIELD.get(loader); + return desc.getName(); + } + return null; + } +} + diff --git a/spark-bungeecord/src/main/java/me/lucko/spark/bungeecord/BungeeCordSparkPlugin.java b/spark-bungeecord/src/main/java/me/lucko/spark/bungeecord/BungeeCordSparkPlugin.java index 357c457..2fb44c3 100644 --- a/spark-bungeecord/src/main/java/me/lucko/spark/bungeecord/BungeeCordSparkPlugin.java +++ b/spark-bungeecord/src/main/java/me/lucko/spark/bungeecord/BungeeCordSparkPlugin.java @@ -23,6 +23,7 @@ package me.lucko.spark.bungeecord; import me.lucko.spark.common.SparkPlatform; import me.lucko.spark.common.SparkPlugin; import me.lucko.spark.common.platform.PlatformInfo; +import me.lucko.spark.common.util.ClassSourceLookup; import net.kyori.adventure.platform.bungeecord.BungeeAudiences; import net.md_5.bungee.api.CommandSender; @@ -79,6 +80,11 @@ public class BungeeCordSparkPlugin extends Plugin implements SparkPlugin { } @Override + public ClassSourceLookup createClassSourceLookup() { + return new BungeeCordClassSourceLookup(); + } + + @Override public PlatformInfo getPlatformInfo() { return new BungeeCordPlatformInfo(getProxy()); } diff --git a/spark-common/build.gradle b/spark-common/build.gradle index e07647d..59e6439 100644 --- a/spark-common/build.gradle +++ b/spark-common/build.gradle @@ -9,6 +9,7 @@ dependencies { compile 'com.google.protobuf:protobuf-javalite:3.15.6' compile 'com.squareup.okhttp3:okhttp:3.14.1' compile 'com.squareup.okio:okio:1.17.3' + compile 'net.bytebuddy:byte-buddy-agent:1.11.0' compile 'org.tukaani:xz:1.8' compile('net.kyori:adventure-api:4.7.0') { exclude(module: 'checker-qual') diff --git a/spark-common/src/main/java/me/lucko/spark/common/SparkPlatform.java b/spark-common/src/main/java/me/lucko/spark/common/SparkPlatform.java index 491b7d3..fdced75 100644 --- a/spark-common/src/main/java/me/lucko/spark/common/SparkPlatform.java +++ b/spark-common/src/main/java/me/lucko/spark/common/SparkPlatform.java @@ -44,6 +44,7 @@ import me.lucko.spark.common.monitor.tick.TickStatistics; import me.lucko.spark.common.tick.TickHook; import me.lucko.spark.common.tick.TickReporter; import me.lucko.spark.common.util.BytebinClient; +import me.lucko.spark.common.util.ClassSourceLookup; import net.kyori.adventure.text.event.ClickEvent; @@ -87,6 +88,7 @@ public class SparkPlatform { private final ActivityLog activityLog; private final TickHook tickHook; private final TickReporter tickReporter; + private final ClassSourceLookup classSourceLookup; private final TickStatistics tickStatistics; private Map<String, GarbageCollectorStatistics> startupGcStatistics = ImmutableMap.of(); private long serverNormalOperationStartTime; @@ -115,6 +117,7 @@ public class SparkPlatform { this.tickHook = plugin.createTickHook(); this.tickReporter = plugin.createTickReporter(); + this.classSourceLookup = plugin.createClassSourceLookup(); this.tickStatistics = this.tickHook != null ? new TickStatistics() : null; } @@ -175,6 +178,10 @@ public class SparkPlatform { return this.tickReporter; } + public ClassSourceLookup getClassSourceLookup() { + return this.classSourceLookup; + } + public TickStatistics getTickStatistics() { return this.tickStatistics; } diff --git a/spark-common/src/main/java/me/lucko/spark/common/SparkPlugin.java b/spark-common/src/main/java/me/lucko/spark/common/SparkPlugin.java index 216f23f..aa5112d 100644 --- a/spark-common/src/main/java/me/lucko/spark/common/SparkPlugin.java +++ b/spark-common/src/main/java/me/lucko/spark/common/SparkPlugin.java @@ -26,6 +26,7 @@ import me.lucko.spark.common.platform.PlatformInfo; import me.lucko.spark.common.sampler.ThreadDumper; import me.lucko.spark.common.tick.TickHook; import me.lucko.spark.common.tick.TickReporter; +import me.lucko.spark.common.util.ClassSourceLookup; import java.nio.file.Path; import java.util.stream.Stream; @@ -102,6 +103,15 @@ public interface SparkPlugin { } /** + * Creates a class source lookup function. + * + * @return the class source lookup function + */ + default ClassSourceLookup createClassSourceLookup() { + return ClassSourceLookup.NO_OP; + } + + /** * Gets information for the platform. * * @return information about the platform diff --git a/spark-common/src/main/java/me/lucko/spark/common/command/modules/SamplerModule.java b/spark-common/src/main/java/me/lucko/spark/common/command/modules/SamplerModule.java index 856a182..ebf6372 100644 --- a/spark-common/src/main/java/me/lucko/spark/common/command/modules/SamplerModule.java +++ b/spark-common/src/main/java/me/lucko/spark/common/command/modules/SamplerModule.java @@ -299,7 +299,7 @@ public class SamplerModule implements CommandModule { } private void handleUpload(SparkPlatform platform, CommandResponseHandler resp, Sampler sampler, ThreadNodeOrder threadOrder, String comment, MergeMode mergeMode) { - byte[] output = sampler.formCompressedDataPayload(platform.getPlugin().getPlatformInfo(), resp.sender(), threadOrder, comment, mergeMode); + byte[] output = sampler.formCompressedDataPayload(new Sampler.ExportProps(platform.getPlugin().getPlatformInfo(), resp.sender(), threadOrder, comment, mergeMode, platform.getClassSourceLookup())); try { String key = SparkPlatform.BYTEBIN_CLIENT.postContent(output, SPARK_SAMPLER_MEDIA_TYPE).key(); String url = SparkPlatform.VIEWER_URL + key; diff --git a/spark-common/src/main/java/me/lucko/spark/common/sampler/Sampler.java b/spark-common/src/main/java/me/lucko/spark/common/sampler/Sampler.java index 5088ed7..bc08dfd 100644 --- a/spark-common/src/main/java/me/lucko/spark/common/sampler/Sampler.java +++ b/spark-common/src/main/java/me/lucko/spark/common/sampler/Sampler.java @@ -24,6 +24,7 @@ import me.lucko.spark.common.command.sender.CommandSender; import me.lucko.spark.common.platform.PlatformInfo; import me.lucko.spark.common.sampler.node.MergeMode; import me.lucko.spark.common.sampler.node.ThreadNode; +import me.lucko.spark.common.util.ClassSourceLookup; import me.lucko.spark.proto.SparkProtos.SamplerData; import java.io.ByteArrayOutputStream; @@ -71,16 +72,10 @@ public interface Sampler { CompletableFuture<? extends Sampler> getFuture(); // Methods used to export the sampler data to the web viewer. - SamplerData toProto( - PlatformInfo platformInfo, - CommandSender creator, - Comparator<? super Map.Entry<String, ThreadNode>> outputOrder, - String comment, - MergeMode mergeMode - ); + SamplerData toProto(ExportProps props); - default byte[] formCompressedDataPayload(PlatformInfo platformInfo, CommandSender creator, Comparator<? super Map.Entry<String, ThreadNode>> outputOrder, String comment, MergeMode mergeMode) { - SamplerData proto = toProto(platformInfo, creator, outputOrder, comment, mergeMode); + default byte[] formCompressedDataPayload(ExportProps props) { + SamplerData proto = toProto(props); ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); try (OutputStream out = new GZIPOutputStream(byteOut)) { @@ -91,4 +86,22 @@ public interface Sampler { return byteOut.toByteArray(); } + class ExportProps { + public final PlatformInfo platformInfo; + public final CommandSender creator; + public final Comparator<? super Map.Entry<String, ThreadNode>> outputOrder; + public final String comment; + public final MergeMode mergeMode; + public final ClassSourceLookup classSourceLookup; + + public ExportProps(PlatformInfo platformInfo, CommandSender creator, Comparator<? super Map.Entry<String, ThreadNode>> outputOrder, String comment, MergeMode mergeMode, ClassSourceLookup classSourceLookup) { + this.platformInfo = platformInfo; + this.creator = creator; + this.outputOrder = outputOrder; + this.comment = comment; + this.mergeMode = mergeMode; + this.classSourceLookup = classSourceLookup; + } + } + } diff --git a/spark-common/src/main/java/me/lucko/spark/common/sampler/async/AsyncSampler.java b/spark-common/src/main/java/me/lucko/spark/common/sampler/async/AsyncSampler.java index c76274b..8d57a6d 100644 --- a/spark-common/src/main/java/me/lucko/spark/common/sampler/async/AsyncSampler.java +++ b/spark-common/src/main/java/me/lucko/spark/common/sampler/async/AsyncSampler.java @@ -20,14 +20,12 @@ package me.lucko.spark.common.sampler.async; -import me.lucko.spark.common.command.sender.CommandSender; -import me.lucko.spark.common.platform.PlatformInfo; import me.lucko.spark.common.sampler.Sampler; import me.lucko.spark.common.sampler.ThreadDumper; import me.lucko.spark.common.sampler.ThreadGrouper; import me.lucko.spark.common.sampler.async.jfr.JfrReader; -import me.lucko.spark.common.sampler.node.MergeMode; import me.lucko.spark.common.sampler.node.ThreadNode; +import me.lucko.spark.common.util.ClassSourceLookup; import me.lucko.spark.proto.SparkProtos; import one.profiler.AsyncProfiler; @@ -37,7 +35,6 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; -import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; @@ -144,17 +141,17 @@ public class AsyncSampler implements Sampler { } @Override - public SparkProtos.SamplerData toProto(PlatformInfo platformInfo, CommandSender creator, Comparator<? super Map.Entry<String, ThreadNode>> outputOrder, String comment, MergeMode mergeMode) { + public SparkProtos.SamplerData toProto(ExportProps props) { final SparkProtos.SamplerMetadata.Builder metadata = SparkProtos.SamplerMetadata.newBuilder() - .setPlatformMetadata(platformInfo.toData().toProto()) - .setCreator(creator.toData().toProto()) + .setPlatformMetadata(props.platformInfo.toData().toProto()) + .setCreator(props.creator.toData().toProto()) .setStartTime(this.startTime) .setInterval(this.interval) .setThreadDumper(this.threadDumper.getMetadata()) .setDataAggregator(this.dataAggregator.getMetadata()); - if (comment != null) { - metadata.setComment(comment); + if (props.comment != null) { + metadata.setComment(props.comment); } SparkProtos.SamplerData.Builder proto = SparkProtos.SamplerData.newBuilder(); @@ -163,10 +160,17 @@ public class AsyncSampler implements Sampler { aggregateOutput(); List<Map.Entry<String, ThreadNode>> data = new ArrayList<>(this.dataAggregator.getData().entrySet()); - data.sort(outputOrder); + data.sort(props.outputOrder); + + ClassSourceLookup.Visitor classSourceVisitor = ClassSourceLookup.createVisitor(props.classSourceLookup); for (Map.Entry<String, ThreadNode> entry : data) { - proto.addThreads(entry.getValue().toProto(mergeMode)); + proto.addThreads(entry.getValue().toProto(props.mergeMode)); + classSourceVisitor.visit(entry.getValue()); + } + + if (classSourceVisitor.hasMappings()) { + proto.putAllClassSources(classSourceVisitor.getMapping()); } return proto.build(); diff --git a/spark-common/src/main/java/me/lucko/spark/common/sampler/java/JavaSampler.java b/spark-common/src/main/java/me/lucko/spark/common/sampler/java/JavaSampler.java index 5fe5add..23d38d8 100644 --- a/spark-common/src/main/java/me/lucko/spark/common/sampler/java/JavaSampler.java +++ b/spark-common/src/main/java/me/lucko/spark/common/sampler/java/JavaSampler.java @@ -23,14 +23,12 @@ package me.lucko.spark.common.sampler.java; import com.google.common.util.concurrent.ThreadFactoryBuilder; -import me.lucko.spark.common.command.sender.CommandSender; -import me.lucko.spark.common.platform.PlatformInfo; import me.lucko.spark.common.sampler.Sampler; import me.lucko.spark.common.sampler.ThreadDumper; import me.lucko.spark.common.sampler.ThreadGrouper; -import me.lucko.spark.common.sampler.node.MergeMode; import me.lucko.spark.common.sampler.node.ThreadNode; import me.lucko.spark.common.tick.TickHook; +import me.lucko.spark.common.util.ClassSourceLookup; import me.lucko.spark.proto.SparkProtos.SamplerData; import me.lucko.spark.proto.SparkProtos.SamplerMetadata; @@ -38,7 +36,6 @@ import java.lang.management.ManagementFactory; import java.lang.management.ThreadInfo; import java.lang.management.ThreadMXBean; import java.util.ArrayList; -import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; @@ -161,27 +158,34 @@ public class JavaSampler implements Sampler, Runnable { } @Override - public SamplerData toProto(PlatformInfo platformInfo, CommandSender creator, Comparator<? super Map.Entry<String, ThreadNode>> outputOrder, String comment, MergeMode mergeMode) { + public SamplerData toProto(ExportProps props) { final SamplerMetadata.Builder metadata = SamplerMetadata.newBuilder() - .setPlatformMetadata(platformInfo.toData().toProto()) - .setCreator(creator.toData().toProto()) + .setPlatformMetadata(props.platformInfo.toData().toProto()) + .setCreator(props.creator.toData().toProto()) .setStartTime(this.startTime) .setInterval(this.interval) .setThreadDumper(this.threadDumper.getMetadata()) .setDataAggregator(this.dataAggregator.getMetadata()); - if (comment != null) { - metadata.setComment(comment); + if (props.comment != null) { + metadata.setComment(props.comment); } SamplerData.Builder proto = SamplerData.newBuilder(); proto.setMetadata(metadata.build()); List<Map.Entry<String, ThreadNode>> data = new ArrayList<>(this.dataAggregator.getData().entrySet()); - data.sort(outputOrder); + data.sort(props.outputOrder); + + ClassSourceLookup.Visitor classSourceVisitor = ClassSourceLookup.createVisitor(props.classSourceLookup); for (Map.Entry<String, ThreadNode> entry : data) { - proto.addThreads(entry.getValue().toProto(mergeMode)); + proto.addThreads(entry.getValue().toProto(props.mergeMode)); + classSourceVisitor.visit(entry.getValue()); + } + + if (classSourceVisitor.hasMappings()) { + proto.putAllClassSources(classSourceVisitor.getMapping()); } return proto.build(); diff --git a/spark-common/src/main/java/me/lucko/spark/common/sampler/node/AbstractNode.java b/spark-common/src/main/java/me/lucko/spark/common/sampler/node/AbstractNode.java index 2ef06d3..73f7bd7 100644 --- a/spark-common/src/main/java/me/lucko/spark/common/sampler/node/AbstractNode.java +++ b/spark-common/src/main/java/me/lucko/spark/common/sampler/node/AbstractNode.java @@ -24,6 +24,7 @@ package me.lucko.spark.common.sampler.node; import me.lucko.spark.common.sampler.async.AsyncStackTraceElement; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; @@ -56,6 +57,10 @@ public abstract class AbstractNode { return this.totalTime.longValue() / 1000d; } + public Collection<StackTraceNode> getChildren() { + return this.children.values(); + } + /** * Merge {@code other} into {@code this}. * diff --git a/spark-common/src/main/java/me/lucko/spark/common/sampler/node/StackTraceNode.java b/spark-common/src/main/java/me/lucko/spark/common/sampler/node/StackTraceNode.java index 4179464..efc7f81 100644 --- a/spark-common/src/main/java/me/lucko/spark/common/sampler/node/StackTraceNode.java +++ b/spark-common/src/main/java/me/lucko/spark/common/sampler/node/StackTraceNode.java @@ -51,6 +51,10 @@ public final class StackTraceNode extends AbstractNode implements Comparable<Sta return this.description.methodName; } + public String getMethodDescription() { + return this.description.methodDescription; + } + public int getLineNumber() { return this.description.lineNumber; } diff --git a/spark-common/src/main/java/me/lucko/spark/common/util/ClassFinder.java b/spark-common/src/main/java/me/lucko/spark/common/util/ClassFinder.java new file mode 100644 index 0000000..4481786 --- /dev/null +++ b/spark-common/src/main/java/me/lucko/spark/common/util/ClassFinder.java @@ -0,0 +1,71 @@ +/* + * This file is part of spark. + * + * Copyright (c) lucko (Luck) <luck@lucko.me> + * Copyright (c) contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package me.lucko.spark.common.util; + +import net.bytebuddy.agent.ByteBuddyAgent; + +import org.checkerframework.checker.nullness.qual.Nullable; + +import java.lang.instrument.Instrumentation; +import java.util.HashMap; +import java.util.Map; + +/** + * Uses {@link Instrumentation} to find a class reference for given class names. + * + * <p>This is necessary as we don't always have access to the classloader for a given class.</p> + */ +public class ClassFinder { + + private final Map<String, Class<?>> classes = new HashMap<>(); + + public ClassFinder() { + Instrumentation instrumentation; + try { + instrumentation = ByteBuddyAgent.install(); + } catch (Exception e) { + return; + } + + // obtain and cache loaded classes + for (Class<?> loadedClass : instrumentation.getAllLoadedClasses()) { + this.classes.put(loadedClass.getName(), loadedClass); + } + } + + public @Nullable Class<?> findClass(String className) { + // try instrumentation + Class<?> clazz = this.classes.get(className); + if (clazz != null) { + return clazz; + } + + // try Class.forName + try { + return Class.forName(className); + } catch (Throwable e) { + // ignore + } + + return null; + } + +} diff --git a/spark-common/src/main/java/me/lucko/spark/common/util/ClassSourceLookup.java b/spark-common/src/main/java/me/lucko/spark/common/util/ClassSourceLookup.java new file mode 100644 index 0000000..27e3ec6 --- /dev/null +++ b/spark-common/src/main/java/me/lucko/spark/common/util/ClassSourceLookup.java @@ -0,0 +1,223 @@ +/* + * This file is part of spark. + * + * Copyright (c) lucko (Luck) <luck@lucko.me> + * Copyright (c) contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You |
