mirror of
https://github.com/filoghost/HolographicDisplays.git
synced 2024-12-19 23:37:33 +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.util.ConsoleLogger;
|
||||
import com.gmail.filoghost.holographicdisplays.util.NMSVersion;
|
||||
import com.gmail.filoghost.holographicdisplays.util.Utils;
|
||||
import com.gmail.filoghost.holographicdisplays.util.VersionUtils;
|
||||
|
||||
public class HolographicDisplays extends JavaPlugin {
|
||||
@ -161,7 +162,7 @@ public class HolographicDisplays extends JavaPlugin {
|
||||
if (requiredVersionError == null) {
|
||||
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
|
||||
ConsoleLogger.log(Level.INFO, "Found ProtocolLib, using new version.");
|
||||
protocolLibHook = new com.gmail.filoghost.holographicdisplays.bridge.protocollib.current.ProtocolLibHookImpl();
|
||||
|
@ -36,6 +36,13 @@
|
||||
<version>1.8-R0.1-SNAPSHOT</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>holographicdisplays-javacompat</artifactId>
|
||||
<version>2.3.0-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
@ -53,15 +53,10 @@ public class Utils extends Object {
|
||||
return new ArrayList<T>();
|
||||
}
|
||||
|
||||
|
||||
public static <T> Set<T> newSet() {
|
||||
return new HashSet<T>();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T[] listToArray(List<T> list) {
|
||||
return (T[]) list.toArray();
|
||||
}
|
||||
|
||||
public static int floor(double num) {
|
||||
int floor = (int) num;
|
||||
@ -107,10 +102,12 @@ public class Utils extends Object {
|
||||
return join(elements, separator, 0, elements.size());
|
||||
}
|
||||
|
||||
|
||||
public static String sanitize(String s) {
|
||||
return s != null ? s : "null";
|
||||
}
|
||||
|
||||
|
||||
public static boolean isThereNonNull(Object... objects) {
|
||||
if (objects == null) {
|
||||
return false;
|
||||
@ -124,4 +121,14 @@ public class Utils extends Object {
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.StackWalker.StackFrame;
|
||||
import java.util.function.Function;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.gmail.filoghost.holographicdisplays.util.ConsoleLogger;
|
||||
import com.gmail.filoghost.holographicdisplays.util.Utils;
|
||||
|
||||
public class ReflectionUtils {
|
||||
|
||||
private static Method getStackTraceElementMethod;
|
||||
private static Method getStackTraceDepthMethod;
|
||||
private static final boolean HAS_JAVA9_STACKWALKER = Utils.classExists("java.lang.StackWalker");
|
||||
|
||||
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],
|
||||
* 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) {
|
||||
try {
|
||||
if (getStackTraceElementMethod == null) {
|
||||
getStackTraceElementMethod = Throwable.class.getDeclaredMethod("getStackTraceElement", int.class);
|
||||
getStackTraceElementMethod.setAccessible(true);
|
||||
}
|
||||
if (getStackTraceDepthMethod == null) {
|
||||
getStackTraceDepthMethod = Throwable.class.getDeclaredMethod("getStackTraceDepth");
|
||||
getStackTraceDepthMethod.setAccessible(true);
|
||||
}
|
||||
public static StackTraceElement getStackTraceElement(final int index) {
|
||||
// Use the faster methods only if there hasn't been any error while executing them previously
|
||||
if (!stackTraceError) {
|
||||
try {
|
||||
if (HAS_JAVA9_STACKWALKER) {
|
||||
// Use the Java 9 StackWalker API
|
||||
StackFrame result = StackWalker.getInstance().walk(new Function<Stream<StackFrame>, StackFrame>() {
|
||||
|
||||
Throwable dummyThrowable = new Throwable();
|
||||
int depth = (Integer) getStackTraceDepthMethod.invoke(dummyThrowable);
|
||||
@Override
|
||||
public StackFrame apply(Stream<StackFrame> stream) {
|
||||
return stream.skip(index).limit(1).findFirst().orElse(null);
|
||||
}
|
||||
|
||||
if (index < depth) {
|
||||
return (StackTraceElement) getStackTraceElementMethod.invoke(new Throwable(), index);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
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);
|
||||
stackTraceErrorPrinted = true;
|
||||
});
|
||||
return result != null ? result.toStackTraceElement() : null;
|
||||
|
||||
} else {
|
||||
// Use reflection to avoid generating the full stacktrace
|
||||
Throwable dummyThrowable = new Throwable();
|
||||
int depth = GET_STACKTRACE_DEPTH_METHOD.invoke(dummyThrowable);
|
||||
|
||||
if (index < depth) {
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user