mirror of
https://github.com/filoghost/HolographicDisplays.git
synced 2024-12-24 01:37:35 +01:00
Use StackWalker on Java 9+ and add compatibility layer
This commit is contained in:
parent
57f7e0e9e4
commit
0ad5cdac32
15
JavaCompat/pom.xml
Normal file
15
JavaCompat/pom.xml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<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/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>com.gmail.filoghost.holographicdisplays</groupId>
|
||||||
|
<artifactId>holographicdisplays-parent</artifactId>
|
||||||
|
<version>2.3.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>holographicdisplays-javacompat</artifactId>
|
||||||
|
<name>HolographicDisplays Java Compat</name>
|
||||||
|
|
||||||
|
</project>
|
20
JavaCompat/src/main/java/java/lang/StackWalker.java
Normal file
20
JavaCompat/src/main/java/java/lang/StackWalker.java
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package java.lang;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public class StackWalker {
|
||||||
|
|
||||||
|
public static interface StackFrame {
|
||||||
|
StackTraceElement toStackTraceElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static StackWalker getInstance() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T walk(Function<? super Stream<StackFrame>, ? extends T> function) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
9
JavaCompat/src/main/java/java/util/Optional.java
Normal file
9
JavaCompat/src/main/java/java/util/Optional.java
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package java.util;
|
||||||
|
|
||||||
|
public class Optional<T> {
|
||||||
|
|
||||||
|
public T orElse(T other) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
package java.util.function;
|
||||||
|
|
||||||
|
public interface Function<T, R> {
|
||||||
|
|
||||||
|
R apply(T t);
|
||||||
|
|
||||||
|
}
|
13
JavaCompat/src/main/java/java/util/stream/Stream.java
Normal file
13
JavaCompat/src/main/java/java/util/stream/Stream.java
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package java.util.stream;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public interface Stream<T> {
|
||||||
|
|
||||||
|
public Stream<T> skip(long n);
|
||||||
|
|
||||||
|
public Stream<T> limit(long maxSize);
|
||||||
|
|
||||||
|
public Optional<T> findFirst();
|
||||||
|
|
||||||
|
}
|
@ -35,6 +35,7 @@ import com.gmail.filoghost.holographicdisplays.task.StartupLoadHologramsTask;
|
|||||||
import com.gmail.filoghost.holographicdisplays.task.WorldPlayerCounterTask;
|
import com.gmail.filoghost.holographicdisplays.task.WorldPlayerCounterTask;
|
||||||
import com.gmail.filoghost.holographicdisplays.util.ConsoleLogger;
|
import com.gmail.filoghost.holographicdisplays.util.ConsoleLogger;
|
||||||
import com.gmail.filoghost.holographicdisplays.util.NMSVersion;
|
import com.gmail.filoghost.holographicdisplays.util.NMSVersion;
|
||||||
|
import com.gmail.filoghost.holographicdisplays.util.Utils;
|
||||||
import com.gmail.filoghost.holographicdisplays.util.VersionUtils;
|
import com.gmail.filoghost.holographicdisplays.util.VersionUtils;
|
||||||
|
|
||||||
public class HolographicDisplays extends JavaPlugin {
|
public class HolographicDisplays extends JavaPlugin {
|
||||||
@ -161,7 +162,7 @@ public class HolographicDisplays extends JavaPlugin {
|
|||||||
if (requiredVersionError == null) {
|
if (requiredVersionError == null) {
|
||||||
ProtocolLibHook protocolLibHook;
|
ProtocolLibHook protocolLibHook;
|
||||||
|
|
||||||
if (VersionUtils.classExists("com.comphenix.protocol.wrappers.WrappedDataWatcher$WrappedDataWatcherObject")) {
|
if (Utils.classExists("com.comphenix.protocol.wrappers.WrappedDataWatcher$WrappedDataWatcherObject")) {
|
||||||
// Only the new version contains this class
|
// Only the new version contains this class
|
||||||
ConsoleLogger.log(Level.INFO, "Found ProtocolLib, using new version.");
|
ConsoleLogger.log(Level.INFO, "Found ProtocolLib, using new version.");
|
||||||
protocolLibHook = new com.gmail.filoghost.holographicdisplays.bridge.protocollib.current.ProtocolLibHookImpl();
|
protocolLibHook = new com.gmail.filoghost.holographicdisplays.bridge.protocollib.current.ProtocolLibHookImpl();
|
||||||
|
@ -36,6 +36,13 @@
|
|||||||
<version>1.8-R0.1-SNAPSHOT</version>
|
<version>1.8-R0.1-SNAPSHOT</version>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>${project.groupId}</groupId>
|
||||||
|
<artifactId>holographicdisplays-javacompat</artifactId>
|
||||||
|
<version>2.3.0-SNAPSHOT</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
@ -53,15 +53,10 @@ public class Utils extends Object {
|
|||||||
return new ArrayList<T>();
|
return new ArrayList<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static <T> Set<T> newSet() {
|
public static <T> Set<T> newSet() {
|
||||||
return new HashSet<T>();
|
return new HashSet<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public static <T> T[] listToArray(List<T> list) {
|
|
||||||
return (T[]) list.toArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int floor(double num) {
|
public static int floor(double num) {
|
||||||
int floor = (int) num;
|
int floor = (int) num;
|
||||||
@ -107,10 +102,12 @@ public class Utils extends Object {
|
|||||||
return join(elements, separator, 0, elements.size());
|
return join(elements, separator, 0, elements.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static String sanitize(String s) {
|
public static String sanitize(String s) {
|
||||||
return s != null ? s : "null";
|
return s != null ? s : "null";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static boolean isThereNonNull(Object... objects) {
|
public static boolean isThereNonNull(Object... objects) {
|
||||||
if (objects == null) {
|
if (objects == null) {
|
||||||
return false;
|
return false;
|
||||||
@ -124,4 +121,14 @@ public class Utils extends Object {
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static boolean classExists(String className) {
|
||||||
|
try {
|
||||||
|
Class.forName(className);
|
||||||
|
return true;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,14 +79,4 @@ public class VersionUtils {
|
|||||||
return isVersionGreaterEqual(reference, lowest) && isVersionLessEqual(reference, highest);
|
return isVersionGreaterEqual(reference, lowest) && isVersionLessEqual(reference, highest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static boolean classExists(String className) {
|
|
||||||
try {
|
|
||||||
Class.forName(className);
|
|
||||||
return true;
|
|
||||||
} catch (Throwable t) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,47 +1,69 @@
|
|||||||
package com.gmail.filoghost.holographicdisplays.util.reflection;
|
package com.gmail.filoghost.holographicdisplays.util.reflection;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.StackWalker.StackFrame;
|
||||||
|
import java.util.function.Function;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import com.gmail.filoghost.holographicdisplays.util.ConsoleLogger;
|
import com.gmail.filoghost.holographicdisplays.util.ConsoleLogger;
|
||||||
|
import com.gmail.filoghost.holographicdisplays.util.Utils;
|
||||||
|
|
||||||
public class ReflectionUtils {
|
public class ReflectionUtils {
|
||||||
|
|
||||||
private static Method getStackTraceElementMethod;
|
private static final boolean HAS_JAVA9_STACKWALKER = Utils.classExists("java.lang.StackWalker");
|
||||||
private static Method getStackTraceDepthMethod;
|
|
||||||
|
|
||||||
private static boolean stackTraceErrorPrinted;
|
private static final ReflectMethod<Integer> GET_STACKTRACE_DEPTH_METHOD = new ReflectMethod<Integer>(Throwable.class, "getStackTraceDepth");
|
||||||
|
private static final ReflectMethod<StackTraceElement> GET_STACKTRACE_ELEMENT_METHOD = new ReflectMethod<StackTraceElement>(Throwable.class, "getStackTraceElement", int.class);
|
||||||
|
|
||||||
|
private static boolean stackTraceError;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If you only need one stack trace element this is faster than Throwable.getStackTrace()[element],
|
* If you only need one stack trace element this is faster than Throwable.getStackTrace()[element],
|
||||||
* it doesn't generate the full stack trace.
|
* it doesn't generate the full stack trace (except as fallback).
|
||||||
*/
|
*/
|
||||||
public static StackTraceElement getStackTraceElement(int index) {
|
public static StackTraceElement getStackTraceElement(final int index) {
|
||||||
try {
|
// Use the faster methods only if there hasn't been any error while executing them previously
|
||||||
if (getStackTraceElementMethod == null) {
|
if (!stackTraceError) {
|
||||||
getStackTraceElementMethod = Throwable.class.getDeclaredMethod("getStackTraceElement", int.class);
|
try {
|
||||||
getStackTraceElementMethod.setAccessible(true);
|
if (HAS_JAVA9_STACKWALKER) {
|
||||||
}
|
// Use the Java 9 StackWalker API
|
||||||
if (getStackTraceDepthMethod == null) {
|
StackFrame result = StackWalker.getInstance().walk(new Function<Stream<StackFrame>, StackFrame>() {
|
||||||
getStackTraceDepthMethod = Throwable.class.getDeclaredMethod("getStackTraceDepth");
|
|
||||||
getStackTraceDepthMethod.setAccessible(true);
|
@Override
|
||||||
}
|
public StackFrame apply(Stream<StackFrame> stream) {
|
||||||
|
return stream.skip(index).limit(1).findFirst().orElse(null);
|
||||||
Throwable dummyThrowable = new Throwable();
|
}
|
||||||
int depth = (Integer) getStackTraceDepthMethod.invoke(dummyThrowable);
|
|
||||||
|
});
|
||||||
if (index < depth) {
|
return result != null ? result.toStackTraceElement() : null;
|
||||||
return (StackTraceElement) getStackTraceElementMethod.invoke(new Throwable(), index);
|
|
||||||
} else {
|
} else {
|
||||||
return null;
|
// Use reflection to avoid generating the full stacktrace
|
||||||
}
|
Throwable dummyThrowable = new Throwable();
|
||||||
} catch (Throwable t) {
|
int depth = GET_STACKTRACE_DEPTH_METHOD.invoke(dummyThrowable);
|
||||||
if (!stackTraceErrorPrinted) {
|
|
||||||
ConsoleLogger.log(Level.WARNING, "Unable to get a stacktrace element, please inform the developer. You will only see this error once to avoid spam.", t);
|
if (index < depth) {
|
||||||
stackTraceErrorPrinted = true;
|
return GET_STACKTRACE_ELEMENT_METHOD.invoke(dummyThrowable, index);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Throwable t) {
|
||||||
|
if (!stackTraceError) {
|
||||||
|
ConsoleLogger.log(Level.WARNING, "Unable to get a stacktrace element, please inform the developer. You will only see this error once and a fallback method will be used.", t);
|
||||||
|
stackTraceError = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback slower method, generates the full stack trace (it should never be called if everything works as expected)
|
||||||
|
StackTraceElement[] fullStackTrace = new Throwable().getStackTrace();
|
||||||
|
if (index < fullStackTrace.length) {
|
||||||
|
return fullStackTrace[index];
|
||||||
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user