From 0f196f59c6a4cb76ab8409da62ff1f35505f94a8 Mon Sep 17 00:00:00 2001 From: Dico Karssiens Date: Sun, 11 Nov 2018 14:06:45 +0000 Subject: Changes I made before breaking my local repository. Hoping this works. --- .../src/main/java/io/dico/dicore/BitModifier.java | 364 ++--- .../src/main/java/io/dico/dicore/Formatting.java | 588 ++++---- .../main/java/io/dico/dicore/InterfaceChain.java | 346 ++--- .../java/io/dico/dicore/InventoryEventUtil.java | 240 +-- .../core/src/main/java/io/dico/dicore/Logging.java | 232 +-- .../src/main/java/io/dico/dicore/Reflection.java | 1560 ++++++++++---------- .../java/io/dico/dicore/SetBasedWhitelist.java | 118 +- .../src/main/java/io/dico/dicore/SpigotUtil.java | 816 +++++----- .../src/main/java/io/dico/dicore/StringUtil.java | 946 ++++++------ .../src/main/java/io/dico/dicore/Whitelist.java | 182 +-- .../java/io/dico/dicore/event/ChainedListener.java | 92 +- .../dico/dicore/event/ChainedListenerHandle.java | 110 +- .../dico/dicore/event/ChainedListenerHandles.java | 126 +- .../io/dico/dicore/event/ChainedListeners.java | 112 +- .../java/io/dico/dicore/event/HandlerList.java | 182 +-- .../main/java/io/dico/dicore/event/Listener.java | 34 +- .../java/io/dico/dicore/event/ListenerHandle.java | 18 +- .../java/io/dico/dicore/event/SimpleListener.java | 14 +- .../dico/dicore/exceptions/ExceptionHandler.java | 406 ++--- .../checkedfunctions/CheckedBiConsumer.java | 138 +- .../checkedfunctions/CheckedBiFunction.java | 152 +- .../checkedfunctions/CheckedConsumer.java | 134 +- .../checkedfunctions/CheckedFunction.java | 148 +- .../checkedfunctions/CheckedFunctionalObject.java | 170 +-- .../checkedfunctions/CheckedRunnable.java | 124 +- .../checkedfunctions/CheckedSupplier.java | 140 +- .../main/java/io/dico/dicore/task/BaseTask.java | 216 +-- .../java/io/dico/dicore/task/IteratorTask.java | 240 +-- .../main/java/io/dico/dicore/task/VoidTask.java | 38 +- 29 files changed, 3993 insertions(+), 3993 deletions(-) (limited to 'dicore3/core/src/main/java/io/dico') diff --git a/dicore3/core/src/main/java/io/dico/dicore/BitModifier.java b/dicore3/core/src/main/java/io/dico/dicore/BitModifier.java index e4facb1..ae25123 100644 --- a/dicore3/core/src/main/java/io/dico/dicore/BitModifier.java +++ b/dicore3/core/src/main/java/io/dico/dicore/BitModifier.java @@ -1,182 +1,182 @@ -package io.dico.dicore; - -public interface BitModifier { - - long mask(); - - long get(long x); - - long set(long x, long value); - - default int lowerBound() { - return Long.numberOfTrailingZeros(mask()); - } - - default int upperBound() { - return 64 - Long.numberOfLeadingZeros(mask()); - } - - default int bitCount() { - return Long.bitCount(mask()); - } - - default boolean getBoolean(long x) { - return get(x) == 1; - } - - default long setBoolean(long x, boolean value) { - return set(x, value ? 1 : 0); - } - - default int getInt(long x) { - return (int) (get(x) & 0xFFFFFFFFL); - } - - default long setInt(long x, int value) { - return set(x, value & 0xFFFFFFFFL); - } - - default short getShort(long x) { - return (short) (get(x) & 0xFFFFL); - } - - default long setShort(long x, int value) { - return set(x, value & 0xFFFFL); - } - - default byte getByte(long x) { - return (byte) (get(x) & 0xFFL); - } - - default long setByte(long x, int value) { - return set(x, value & 0xFFL); - } - - final class OfSingle implements BitModifier { - private final long mask; - - public OfSingle(int bit) { - if (bit < 0 || bit >= 64) { - throw new IndexOutOfBoundsException(); - } - this.mask = 1L << bit; - } - - @Override - public int bitCount() { - return 1; - } - - @Override - public long mask() { - return mask; - } - - public boolean getBoolean(long x) { - return (x & mask) != 0; - } - - public long setBoolean(long x, boolean value) { - return value ? (x | mask) : (x & ~mask); - } - - @Override - public long get(long x) { - return getBoolean(x) ? 1 : 0; - } - - @Override - public long set(long x, long value) { - if (value < 0 || value > 1) { - throw new IllegalArgumentException(); - } - return setBoolean(x, value == 1); - } - } - - final class OfMultiple implements BitModifier { - private final int lowerBound; - private final int bitCount; - private final long mask; - - public OfMultiple(int lowerBound, int bitCount) { - int upperBound = lowerBound + bitCount; - if (lowerBound < 0 || lowerBound >= 64 || upperBound < 1 || upperBound > 64 || upperBound < lowerBound) { - throw new IndexOutOfBoundsException(); - } - this.lowerBound = lowerBound; - this.bitCount = bitCount; - this.mask = (Long.MIN_VALUE >> (bitCount - 1)) >>> (64 - bitCount - lowerBound); - } - - @Override - public int lowerBound() { - return lowerBound; - } - - @Override - public int bitCount() { - return bitCount; - } - - @Override - public int upperBound() { - return lowerBound + bitCount; - } - - @Override - public long mask() { - return mask; - } - - @Override - public long get(long x) { - return (x & mask) >>> lowerBound; - } - - @Override - public long set(long x, long value) { - return (x & ~mask) | ((value << lowerBound) & mask); - } - - } - - class Builder { - int currentIndex; - - public int getCurrentIndex() { - return currentIndex; - } - - public int getRemaining() { - return 64 - currentIndex; - } - - public OfSingle single() { - checkAvailable(1); - return new OfSingle(currentIndex++); - } - - public BitModifier size(int size) { - if (size == 1) { - return single(); - } - checkAvailable(size); - BitModifier result = new OfMultiple(currentIndex, size); - currentIndex += size; - return result; - } - - public BitModifier remaining() { - return size(getRemaining()); - } - - private void checkAvailable(int size) { - if (size <= 0 || currentIndex + size > 64) { - throw new IllegalStateException("Exceeding bit count of a long"); - } - } - - } - -} +package io.dico.dicore; + +public interface BitModifier { + + long mask(); + + long get(long x); + + long set(long x, long value); + + default int lowerBound() { + return Long.numberOfTrailingZeros(mask()); + } + + default int upperBound() { + return 64 - Long.numberOfLeadingZeros(mask()); + } + + default int bitCount() { + return Long.bitCount(mask()); + } + + default boolean getBoolean(long x) { + return get(x) == 1; + } + + default long setBoolean(long x, boolean value) { + return set(x, value ? 1 : 0); + } + + default int getInt(long x) { + return (int) (get(x) & 0xFFFFFFFFL); + } + + default long setInt(long x, int value) { + return set(x, value & 0xFFFFFFFFL); + } + + default short getShort(long x) { + return (short) (get(x) & 0xFFFFL); + } + + default long setShort(long x, int value) { + return set(x, value & 0xFFFFL); + } + + default byte getByte(long x) { + return (byte) (get(x) & 0xFFL); + } + + default long setByte(long x, int value) { + return set(x, value & 0xFFL); + } + + final class OfSingle implements BitModifier { + private final long mask; + + public OfSingle(int bit) { + if (bit < 0 || bit >= 64) { + throw new IndexOutOfBoundsException(); + } + this.mask = 1L << bit; + } + + @Override + public int bitCount() { + return 1; + } + + @Override + public long mask() { + return mask; + } + + public boolean getBoolean(long x) { + return (x & mask) != 0; + } + + public long setBoolean(long x, boolean value) { + return value ? (x | mask) : (x & ~mask); + } + + @Override + public long get(long x) { + return getBoolean(x) ? 1 : 0; + } + + @Override + public long set(long x, long value) { + if (value < 0 || value > 1) { + throw new IllegalArgumentException(); + } + return setBoolean(x, value == 1); + } + } + + final class OfMultiple implements BitModifier { + private final int lowerBound; + private final int bitCount; + private final long mask; + + public OfMultiple(int lowerBound, int bitCount) { + int upperBound = lowerBound + bitCount; + if (lowerBound < 0 || lowerBound >= 64 || upperBound < 1 || upperBound > 64 || upperBound < lowerBound) { + throw new IndexOutOfBoundsException(); + } + this.lowerBound = lowerBound; + this.bitCount = bitCount; + this.mask = (Long.MIN_VALUE >> (bitCount - 1)) >>> (64 - bitCount - lowerBound); + } + + @Override + public int lowerBound() { + return lowerBound; + } + + @Override + public int bitCount() { + return bitCount; + } + + @Override + public int upperBound() { + return lowerBound + bitCount; + } + + @Override + public long mask() { + return mask; + } + + @Override + public long get(long x) { + return (x & mask) >>> lowerBound; + } + + @Override + public long set(long x, long value) { + return (x & ~mask) | ((value << lowerBound) & mask); + } + + } + + class Builder { + int currentIndex; + + public int getCurrentIndex() { + return currentIndex; + } + + public int getRemaining() { + return 64 - currentIndex; + } + + public OfSingle single() { + checkAvailable(1); + return new OfSingle(currentIndex++); + } + + public BitModifier size(int size) { + if (size == 1) { + return single(); + } + checkAvailable(size); + BitModifier result = new OfMultiple(currentIndex, size); + currentIndex += size; + return result; + } + + public BitModifier remaining() { + return size(getRemaining()); + } + + private void checkAvailable(int size) { + if (size <= 0 || currentIndex + size > 64) { + throw new IllegalStateException("Exceeding bit count of a long"); + } + } + + } + +} diff --git a/dicore3/core/src/main/java/io/dico/dicore/Formatting.java b/dicore3/core/src/main/java/io/dico/dicore/Formatting.java index 9fdfe0e..40afb9b 100644 --- a/dicore3/core/src/main/java/io/dico/dicore/Formatting.java +++ b/dicore3/core/src/main/java/io/dico/dicore/Formatting.java @@ -1,295 +1,295 @@ -/* - * Copyright (c) 2017 ProjectOreville - * - * All rights reserved. - * - * Author(s): - * Dico Karssiens - */ - -package io.dico.dicore; - -import org.jetbrains.annotations.NotNull; - -public final class Formatting implements CharSequence { - public static final char FORMAT_CHAR = '\u00a7'; - private static final String CACHED_CHARS = "0123456789abcdefklmnor"; - private static final Formatting[] singleCharInstances = new Formatting[CACHED_CHARS.length()]; - - @NotNull - public static final Formatting - BLACK = from('0'), - DARK_BLUE = from('1'), - DARL_GREEN = from('2'), - CYAN = from('3'), - DARK_RED = from('4'), - PURPLE = from('5'), - ORANGE = from('6'), - GRAY = from('7'), - DARK_GRAY = from('8'), - BLUE = from('9'), - GREEN = from('a'), - AQUA = from('b'), - RED = from('c'), - PINK = from('d'), - YELLOW = from('e'), - WHITE = from('f'), - BOLD = from('l'), - STRIKETHROUGH = from('m'), - UNDERLINE = from('n'), - ITALIC = from('o'), - MAGIC = from('k'), - RESET = from('r'), - EMPTY = from('\0'); - - public static String stripAll(String value) { - return stripAll(FORMAT_CHAR, value); - } - - public static String stripAll(char alternateChar, String value) { - int index = value.indexOf(alternateChar); - int max; - if (index == -1 || index == (max = value.length() - 1)) { - return value; - } - - StringBuilder result = new StringBuilder(); - int from = 0; - do { - if (isRecognizedChar(value.charAt(index + 1))) { - result.append(value, from, index); - from = index + 2; - } else { - result.append(value, from, from = index + 2); - } - - index = value.indexOf(alternateChar, index + 1); - } while (index != -1 && index != max && from <= max); - - if (from <= max) { - result.append(value, from, value.length()); - } - return result.toString(); - } - - public static String stripFirst(String value) { - return stripFirst(FORMAT_CHAR, value); - } - - public static String stripFirst(char alternateChar, String value) { - int index = value.indexOf(alternateChar); - int max; - if (index == -1 || index == (max = value.length() - 1)) { - return value; - } - - StringBuilder result = new StringBuilder(value.length()); - int from = 0; - if (isRecognizedChar(value.charAt(index + 1))) { - result.append(value, from, index); - from = index + 2; - } else { - result.append(value, from, from = index + 2); - } - - if (from < max) { - result.append(value, from, value.length()); - } - return result.toString(); - } - - public static Formatting from(char c) { - if (isRecognizedChar(c)) { - c = Character.toLowerCase(c); - int index = CACHED_CHARS.indexOf(c); - if (index == -1) return EMPTY; - - Formatting res = singleCharInstances[index]; - if (res == null) { - singleCharInstances[index] = res = new Formatting(c); - } - return res; - } - return EMPTY; - } - - public static Formatting from(String chars) { - return chars.length() == 1 ? from(chars.charAt(0)) : getFormats(chars, '\0'); - } - - public static Formatting getFormats(String input) { - return getFormats(input, FORMAT_CHAR); - } - - public static Formatting getFormats(String input, char formatChar) { - return getFormats(input, 0, input.length(), formatChar); - } - - public static Formatting getFormats(String input, int start, int end, char formatChar) { - if ((start < 0) || (start > end) || (end > input.length())) { - throw new IndexOutOfBoundsException("start " + start + ", end " + end + ", input.length() " + input.length()); - } - - boolean needsFormatChar = formatChar != '\0'; - char[] formats = new char[6]; - // just make sure it's not the same as formatChar - char previous = (char) (formatChar + 1); - - for (int i = start; i < end; i++) { - char c = input.charAt(i); - - if (previous == formatChar || !needsFormatChar) { - if (isColourChar(c) || isResetChar(c)) { - formats = new char[6]; - formats[0] = Character.toLowerCase(c); - } else if (isFormatChar(c)) { - char format = Character.toLowerCase(c); - for (int j = 0; j < 6; j++) { - if (formats[j] == '\0') { - formats[j] = format; - break; - } else if (formats[j] == format) { - break; - } - } - } - } - - previous = c; - } - - return formats[1] == '\0' ? from(formats[0]) : new Formatting(formats); - } - - public static String translate(String input) { - return translateChars('&', input); - } - - public static String translateChars(char alternateChar, String input) { - return translateFormat(alternateChar, FORMAT_CHAR, input); - } - - public static String revert(String input) { - return revertChars('&', input); - } - - public static String revertChars(char alternateChar, String input) { - return translateFormat(FORMAT_CHAR, alternateChar, input); - } - - public static String translateFormat(char fromChar, char toChar, String input) { - if (input == null) { - return null; - } - int n = input.length(); - if (n < 2) { - return input; - } - char[] result = null; - char previous = input.charAt(0); - for (int i = 1; i < n; i++) { - char c = input.charAt(i); - if (previous == fromChar && isRecognizedChar(c)) { - if (result == null) { - result = input.toCharArray(); - } - result[i - 1] = toChar; - } - previous = c; - } - return result == null ? input : String.valueOf(result); - } - - public static void translate(StringBuilder input) { - translateChars('&', input); - } - - public static void translateChars(char alternateChar, StringBuilder input) { - translateFormat(alternateChar, FORMAT_CHAR, input); - } - - public static void revert(StringBuilder input) { - revertChars('&', input); - } - - public static void revertChars(char alternateChar, StringBuilder input) { - translateFormat(FORMAT_CHAR, alternateChar, input); - } - - public static void translateFormat(char fromChar, char toChar, StringBuilder input) { - if (input == null) { - return; - } - int n = input.length(); - if (n < 2) { - return; - } - char previous = input.charAt(0); - for (int i = 1; i < n; i++) { - char c = input.charAt(i); - if (previous == fromChar && isRecognizedChar(c)) { - input.setCharAt(i -1, toChar); - } - previous = c; - } - } - - private static boolean isRecognizedChar(char c) { - return isColourChar(c) || isFormatChar(c) || isResetChar(c); - } - - private static boolean isColourChar(char c) { - return "0123456789abcdefABCDEF".indexOf(c) >= 0; - } - - private static boolean isResetChar(char c) { - return c == 'r' || c == 'R'; - } - - private static boolean isFormatChar(char c) { - return "klmnoKLMNO".indexOf(c) >= 0; - } - - private final String format; - - private Formatting(char[] formats) { - StringBuilder format = new StringBuilder(12); - for (char c : formats) { - if (c != '\0') { - format.append(FORMAT_CHAR).append(c); - } else { - break; - } - } - this.format = format.toString(); - } - - private Formatting(char c) { - this.format = (c != '\0') ? String.valueOf(new char[]{FORMAT_CHAR, c}) : ""; - } - - @Override - public int length() { - return format.length(); - } - - @Override - public char charAt(int index) { - return format.charAt(index); - } - - @Override - public String subSequence(int start, int end) { - return format.substring(start, end); - } - - @Override - public String toString() { - return format; - } - - public String toString(char formatChar) { - return format.replace(FORMAT_CHAR, formatChar); - } - +/* + * Copyright (c) 2017 ProjectOreville + * + * All rights reserved. + * + * Author(s): + * Dico Karssiens + */ + +package io.dico.dicore; + +import org.jetbrains.annotations.NotNull; + +public final class Formatting implements CharSequence { + public static final char FORMAT_CHAR = '\u00a7'; + private static final String CACHED_CHARS = "0123456789abcdefklmnor"; + private static final Formatting[] singleCharInstances = new Formatting[CACHED_CHARS.length()]; + + @NotNull + public static final Formatting + BLACK = from('0'), + DARK_BLUE = from('1'), + DARL_GREEN = from('2'), + CYAN = from('3'), + DARK_RED = from('4'), + PURPLE = from('5'), + ORANGE = from('6'), + GRAY = from('7'), + DARK_GRAY = from('8'), + BLUE = from('9'), + GREEN = from('a'), + AQUA = from('b'), + RED = from('c'), + PINK = from('d'), + YELLOW = from('e'), + WHITE = from('f'), + BOLD = from('l'), + STRIKETHROUGH = from('m'), + UNDERLINE = from('n'), + ITALIC = from('o'), + MAGIC = from('k'), + RESET = from('r'), + EMPTY = from('\0'); + + public static String stripAll(String value) { + return stripAll(FORMAT_CHAR, value); + } + + public static String stripAll(char alternateChar, String value) { + int index = value.indexOf(alternateChar); + int max; + if (index == -1 || index == (max = value.length() - 1)) { + return value; + } + + StringBuilder result = new StringBuilder(); + int from = 0; + do { + if (isRecognizedChar(value.charAt(index + 1))) { + result.append(value, from, index); + from = index + 2; + } else { + result.append(value, from, from = index + 2); + } + + index = value.indexOf(alternateChar, index + 1); + } while (index != -1 && index != max && from <= max); + + if (from <= max) { + result.append(value, from, value.length()); + } + return result.toString(); + } + + public static String stripFirst(String value) { + return stripFirst(FORMAT_CHAR, value); + } + + public static String stripFirst(char alternateChar, String value) { + int index = value.indexOf(alternateChar); + int max; + if (index == -1 || index == (max = value.length() - 1)) { + return value; + } + + StringBuilder result = new StringBuilder(value.length()); + int from = 0; + if (isRecognizedChar(value.charAt(index + 1))) { + result.append(value, from, index); + from = index + 2; + } else { + result.append(value, from, from = index + 2); + } + + if (from < max) { + result.append(value, from, value.length()); + } + return result.toString(); + } + + public static Formatting from(char c) { + if (isRecognizedChar(c)) { + c = Character.toLowerCase(c); + int index = CACHED_CHARS.indexOf(c); + if (index == -1) return EMPTY; + + Formatting res = singleCharInstances[index]; + if (res == null) { + singleCharInstances[index] = res = new Formatting(c); + } + return res; + } + return EMPTY; + } + + public static Formatting from(String chars) { + return chars.length() == 1 ? from(chars.charAt(0)) : getFormats(chars, '\0'); + } + + public static Formatting getFormats(String input) { + return getFormats(input, FORMAT_CHAR); + } + + public static Formatting getFormats(String input, char formatChar) { + return getFormats(input, 0, input.length(), formatChar); + } + + public static Formatting getFormats(String input, int start, int end, char formatChar) { + if ((start < 0) || (start > end) || (end > input.length())) { + throw new IndexOutOfBoundsException("start " + start + ", end " + end + ", input.length() " + input.length()); + } + + boolean needsFormatChar = formatChar != '\0'; + char[] formats = new char[6]; + // just make sure it's not the same as formatChar + char previous = (char) (formatChar + 1); + + for (int i = start; i < end; i++) { + char c = input.charAt(i); + + if (previous == formatChar || !needsFormatChar) { + if (isColourChar(c) || isResetChar(c)) { + formats = new char[6]; + formats[0] = Character.toLowerCase(c); + } else if (isFormatChar(c)) { + char format = Character.toLowerCase(c); + for (int j = 0; j < 6; j++) { + if (formats[j] == '\0') { + formats[j] = format; + break; + } else if (formats[j] == format) { + break; + } + } + } + } + + previous = c; + } + + return formats[1] == '\0' ? from(formats[0]) : new Formatting(formats); + } + + public static String translate(String input) { + return translateChars('&', input); + } + + public static String translateChars(char alternateChar, String input) { + return translateFormat(alternateChar, FORMAT_CHAR, input); + } + + public static String revert(String input) { + return revertChars('&', input); + } + + public static String revertChars(char alternateChar, String input) { + return translateFormat(FORMAT_CHAR, alternateChar, input); + } + + public static String translateFormat(char fromChar, char toChar, String input) { + if (input == null) { + return null; + } + int n = input.length(); + if (n < 2) { + return input; + } + char[] result = null; + char previous = input.charAt(0); + for (int i = 1; i < n; i++) { + char c = input.charAt(i); + if (previous == fromChar && isRecognizedChar(c)) { + if (result == null) { + result = input.toCharArray(); + } + result[i - 1] = toChar; + } + previous = c; + } + return result == null ? input : String.valueOf(result); + } + + public static void translate(StringBuilder input) { + translateChars('&', input); + } + + public static void translateChars(char alternateChar, StringBuilder input) { + translateFormat(alternateChar, FORMAT_CHAR, input); + } + + public static void revert(StringBuilder input) { + revertChars('&', input); + } + + public static void revertChars(char alternateChar, StringBuilder input) { + translateFormat(FORMAT_CHAR, alternateChar, input); + } + + public static void translateFormat(char fromChar, char toChar, StringBuilder input) { + if (input == null) { + return; + } + int n = input.length(); + if (n < 2) { + return; + } + char previous = input.charAt(0); + for (int i = 1; i < n; i++) { + char c = input.charAt(i); + if (previous == fromChar && isRecognizedChar(c)) { + input.setCharAt(i -1, toChar); + } + previous = c; + } + } + + private static boolean isRecognizedChar(char c) { + return isColourChar(c) || isFormatChar(c) || isResetChar(c); + } + + private static boolean isColourChar(char c) { + return "0123456789abcdefABCDEF".indexOf(c) >= 0; + } + + private static boolean isResetChar(char c) { + return c == 'r' || c == 'R'; + } + + private static boolean isFormatChar(char c) { + return "klmnoKLMNO".indexOf(c) >= 0; + } + + private final String format; + + private Formatting(char[] formats) { + StringBuilder format = new StringBuilder(12); + for (char c : formats) { + if (c != '\0') { + format.append(FORMAT_CHAR).append(c); + } else { + break; + } + } + this.format = format.toString(); + } + + private Formatting(char c) { + this.format = (c != '\0') ? String.valueOf(new char[]{FORMAT_CHAR, c}) : ""; + } + + @Override + public int length() { + return format.length(); + } + + @Override + public char charAt(int index) { + return format.charAt(index); + } + + @Override + public String subSequence(int start, int end) { + return format.substring(start, end); + } + + @Override + public String toString() { + return format; + } + + public String toString(char formatChar) { + return format.replace(FORMAT_CHAR, formatChar); + } + } \ No newline at end of file diff --git a/dicore3/core/src/main/java/io/dico/dicore/InterfaceChain.java b/dicore3/core/src/main/java/io/dico/dicore/InterfaceChain.java index b59979a..f92da6b 100644 --- a/dicore3/core/src/main/java/io/dico/dicore/InterfaceChain.java +++ b/dicore3/core/src/main/java/io/dico/dicore/InterfaceChain.java @@ -1,173 +1,173 @@ -package io.dico.dicore; - -/** - * A chainable object - *

- * It is not possible to declare another upper bound for type parameter Subtype. - * However, it is required that it also extends the type parameter Element. - * - * @param the interface that is chainable - * @param the element of the chain, this is a supertype of the subtype - */ -@SuppressWarnings("unchecked") -public interface InterfaceChain> { - - /** - * returns the empty InterfaceChain instance. - * - * @return the empty InterfaceChain instance - */ - Subtype getEmptyInstance(); - - /** - * returns a InterfaceChain with the last added element detached. - *

- * if this InterfaceChain is the empty instance, the empty instance is returned. - * - * @return a InterfaceChain with the last added element detached - * @implNote for the purpose of lambdas, the default implementation also returns the empty instance. - */ - default Subtype withoutLastNode() { - return getEmptyInstance(); - } - - /** - * returns the element that was inserted as the last element - *

- * For instance, calling this method on the result of calling {@link InterfaceChain#withElement(Object)} - * would return the given element. - * - * @return the element that was inserted as the last element - * @implNote for the purpose of lambdas, the default implementation returns this object, - * which is required to implement the Element type parameter. - */ - default Element getDelegateOfLastNode() { - //noinspection unchecked - return (Element) this; - } - - /** - * @return The number of elements chained from this InterfaceChain. - * @implNote for the purpose of lambdas, the default implementation returns 1. - */ - default int getElementCount() { - return 1; - } - - /** - * Get a new InterfaceChain that includes the given Element. - *

- * The default implementation of the Subtype should look like this: - *

 {@code
-     * if (element == null) {
-     *     return this;
-     * }
-     *
-     * int count = getElementCount() + 1;
-     * return new Subtype() {
-     *     \@Override
-     *     public void exampleElementMethod() {
-     *         try {
-     *             Subtype.this.exampleElementMethod();
-     *         } finally {
-     *             element.exampleElementMethod();
-     *         }
-     *     }
-     *
-     *     \@Override
-     *     public Subtype withoutLastNode() {
-     *         return Subtype.this;
-     *     }
-     *
-     *     \@Override
-     *     public Element getDelegateOfLastNode() {
-     *         return element;
-     *     }
-     *
-     *     \@Override
-     *     public int getElementCount() {
-     *         return count;
-     *     }
-     * };
-     * }
-     * 
- * - * @param element A new element to insert at the end of this InterfaceChain. - * @return a new InterfaceChain that includes the given Element. - */ - Subtype withElement(Element element); - - /** - * Append each of the elements to this InterfaceChain - * - * @param elements the elements to append - * @return a new InterfaceChain with the elements appended - */ - default Subtype withElements(Element... elements) { - Subtype result = (Subtype) this; - for (Element element : elements) { - result = result.withElement(element); - } - return result; - } - - /* - Example Subtypes implementation - - public class Subtypes { - - private Subtypes() { - - } - - private static final Subtype empty = new Subtype() { - @Override - public void exampleElementMethod() { - - } - - @Override - public Subtype withElement(Element other) { - return Subtypes.singleton(other); - } - - @Override - public int getElementCount() { - return 0; - } - - @Override - public Element getDelegateOfLastNode() { - return null; - } - }; - - public static Subtype empty() { - return empty; - } - - public static Subtype singleton(Element element) { - if (element instanceof Subtype) { - return (Subtype) element; - } - if (element == null) { - return empty(); - } - return new Subtype() { - @Override - public void exampleElementMethod() { - element.exampleElementMethod(); - } - - @Override - public Element getDelegateOfLastNode() { - return element; - } - }; - } - - } - - */ - -} +package io.dico.dicore; + +/** + * A chainable object + *

+ * It is not possible to declare another upper bound for type parameter Subtype. + * However, it is required that it also extends the type parameter Element. + * + * @param the interface that is chainable + * @param the element of the chain, this is a supertype of the subtype + */ +@SuppressWarnings("unchecked") +public interface InterfaceChain> { + + /** + * returns the empty InterfaceChain instance. + * + * @return the empty InterfaceChain instance + */ + Subtype getEmptyInstance(); + + /** + * returns a InterfaceChain with the last added element detached. + *

+ * if this InterfaceChain is the empty instance, the empty instance is returned. + * + * @return a InterfaceChain with the last added element detached + * @implNote for the purpose of lambdas, the default implementation also returns the empty instance. + */ + default Subtype withoutLastNode() { + return getEmptyInstance(); + } + + /** + * returns the element that was inserted as the last element + *

+ * For instance, calling this method on the result of calling {@link InterfaceChain#withElement(Object)} + * would return the given element. + * + * @return the element that was inserted as the last element + * @implNote for the purpose of lambdas, the default implementation returns this object, + * which is required to implement the Element type parameter. + */ + default Element getDelegateOfLastNode() { + //noinspection unchecked + return (Element) this; + } + + /** + * @return The number of elements chained from this InterfaceChain. + * @implNote for the purpose of lambdas, the default implementation returns 1. + */ + default int getElementCount() { + return 1; + } + + /** + * Get a new InterfaceChain that includes the given Element. + *

+ * The default implementation of the Subtype should look like this: + *

 {@code
+     * if (element == null) {
+     *     return this;
+     * }
+     *
+     * int count = getElementCount() + 1;
+     * return new Subtype() {
+     *     \@Override
+     *     public void exampleElementMethod() {
+     *         try {
+     *             Subtype.this.exampleElementMethod();
+     *         } finally {
+     *             element.exampleElementMethod();
+     *         }
+     *     }
+     *
+     *     \@Override
+     *     public Subtype withoutLastNode() {
+     *         return Subtype.this;
+     *     }
+     *
+     *     \@Override
+     *     public Element getDelegateOfLastNode() {
+     *         return element;
+     *     }
+     *
+     *     \@Override
+     *     public int getElementCount() {
+     *         return count;
+     *     }
+     * };
+     * }
+     * 
+ * + * @param element A new element to insert at the end of this InterfaceChain. + * @return a new InterfaceChain that includes the given Element. + */ + Subtype withElement(Element element); + + /** + * Append each of the elements to this InterfaceChain + * + * @param elements the elements to append + * @return a new InterfaceChain with the elements appended + */ + default Subtype withElements(Element... elements) { + Subtype result = (Subtype) this; + for (Element element : elements) { + result = result.withElement(element); + } + return result; + } + + /* + Example Subtypes implementation + + public class Subtypes { + + private Subtypes() { + + } + + private static final Subtype empty = new Subtype() { + @Override + public void exampleElementMethod() { + + } + + @Override + public Subtype withElement(Element other) { + return Subtypes.singleton(other); + } + + @Override + public int getElementCount() { + return 0; + } + + @Override + public Element getDelegateOfLastNode() { + return null; + } + }; + + public static Subtype empty() { + return empty; + } + + public static Subtype singleton(Element element) { + if (element instanceof Subtype) { + return (Subtype) element; + } + if (element == null) { + return empty(); + } + return new Subtype() { + @Override + public void exampleElementMethod() { + element.exampleElementMethod(); + } + + @Override + public Element getDelegateOfLastNode() { + return element; + } + }; + } + + } + + */ + +} diff --git a/dicore3/core/src/main/java/io/dico/dicore/InventoryEventUtil.java b/dicore3/core/src/main/java/io/dico/dicore/InventoryEventUtil.java index 5c19848..3be2179 100644 --- a/dicore3/core/src/main/java/io/dico/dicore/InventoryEventUtil.java +++ b/dicore3/core/src/main/java/io/dico/dicore/InventoryEventUtil.java @@ -1,120 +1,120 @@ -package io.dico.dicore; - -import org.bukkit.Material; -import org.bukkit.event.inventory.InventoryClickEvent; -import org.bukkit.inventory.Inventory; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.PlayerInventory; - -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.Map; - -public class InventoryEventUtil { - - private InventoryEventUtil() { - - } - - public static ItemStack getNewItem(InventoryClickEvent event) { - Inventory clicked = event.getInventory(); - switch (event.getAction()) { - case SWAP_WITH_CURSOR: - case PLACE_ALL: - return event.getCursor(); - case PICKUP_ALL: - case HOTBAR_MOVE_AND_READD: - case MOVE_TO_OTHER_INVENTORY: - case DROP_ALL_SLOT: - case COLLECT_TO_CURSOR: - return null; - case PICKUP_HALF: - case PICKUP_SOME: - ItemStack item = clicked.getItem(event.getSlot()).clone(); - item.setAmount(item.getAmount() / 2); - return item; - case PICKUP_ONE: - case DROP_ONE_SLOT: - item = clicked.getItem(event.getSlot()).clone(); - item.setAmount(Math.max(0, item.getAmount() - 1)); - return item; - case PLACE_ONE: - item = event.getView().getCursor().clone(); - item.setAmount(1); - return item; - case PLACE_SOME: - item = event.getView().getCursor().clone(); - item.setAmount(item.getAmount() / 2); - return item; - case HOTBAR_SWAP: - return event.getView().getBottomInventory().getItem(event.getHotbarButton()); - default: - return clicked.getItem(event.getSlot()); - } - } - - - public static Map deduceChangesIfItemAdded(Inventory inventory, ItemStack added, boolean computeNewItem) { - int addedAmount = added.getAmount(); - Map rv = Collections.emptyMap(); - - for (int n = inventory.getSize(), i = 0; i < n; i++) { - if (addedAmount <= 0) break; - - ItemStack current = inventory.getItem(i); - if (current == null || current.getType() == Material.AIR || current.isSimilar(added)) { - int count = current == null ? 0 : current.getAmount(); - int max = (current == null ? added : current).getType().getMaxStackSize(); - if (count < max) { - int diff = max - count; - if (diff > addedAmount) { - diff = addedAmount; - } - addedAmount -= diff; - - if (rv.isEmpty()) rv = new LinkedHashMap<>(); - - if (computeNewItem) { - current = (current == null ? added : current).clone(); - current.setAmount(count + diff); - rv.put(i, current); - } else { - rv.put(i, null); - } - } - } - } - - return rv; - } - - - public static ItemStack getNewHeldItemIfPickedUp(PlayerInventory inventory, ItemStack added) { - int heldItemSlot = inventory.getHeldItemSlot(); - ItemStack heldItem = inventory.getItem(heldItemSlot); - - if (SpigotUtil.isItemPresent(heldItem) && !added.isSimilar(heldItem)) { - return null; - } - - int amt = added.getAmount(); - for (int i = 0; i < heldItemSlot; i++) { - ItemStack item = inventory.getItem(i); - if (!SpigotUtil.isItemPresent(item)) { - return null; - } - if (item.isSimilar(item)) { - amt -= Math.max(0, item.getMaxStackSize() - item.getAmount()); - if (amt <= 0) { - return null; - } - } - } - - added = added.clone(); - added.setAmount(amt + Math.max(0, heldItem == null ? 0 : heldItem.getAmount())); - return added; - } - - -} +package io.dico.dicore; + +import org.bukkit.Material; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; + +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; + +public class InventoryEventUtil { + + private InventoryEventUtil() { + + } + + public static ItemStack getNewItem(InventoryClickEvent event) { + Inventory clicked = event.getInventory(); + switch (event.getAction()) { + case SWAP_WITH_CURSOR: + case PLACE_ALL: + return event.getCursor(); + case PICKUP_ALL: + case HOTBAR_MOVE_AND_READD: + case MOVE_TO_OTHER_INVENTORY: + case DROP_ALL_SLOT: + case COLLECT_TO_CURSOR: + return null; + case PICKUP_HALF: + case PICKUP_SOME: + ItemStack item = clicked.getItem(event.getSlot()).clone(); + item.setAmount(item.getAmount() / 2); + return item; + case PICKUP_ONE: + case DROP_ONE_SLOT: + item = clicked.getItem(event.getSlot()).clone(); + item.setAmount(Math.max(0, item.getAmount() - 1)); + return item; + case PLACE_ONE: + item = event.getView().getCursor().clone(); + item.setAmount(1); + return item; + case PLACE_SOME: + item = event.getView().getCursor().clone(); + item.setAmount(item.getAmount() / 2); + return item; + case HOTBAR_SWAP: + return event.getView().getBottomInventory().getItem(event.getHotbarButton()); + default: + return clicked.getItem(event.getSlot()); + } + } + + + public static Map deduceChangesIfItemAdded(Inventory inventory, ItemStack added, boolean computeNewItem) { + int addedAmount = added.getAmount(); + Map rv = Collections.emptyMap(); + + for (int n = inventory.getSize(), i = 0; i < n; i++) { + if (addedAmount <= 0) break; + + ItemStack current = inventory.getItem(i); + if (current == null || current.getType() == Material.AIR || current.isSimilar(added)) { + int count = current == null ? 0 : current.getAmount(); + int max = (current == null ? added : current).getType().getMaxStackSize(); + if (count < max) { + int diff = max - count; + if (diff > addedAmount) { + diff = addedAmount; + } + addedAmount -= diff; + + if (rv.isEmpty()) rv = new LinkedHashMap<>(); + + if (computeNewItem) { + current = (current == null ? added : current).clone(); + current.setAmount(count + diff); + rv.put(i, current); + } else { + rv.put(i, null); + } + } + } + } + + return rv; + } + + + public static ItemStack getNewHeldItemIfPickedUp(PlayerInventory inventory, ItemStack added) { + int heldItemSlot = inventory.getHeldItemSlot(); + ItemStack heldItem = inventory.getItem(heldItemSlot); + + if (SpigotUtil.isItemPresent(heldItem) && !added.isSimilar(heldItem)) { + return null; + } + + int amt = added.getAmount(); + for (int i = 0; i < heldItemSlot; i++) { + ItemStack item = inventory.getItem(i); + if (!SpigotUtil.isItemPresent(item)) { + return null; + } + if (item.isSimilar(item)) { + amt -= Math.max(0, item.getMaxStackSize() - item.getAmount()); + if (amt <= 0) { + return null; + } + } + } + + added = added.clone(); + added.setAmount(amt + Math.max(0, heldItem == null ? 0 : heldItem.getAmount())); + return added; + } + + +} diff --git a/dicore3/core/src/main/java/io/dico/dicore/Logging.java b/dicore3/core/src/main/java/io/dico/dicore/Logging.java index fa2a676..50c4b52 100644 --- a/dicore3/core/src/main/java/io/dico/dicore/Logging.java +++ b/dicore3/core/src/main/java/io/dico/dicore/Logging.java @@ -1,116 +1,116 @@ -package io.dico.dicore; - -import java.util.logging.Logger; - -public interface Logging { - - void info(Object o); - - void warn(Object o); - - void error(Object o); - - void debug(Object o); - - void setDebugging(boolean debugging); - - boolean isDebugging(); - - class RootLogging implements Logging { - private final String prefix; - private final Logger root; - private boolean debugging; - - public RootLogging(String prefix, Logger root, boolean debugging) { - this.root = root; - this.prefix = prefix; - this.debugging = debugging; - } - - @Override - public void info(Object o) { - root.info(prefix(o)); - } - - @Override - public void warn(Object o) { - root.warning(prefix(o)); - } - - @Override - public void error(Object o) { - root.severe(prefix(o)); - } - - @Override - public void debug(Object o) { - if (debugging) { - root.info(String.format("[DEBUG] %s", prefix(o))); - } - } - - @Override - public boolean isDebugging() { - return debugging; - } - - @Override - public void setDebugging(boolean debugging) { - this.debugging = debugging; - } - - private String prefix(Object o) { - return String.format("[%s] %s", prefix, String.valueOf(o)); - } - } - - class SubLogging implements Logging { - protected String prefix; - private final Logging superLogger; - private boolean debugging; - - public SubLogging(String prefix, Logging superLogger, boolean debugging) { - this.superLogger = superLogger; - this.prefix = prefix; - this.debugging = debugging; - } - - @Override - public void info(Object o) { - superLogger.info(prefix(o)); - } - - @Override - public void warn(Object o) { - superLogger.warn(prefix(o)); - } - - @Override - public void error(Object o) { - superLogger.error(prefix(o)); - } - - @Override - public void debug(Object o) { - if (debugging) { - superLogger.info(String.format("[DEBUG] %s", prefix(o))); - } - } - - @Override - public boolean isDebugging() { - return debugging; - } - - @Override - public void setDebugging(boolean debugging) { - this.debugging = debugging; - } - - private String prefix(Object o) { - return String.format("[%s] %s", prefix, String.valueOf(o)); - } - - } - -} +package io.dico.dicore; + +import java.util.logging.Logger; + +public interface Logging { + + void info(Object o); + + void warn(Object o); + + void error(Object o); + + void debug(Object o); + + void setDebugging(boolean debugging); + + boolean isDebugging(); + + class RootLogging implements Logging { + private final String prefix; + private final Logger root; + private boolean debugging; + + public RootLogging(String prefix, Logger root, boolean debugging) { + this.root = root; + this.prefix = prefix; + this.debugging = debugging; + } + + @Override + public void info(Object o) { + root.info(prefix(o)); + } + + @Override + public void warn(Object o) { + root.warning(prefix(o)); + } + + @Override + public void error(Object o) { + root.severe(prefix(o)); + } + + @Override + public void debug(Object o) { + if (debugging) { + root.info(String.format("[DEBUG] %s", prefix(o))); + } + } + + @Override + public boolean isDebugging() { + return debugging; + } + + @Override + public void setDebugging(boolean debugging) { + this.debugging = debugging; + } + + private String prefix(Object o) { + return String.format("[%s] %s", prefix, String.valueOf(o)); + } + } + + class SubLogging implements Logging { + protected String prefix; + private final Logging superLogger; + private boolean debugging; + + public SubLogging(String prefix, Logging superLogger, boolean debugging) { + this.superLogger = superLogger; + this.prefix = prefix; + this.debugging = debugging; + } + + @Override + public void info(Object o) { + superLogger.info(prefix(o)); + } + + @Override + public void warn(Object o) { + superLogger.warn(prefix(o)); + } + + @Override + public void error(Object o) { + superLogger.error(prefix(o)); + } + + @Override + public void debug(Object o) { + if (debugging) { + superLogger.info(String.format("[DEBUG] %s", prefix(o))); + } + } + + @Override + public boolean isDebugging() { + return debugging; + } + + @Override + public void setDebugging(boolean debugging) { + this.debugging = debugging; + } + + private String prefix(Object o) { + return String.format("[%s] %s", prefix, String.valueOf(o)); + } + + } + +} diff --git a/dicore3/core/src/main/java/io/dico/dicore/Reflection.java b/dicore3/core/src/main/java/io/dico/dicore/Reflection.java index b7b1ed4..2452d75 100644 --- a/dicore3/core/src/main/java/io/dico/dicore/Reflection.java +++ b/dicore3/core/src/main/java/io/dico/dicore/Reflection.java @@ -1,780 +1,780 @@ -package io.dico.dicore; - -import io.dico.dicore.exceptions.ExceptionHandler; - -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.Objects; -import java.util.function.Consumer; - -/** - * Reflective utilities - */ -@SuppressWarnings("unchecked") -public class Reflection { - private static final ExceptionHandler exceptionHandler; - private static final Field fieldModifiersField = restrictedSearchField(Field.class, "modifiers"); - private static Consumer errorTarget; - - private Reflection() { - - } - - static { - exceptionHandler = new ExceptionHandler() { - @Override - public void handle(Throwable ex) { - handleGenericException(ex); - } - - @Override - public Object handleGenericException(Throwable ex, Object... args) { - String action = args.length == 0 || !(args[0] instanceof String) ? "executing a reflective operation" : (String) args[0]; - ExceptionHandler.log(errorTarget, action, ex); - return null; - } - }; - - // don't use method reference here: the current reference in System.out would be cached. - setErrorTarget(msg -> System.out.println(msg)); - } - - /** - * Sets the output where ReflectiveOperationException's and similar are sent. - * This defaults to {@link System#out}. - * - * @param target The new output - * @throws NullPointerException if target is null - */ - public static void setErrorTarget(Consumer target) { - errorTarget = Objects.requireNonNull(target); - } - - /** - * This search modifier tells the implementation that it should subsequently search superclasses for the field/method. - * Using this modifier means a call to {@link #deepSearchField(Class, String)} will be used instead of {@link #restrictedSearchField(Class, String)} - * and a call to {@link #deepSearchMethod(Class, String, Class[])} will be used instead of {@link #restrictedSearchMethod(Class, String, Class[])} - */ - public static final int DEEP_SEARCH = 0x1; - - /** - * This search modifier applies only to fields, and tells the implementation that a final modifier might be present on a found field, and that it should be removed. - */ - public static final int REMOVE_FINAL = 0x2; - - /** - * This search modifier applies only to methods, and tells the implementation that it should completely ignore parameter types and return the first method with a matching name - * The implementation uses {@link Class#getDeclaredMethods()} instead of {@link Class#getDeclaredMethod(String, Class[])} if this modifier is set. - */ - public static final int IGNORE_PARAMS = 0x2; - - /* - ### FIELD METHODS ### - */ - - /** - * Search a field of any accessibility within the class or any of its superclasses. - * The first field with the given name that is found will be returned. - *

- * If a field is found and it is not accessible, this method attempts to make it accessible. - * If a {@link SecurityException} is thrown in the process, that is ignored and the field will be returned nonetheless. - *

- * This method throws IllegalArgumentException if the Field is not found, because, in most cases, that should never happen, - * and it should simplify debugging. In some cases, if you want to know if the field exists, you'll have to use try/catch for that. - * - * @param clazz The lowest class in the ladder to start searching from - * @param fieldName The name of the field - * //@param fieldType the type of the field, or null if it can be any. - * @return The field - * @throws NullPointerException if clazz is null or fieldName is null - * @throws IllegalArgumentException if the field doesn't exist - * @see #restrictedSearchField(Class, String) - */ - public static Field deepSearchField(Class clazz, String fieldName/*, Class fieldType*/) { - Class currentClass = clazz; - Field result; - do { - // throws NPE if class or fieldName is null - result = internalSearchField(clazz, fieldName); - if (result != null) { - return result; - } - currentClass = currentClass.getSuperclass(); - } while (currentClass != null); - - throw new IllegalArgumentException("field not found in " + clazz.getCanonicalName() + " and superclasses: " + fieldName); - } - - /** - * Search a field of any accessibility within the class, but not its superclasses. - *

- * If a field is found and it is not accessible, this method attempts to make it accessible. - * If a {@link SecurityException} is thrown in the process, that is ignored and the field will be returned nonetheless. - *

- * This method throws IllegalArgumentException if the Field is not found, because, in most cases, that should never happen, - * and it should simplify debugging. In some cases, if you want to know if the field exists, you'll have to use try/catch for that. - * - * @param clazz The only class to search for the field - * @param fieldName The name of the field - * @return The field - * @throws NullPointerException if clazz or fieldName is null - * @throws IllegalArgumentException if the field does not exist - */ - public static Field restrictedSearchField(Class clazz, String fieldName) { - Field result = internalSearchField(clazz, fieldName); - if (result == null) { - throw new IllegalArgumentException("field not found in " + clazz.getCanonicalName() + ": " + fieldName); - } - return result; - } - - /** - * Searches for a field using the given search method. - * - * @param modifiers The modifiers for field search. Can have {@link #DEEP_SEARCH} and {@link #REMOVE_FINAL} - * @param clazz The class to search in/from - * @param fieldName Name of the field - * @return The field - * @throws NullPointerException if clazz or fieldName is null - * @throws IllegalArgumentException if the field is not found - */ - public static Field searchField(int modifiers, Class clazz, String fieldName) { - Field result; - if ((modifiers & DEEP_SEARCH) != 0) { - result = deepSearchField(clazz, fieldName); - } else { - result = restrictedSearchField(clazz, fieldName); - } - if ((modifiers & REMOVE_FINAL) != 0) { - removeFinalModifier(result); - } - return result; - } - - /** - * @return The same as {@link #restrictedSearchField(Class, String)}, but returns null instead of throwing IllegalArgumentException - * @see #restrictedSearchField(Class, String) - */ - private static Field internalSearchField(Class clazz, String fieldName) { - Field result; - try { - // throws NullPointerException if either clazz or fieldName are null. - result = clazz.getDeclaredField(fieldName); - } catch (NoSuchFieldException | SecurityException ex) { - return null; - } - - if (!result.isAccessible()) try { - result.setAccessible(true); - } catch (SecurityException ignored) { - - } - - return result; - } - - /** - * Attempts to remove existing final modifier of the given field - * This method should always return true. - * - * @param field The field whose final modifier to remove - * @return true if the field most definitely has no final modifier after this call - * @throws NullPointerException if field is null - */ - public static boolean removeFinalModifier(Field field) { - Objects.requireNonNull(field); - try { - int modifiers = (int) fieldModifiersField.get(field); - if (modifiers != (modifiers &= ~Modifier.FINAL)) { - fieldModifiersField.set(field, modifiers); - } - return true; - } catch (Exception ex) { - return false; - } - } - - /** - * Gets field value of the field named fieldName and the given instance - * To find the field, {@link #deepSearchField(Class, String)} is used (DEEP search method). - *

- * If a {@link ReflectiveOperationException} occurs, this is printed to {@link System#out} - * - * @param instance The instance whose field value to get - * @param fieldName the name of the field - * @param The expected/known field type - * @return The field value - * @throws IllegalArgumentException if the field doesn't exist - * @see #deepSearchField(Class, String) - * @see #getFieldValue(Class, String, Object) - */ - public static T getFieldValue(Object instance, String fieldName) { - return getFieldValue(deepSearchField(instance.getClass(), fieldName), instance); - } - - /** - * Gets field value of the field named fieldName and the given instance - * To find the field, {@link #restrictedSearchField(Class, String)} is used (RESTRICTED search method). - *

- * If a {@link ReflectiveOperationException} occurs, this is printed to {@link System#out} - * - * @param clazz The class to search for the field - * @param instance The instance whose field value to get - * @param fieldName the name of the field - * @param The expected/known field type - * @return The field value - * @throws IllegalArgumentException if the field doesn't exist - * @see #restrictedSearchField(Class, String) - * @see #getFieldValue(Field, Object) - */ - public static T getFieldValue(Class clazz, String fieldName, Object instance) { - return getFieldValue(restrictedSearchField(clazz, fieldName), instance); - } - - /** - * Gets field value of the field named fieldName and the given instance - * To find the field, {@link #searchField(int, Class, String)} is used. - *

- * If a {@link ReflectiveOperationException} occurs, this is printed to {@link System#out} - * - * @param modifiers The modifiers for field search. Can have {@link #DEEP_SEARCH} and {@link #REMOVE_FINAL} - * @param clazz The class to search for the field - * @param instance The instance whose field value to get - * @param fieldName the name of the field - * @param The expected/known field type - * @return The field value - * @throws IllegalArgumentException if the field doesn't exist - * @see #searchField(int, Class, String) - * @see #getFieldValue(Field, Object) - */ - public static T getFieldValue(int modifiers, Class clazz, String fieldName, Object instance) { - return getFieldValue(searchField(modifiers, clazz, fieldName), instance); - } - - /** - * Gets field value of the given field and the given instance - *

- * If a {@link ReflectiveOperationException} occurs, this is printed to {@link System#out} - * - * @param field the field - * @param instance The instance whose field value to get - * @param The expected/known field type - * @return The field value - */ - public static T getFieldValue(Field field, Object instance) { - return exceptionHandler.supplySafe(() -> (T) field.get(instance)); - } - - /** - * Gets static field value of the field named fieldName - * To find the field, {@link #restrictedSearchField(Class, String)} is used (RESTRICTED search method). - *

- * If a {@link ReflectiveOperationException} occurs, this is printed to {@link System#out} - * - * @param clazz The class to search for the field - * @param fieldName the name of the field - * @param The expected/known field type - * @return The field value - * @throws IllegalArgumentException if the field doesn't exist - * @see #restrictedSearchField(Class, String) - * @see #getStaticFieldValue(Field) - */ - public static T getStaticFieldValue(Class clazz, String fieldName) { - return getStaticFieldValue(restrictedSearchField(clazz, fieldName)); - } - - /** - * Gets static field value of the field named fieldName - * To find the field, {@link #searchField(int, Class, String)} is used. - *

- * If a {@link ReflectiveOperationException} occurs, this is printed to {@link System#out} - * - * @param modifiers The modifiers for field search. Can have {@link #DEEP_SEARCH} and {@link #REMOVE_FINAL} - * @param clazz The class to search for the field - * @param fieldName the name of the field - * @param The expected/known field type - * @return The field value - * @throws IllegalArgumentException if the field doesn't exist - * @see #deepSearchField(Class, String) - * @see #getStaticFieldValue(Field) - */ - public static T getStaticFieldValue(int modifiers, Class clazz, String fieldName) { - return getStaticFieldValue(searchField(modifiers, clazz, fieldName)); - } - - /** - * Gets static field value - *

- * If a {@link ReflectiveOperationException} occurs, this is printed to {@link System#out} - *

- * Equivalent to the call {@code getFieldValue(field, (Object) null)} - * - * @param field the field - * @param The expected/known field type - * @return The field value - * @see #getFieldValue(Field, Object) - */ - public static T getStaticFieldValue(Field field) { - return getFieldValue(field, (Object) null); - } - - /** - * Sets field value of the field named fieldName and the given instance - * To find the field, {@link #deepSearchField(Class, String)} is used (DEEP search method). - *

- * If a {@link ReflectiveOperationException} occurs, this is printed to {@link System#out} - * - * @param instance The instance whose field value to set - * @param fieldName the name of the field - * @param newValue the new field value - * @throws IllegalArgumentException if the field doesn't exist - * @see #deepSearchField(Class, String) - * @see #setFieldValue(Class, String, Object, Object) - */ - public static void setFieldValue(Object instance, String fieldName, Object newValue) { - setFieldValue(deepSearchField(instance.getClass(), fieldName), instance, newValue); - } - - /** - * Sets field value of the field named fieldName and the given instance - * To find the field, {@link #restrictedSearchField(Class, String)} is used (RESTRICTED search method). - *

- * If a {@link ReflectiveOperationException} occurs, this is printed to {@link System#out} - * - * @param clazz The class to search for the field - * @param fieldName the name of the field - * @param instance The field owner - * @param newValue The new field value - * @throws IllegalArgumentException if the field doesn't exist - * @see #restrictedSearchField(Class, String) - * @see #setFieldValue(Field, Object, Object) - */ - public static void setFieldValue(Class clazz, String fieldName, Object instance, Object newValue) { - setFieldValue(restrictedSearchField(clazz, fieldName), instance, newValue); - } - - /** - * Sets field value of the field named fieldName and the given instance - * To find the field, {@link #searchField(int, Class, String)} is used. - *

- * If a {@link ReflectiveOperationException} occurs, this is printed to {@link System#out} - * - * @param modifiers The modifiers for field search. Can have {@link #DEEP_SEARCH} and {@link #REMOVE_FINAL} - * @param clazz The class to search for the field - * @param instance The instance whose field value to set - * @param fieldName the name of the field - * @param newValue The new field value - * @throws IllegalArgumentException if the field doesn't exist - * @see #searchField(int, Class, String) - * @see #setFieldValue(Field, Object, Object) - */ - public static void setFieldValue(int modifiers, Class clazz, String fieldName, Object instance, Object newValue) { - setFieldValue(searchField(modifiers, clazz, fieldName), instance, newValue); - } - - /** - * Sets a field value - *

- * If a {@link ReflectiveOperationException} occurs, this is printed to {@link System#out} - * - * @param field The field - * @param instance The field owner - * @param newValue The new field value - */ - public static void setFieldValue(Field field, Object instance, Object newValue) { - exceptionHandler.runSafe(() -> field.set(instance, newValue)); - } - - /** - * Sets static field value of the field name fieldName - * To find the field, {@link #restrictedSearchField(Class, String)} is used (RESTRICTED search method). - *

- * If a {@link ReflectiveOperationException} occurs, this is printed to {@link System#out} - * - * @param clazz The class to search for the field - * @param fieldName the name of the field - * @param newValue The new field value - * @throws IllegalArgumentException if the field doesn't exist - * @see #restrictedSearchField(Class, String) - * @see #setStaticFieldValue(Field, Object) - */ - public static void setStaticFieldValue(Class clazz, String fieldName, Object newValue) { - setStaticFieldValue(restrictedSearchField(clazz, fieldName), newValue); - } - - /** - * Sets static field value of the field named fieldName - * To find the field, {@link #searchField(int, Class, String)} is used. - *

- * If a {@link ReflectiveOperationException} occurs, this is printed to {@link System#out} - * - * @param modifiers The modifiers for field search. Can have {@link #DEEP_SEARCH} and {@link #REMOVE_FINAL} - * @param clazz The class to search for the field - * @param fieldName the name of the field - * @param newValue The new field value - * @throws IllegalArgumentException if the field doesn't exist - * @see #searchField(int, Class, String) - * @see #setStaticFieldValue(Field, Object) - */ - public static void setStaticFieldValue(int modifiers, Class clazz, String fieldName, Object newValue) { - setStaticFieldValue(searchField(modifiers, clazz, fieldName), newValue); - } - - /** - * Sets a static field value - *

- * If a {@link ReflectiveOperationException} occurs, this is printed to {@link System#out} - * - * @param field The field - * @param newValue The new field value - */ - public static void setStaticFieldValue(Field field, Object newValue) { - setFieldValue(field, (Object) null, newValue); - } - - /* - ### METHOD METHODS ### - */ - - /** - * Search a method of any accessibility within the class or any of its superclasses. - * The first method with the given name that is found will be returned. - *

- * If a method is found and it is not accessible, this method attempts to make it accessible. - * If a {@link SecurityException} is thrown in the process, that is ignored and the method will be returned nonetheless. - *

- * This method throws IllegalArgumentException if the Method is not found, because, in most cases, that should never happen, - * and it should simplify debugging. In some cases, if you want to know if the method exists, you'll have to use try/catch for that. - * - * @param clazz The lowest class in the ladder to start searching from - * @param methodName The name of the method - * @param parameterTypes the parameter types of the sought method. - * @return The method - * @throws NullPointerException if clazz is null or methodName is null - * @throws IllegalArgumentException if the method doesn't exist - * @see #restrictedSearchMethod(Class, String, Class[]) - */ - public static Method deepSearchMethod(Class clazz, String methodName, Class... parameterTypes) { - return deepSearchMethod(0, clazz, methodName, parameterTypes); - } - - /** - * Search a method of any accessibility within the class or any of its superclasses. - * The first method with the given name that is found will be returned. - *

- * If a method is found and it is not accessible, this method attempts to make it accessible. - * If a {@link SecurityException} is thrown in the process, that is ignored and the method will be returned nonetheless. - *

- * This method throws IllegalArgumentException if the Method is not found, because, in most cases, that should never happen, - * and it should simplify debugging. In some cases, if you want to know if the method exists, you'll have to use try/catch for that. - * - * @param modifiers The modifiers for method search. Can have {@link #IGNORE_PARAMS} - * @param clazz The lowest class in the ladder to start searching from - * @param methodName The name of the method - * @param parameterTypes the parameter types of the sought method. - * @return The method - * @throws NullPointerException if clazz is null or methodName is null - * @throws IllegalArgumentException if the method doesn't exist - * @see #restrictedSearchMethod(Class, String, Class[]) - */ - public static Method deepSearchMethod(int modifiers, Class clazz, String methodName, Class... parameterTypes) { - Class currentClass = clazz; - Method result; - do { - // throws NPE if class or methodName is null - result = internalSearchMethod(modifiers, currentClass, methodName, parameterTypes); - if (result != null) { - return result; - } - currentClass = currentClass.getSuperclass(); - } while (currentClass != null); - - throw new IllegalArgumentException("method not found in " + clazz.getCanonicalName() + " and superclasses: " + methodName); - } - - /** - * Search a method of any accessibility within the class, but not its superclasses. - *

- * If a method is found and it is not accessible, this method attempts to make it accessible. - * If a {@link SecurityException} is thrown in the process, that is ignored and the method will be returned nonetheless. - *

- * This method throws IllegalArgumentException if the Method is not found, because, in most cases, that should never happen, - * and it should simplify debugging. In some cases, if you want to know if the method exists, you'll have to use try/catch for that. - * - * @param clazz The only class to search for the method - * @param methodName The name of the method - * @param parameterTypes the parameter types of the sought method. - * @return The method - * @throws NullPointerException if clazz or methodName is null - * @throws IllegalArgumentException if the method does not exist - */ - public static Method restrictedSearchMethod(Class clazz, String methodName, Class... parameterTypes) { - return restrictedSearchMethod(0, clazz, methodName, parameterTypes); - } - - /** - * Search a method of any accessibility within the class, but not its superclasses. - *

- * If a method is found and it is not accessible, this method attempts to make it accessible. - * If a {@link SecurityException} is thrown in the process, that is ignored and the method will be returned nonetheless. - *

- * This method throws IllegalArgumentException if the Method is not found, because, in most cases, that should never happen, - * and it should simplify debugging. In some cases, if you want to know if the method exists, you'll have to use try/catch for that. - * - * @param modifiers The modifiers for method search. Can have {@link #IGNORE_PARAMS} - * @param clazz The only class to search for the method - * @param methodName The name of the method - * @param parameterTypes the parameter types of the sought method. - * @return The method - * @throws NullPointerException if clazz or methodName is null - * @throws IllegalArgumentException if the method does not exist - */ - public static Method restrictedSearchMethod(int modifiers, Class clazz, String methodName, Class... parameterTypes) { - Method result = internalSearchMethod(modifiers, clazz, methodName, parameterTypes); - if (result == null) { - throw new IllegalArgumentException("method not found in " + clazz.getCanonicalName() + ": " + methodName); - } - return result; - } - - /** - * Searches for a method using the given search method. - *

- * If a method is found and it is not accessible, this method attempts to make it accessible. - * If a {@link SecurityException} is thrown in the process, that is ignored and the method will be returned nonetheless. - *

- * This method throws IllegalArgumentException if the Method is not found, because, in most cases, that should never happen, - * and it should simplify debugging. In some cases, if you want to know if the method exists, you'll have to use try/catch for that. - * - * @param modifiers The modifiers for method search. Can have {@link #DEEP_SEARCH} and {@link #IGNORE_PARAMS} - * @param clazz The class to search in/from - * @param methodName Name of the method - * @param parameterTypes the parameter types of the sought method. - * @return The method - * @throws NullPointerException if clazz or methodName is null - * @throws IllegalArgumentException if the method is not found - */ - public static Method searchMethod(int modifiers, Class clazz, String methodName, Class... parameterTypes) { - if ((modifiers & DEEP_SEARCH) != 0) { - return deepSearchMethod(modifiers, clazz, methodName, parameterTypes); - } else { - return restrictedSearchMethod(modifiers, clazz, methodName, parameterTypes); - } - } - - /** - * @return The same as {@link #restrictedSearchMethod(Class, String, Class[]) }, but returns null instead of throwing IllegalArgumentException - * @see #restrictedSearchMethod(Class, String, Class[]) - */ - private static Method internalSearchMethod(int modifiers, Class clazz, String methodName, Class... parameterTypes) { - Method result = null; - - if ((modifiers & IGNORE_PARAMS) != 0) { - - // throws NullPointerException if either clazz or methodName are null. - methodName = methodName.intern(); - for (Method method : clazz.getDeclaredMethods()) { - // all method names are interned. Identity comparison is much faster. - if (method.getName() == methodName) { - result = method; - break; - } - } - - if (result == null) { - return null; - } - - } else { - - try { - // throws NullPointerException if either clazz or methodName are null. - result = clazz.getDeclaredMethod(methodName, parameterTypes); - } catch (NoSuchMethodException | SecurityException ex) { - return null; - } - - } - - if (!result.isAccessible()) try { - result.setAccessible(true); - } catch (SecurityException ignored) { - - } - - return result; - } - - /** - * Invokes the method named methodName with the given instance and arguments - * To find the method, {@link #searchMethod(int, Class, String, Class[])} is used with no type parameters, - * modifiers {@link #DEEP_SEARCH} and {@link #IGNORE_PARAMS}, and the class {@link Object#getClass() instance.getClass()} - *

- * To search the method with type parameters, you should search the method using {@link #searchMethod(int, Class, String, Class[])} or similar, - * and call {@link #invokeMethod(Method, Object, Object...)} - *

- * If a {@link ReflectiveOperationException} occurs, this is printed to {@link System#out} - * - * @param methodName Name of the method - * @param instance The instance to invoke the method on - * @param args The arguments to use in the method call - * @param The expected/known method return type - * @return The result of calling the method - * @throws NullPointerException if instance or methodName is null - * @throws IllegalArgumentException if the method is not found - * @see #invokeMethod(Method, Object, Object...) - */ - public static T invokeMethod(Object instance, String methodName, Object... args) { - return invokeMethod(searchMethod(DEEP_SEARCH | IGNORE_PARAMS, instance.getClass(), methodName), instance, args); - } - - /** - * Invokes the method named methodName with the given instance and arguments - * To find the method, {@link #searchMethod(int, Class, String, Class[])} is used with no type parameters, - * as well as the modifier {@link #IGNORE_PARAMS} - *

- * To search the method with type parameters, you should search the method using {@link #searchMethod(int, Class, String, Class[])} or similar, - * and call {@link #invokeMethod(Method, Object, Object...)} - *

- * If a {@link ReflectiveOperationException} occurs, this is printed to {@link System#out} - * - * @param clazz The class to search in/from - * @param methodName Name of the method - * @param instance The instance to invoke the method on - * @param args The arguments to use in the method call - * @param The expected/known method return type - * @return The result of calling the method - * @throws NullPointerException if clazz or methodName is null - * @throws IllegalArgumentException if the method is not found - * @see #invokeMethod(Method, Object, Object...) - */ - public static T invokeMethod(Class clazz, String methodName, Object instance, Object... args) { - return invokeMethod(searchMethod(IGNORE_PARAMS, clazz, methodName), instance, args); - } - - /** - * Invokes the method named methodName with the given instance and arguments - * To find the method, {@link #searchMethod(int, Class, String, Class[])} is used with no type parameters. - * For this search, the result of calling {@link Object#getClass() instance.getClass()} is used. - *

- * To search the method with type parameters, you should search the method using {@link #searchMethod(int, Class, String, Class[])} or similar, - * and call {@link #invokeMethod(Method, Object, Object...)} - *

- * If a {@link ReflectiveOperationException} occurs, this is printed to {@link System#out} - * - * @param modifiers The modifiers for method search. Can have {@link #DEEP_SEARCH} and {@link #IGNORE_PARAMS} - * @param methodName Name of the method - * @param instance The instance to invoke the method on - * @param args The arguments to use in the method call - * @param The expected/known method return type - * @return The result of calling the method - * @throws NullPointerException if instance or methodName is null - * @throws IllegalArgumentException if the method is not found - * @see #invokeMethod(Method, Object, Object...) - */ - public static T invokeMethod(int modifiers, Object instance, String methodName, Object... args) { - return invokeMethod(searchMethod(modifiers, instance.getClass(), methodName), instance, args); - } - - /** - * Invokes the method named methodName with the given instance and arguments - * To find the method, {@link #searchMethod(int, Class, String, Class[])} is used with no type parameters. - *

- * To search the method with type parameters, you should search the method using {@link #searchMethod(int, Class, String, Class[])} or similar, - * and call {@link #invokeMethod(Method, Object, Object...)} - *

- * If a {@link ReflectiveOperationException} occurs, this is printed to {@link System#out} - * - * @param modifiers The modifiers for method search. Can have {@link #DEEP_SEARCH} and {@link #IGNORE_PARAMS} - * @param clazz The class to search in/from - * @param methodName Name of the method - * @param instance The instance to invoke the method on - * @param args The arguments to use in the method call - * @param The expected/known method return type - * @return The result of calling the method - * @throws NullPointerException if clazz or methodName is null - * @throws IllegalArgumentException if the method is not found - * @see #invokeMethod(Method, Object, Object...) - */ - public static T invokeMethod(int modifiers, Class clazz, String methodName, Object instance, Object... args) { - return invokeMethod(searchMethod(modifiers, clazz, methodName), instance, args); - } - - /** - * Invokes the method with the given instance and arguments - *

- * If a {@link ReflectiveOperationException} occurs, this is printed to {@link System#out} - * - * @param method The method to invoke - * @param instance The instance to invoke the method on - * @param args The arguments to use in the method call - * @param The expected/known method return type - * @return The result of calling the method - */ - public static T invokeMethod(Method method, Object instance, Object... args) { - return exceptionHandler.supplySafe(() -> (T) method.invoke(instance, args)); - } - - /** - * Invokes the static method named methodName with the given arguments - * To find the method, {@link #searchMethod(int, Class, String, Class[])} is used with no type parameters, - * as well as the modifier {@link #IGNORE_PARAMS} - *

- * To search the method with type parameters, you should search the method using {@link #searchMethod(int, Class, String, Class[])} or similar, - * and call {@link #invokeMethod(Method, Object, Object...)} - *

- * If a {@link ReflectiveOperationException} occurs, this is printed to {@link System#out} - * - * @param clazz The class to search in/from - * @param methodName Name of the method - * @param args The arguments to use in the method call - * @param The expected/known method return type - * @return The result of calling the method - * @throws NullPointerException if clazz or methodName is null - * @throws IllegalArgumentException if the method is not found - * @see #invokeStaticMethod(Method, Object...) - */ - public static T invokeStaticMethod(Class clazz, String methodName, Object... args) { - return invokeStaticMethod(searchMethod(IGNORE_PARAMS, clazz, methodName), args); - } - - /** - * Invokes the static method named methodName with the given arguments - * To find the method, {@link #searchMethod(int, Class, String, Class[])} is used with no type parameters. - *

- * To search the method with type parameters, you should search the method using {@link #searchMethod(int, Class, String, Class[])} or similar, - * and call {@link #invokeMethod(Method, Object, Object...)} - *

- * If a {@link ReflectiveOperationException} occurs, this is printed to {@link System#out} - * - * @param modifiers The modifiers for method search. Can have {@link #DEEP_SEARCH} and {@link #IGNORE_PARAMS} - * @param clazz The class to search in/from - * @param methodName Name of the method - * @param args The arguments to use in the method call - * @param The expected/known method return type - * @return The result of calling the method - * @throws NullPointerException if clazz or methodName is null - * @throws IllegalArgumentException if the method is not found - * @see #invokeStaticMethod(Method, Object...) - */ - public static T invokeStaticMethod(int modifiers, Class clazz, String methodName, Object... args) { - return invokeStaticMethod(searchMethod(modifiers, clazz, methodName), args); - } - - /** - * Invokes the static method with the given arguments - *

- * If a {@link ReflectiveOperationException} occurs, this is printed to {@link System#out} - * - * @param method The method to invoke - * @param args The arguments to use in the method call - * @param The expected/known method return type - * @return The result of calling the method - * @see #invokeMethod(Method, Object, Object...) - */ - public static T invokeStaticMethod(Method method, Object... args) { - return invokeMethod(method, (Object) null, args); - } - -} +package io.dico.dicore; + +import io.dico.dicore.exceptions.ExceptionHandler; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Objects; +import java.util.function.Consumer; + +/** + * Reflective utilities + */ +@SuppressWarnings("unchecked") +public class Reflection { + private static final ExceptionHandler exceptionHandler; + private static final Field fieldModifiersField = restrictedSearchField(Field.class, "modifiers"); + private static Consumer errorTarget; + + private Reflection() { + + } + + static { + exceptionHandler = new ExceptionHandler() { + @Override + public void handle(Throwable ex) { + handleGenericException(ex); + } + + @Override + public Object handleGenericException(Throwable ex, Object... args) { + String action = args.length == 0 || !(args[0] instanceof String) ? "executing a reflective operation" : (String) args[0]; + ExceptionHandler.log(errorTarget, action, ex); + return null; + } + }; + + // don't use method reference here: the current reference in System.out would be cached. + setErrorTarget(msg -> System.out.println(msg)); + } + + /** + * Sets the output where ReflectiveOperationException's and similar are sent. + * This defaults to {@link System#out}. + * + * @param target The new output + * @throws NullPointerException if target is null + */ + public static void setErrorTarget(Consumer target) { + errorTarget = Objects.requireNonNull(target); + } + + /** + * This search modifier tells the implementation that it should subsequently search superclasses for the field/method. + * Using this modifier means a call to {@link #deepSearchField(Class, String)} will be used instead of {@link #restrictedSearchField(Class, String)} + * and a call to {@link #deepSearchMethod(Class, String, Class[])} will be used instead of {@link #restrictedSearchMethod(Class, String, Class[])} + */ + public static final int DEEP_SEARCH = 0x1; + + /** + * This search modifier applies only to fields, and tells the implementation that a final modifier might be present on a found field, and that it should be removed. + */ + public static final int REMOVE_FINAL = 0x2; + + /** + * This search modifier applies only to methods, and tells the implementation that it should completely ignore parameter types and return the first method with a matching name + * The implementation uses {@link Class#getDeclaredMethods()} instead of {@link Class#getDeclaredMethod(String, Class[])} if this modifier is set. + */ + public static final int IGNORE_PARAMS = 0x2; + + /* + ### FIELD METHODS ### + */ + + /** + * Search a field of any accessibility within the class or any of its superclasses. + * The first field with the given name that is found will be returned. + *

+ * If a field is found and it is not accessible, this method attempts to make it accessible. + * If a {@link SecurityException} is thrown in the process, that is ignored and the field will be returned nonetheless. + *

+ * This method throws IllegalArgumentException if the Field is not found, because, in most cases, that should never happen, + * and it should simplify debugging. In some cases, if you want to know if the field exists, you'll have to use try/catch for that. + * + * @param clazz The lowest class in the ladder to start searching from + * @param fieldName The name of the field + * //@param fieldType the type of the field, or null if it can be any. + * @return The field + * @throws NullPointerException if clazz is null or fieldName is null + * @throws IllegalArgumentException if the field doesn't exist + * @see #restrictedSearchField(Class, String) + */ + public static Field deepSearchField(Class clazz, String fieldName/*, Class fieldType*/) { + Class currentClass = clazz; + Field result; + do { + // throws NPE if class or fieldName is null + result = internalSearchField(clazz, fieldName); + if (result != null) { + return result; + } + currentClass = currentClass.getSuperclass(); + } while (currentClass != null); + + throw new IllegalArgumentException("field not found in " + clazz.getCanonicalName() + " and superclasses: " + fieldName); + } + + /** + * Search a field of any accessibility within the class, but not its superclasses. + *

+ * If a field is found and it is not accessible, this method attempts to make it accessible. + * If a {@link SecurityException} is thrown in the process, that is ignored and the field will be returned nonetheless. + *

+ * This method throws IllegalArgumentException if the Field is not found, because, in most cases, that should never happen, + * and it should simplify debugging. In some cases, if you want to know if the field exists, you'll have to use try/catch for that. + * + * @param clazz The only class to search for the field + * @param fieldName The name of the field + * @return The field + * @throws NullPointerException if clazz or fieldName is null + * @throws IllegalArgumentException if the field does not exist + */ + public static Field restrictedSearchField(Class clazz, String fieldName) { + Field result = internalSearchField(clazz, fieldName); + if (result == null) { + throw new IllegalArgumentException("field not found in " + clazz.getCanonicalName() + ": " + fieldName); + } + return result; + } + + /** + * Searches for a field using the given search method. + * + * @param modifiers The modifiers for field search. Can have {@link #DEEP_SEARCH} and {@link #REMOVE_FINAL} + * @param clazz The class to search in/from + * @param fieldName Name of the field + * @return The field + * @throws NullPointerException if clazz or fieldName is null + * @throws IllegalArgumentException if the field is not found + */ + public static Field searchField(int modifiers, Class clazz, String fieldName) { + Field result; + if ((modifiers & DEEP_SEARCH) != 0) { + result = deepSearchField(clazz, fieldName); + } else { + result = restrictedSearchField(clazz, fieldName); + } + if ((modifiers & REMOVE_FINAL) != 0) { + removeFinalModifier(result); + } + return result; + } + + /** + * @return The same as {@link #restrictedSearchField(Class, String)}, but returns null instead of throwing IllegalArgumentException + * @see #restrictedSearchField(Class, String) + */ + private static Field internalSearchField(Class clazz, String fieldName) { + Field result; + try { + // throws NullPointerException if either clazz or fieldName are null. + result = clazz.getDeclaredField(fieldName); + } catch (NoSuchFieldException | SecurityException ex) { + return null; + } + + if (!result.isAccessible()) try { + result.setAccessible(true); + } catch (SecurityException ignored) { + + } + + return result; + } + + /** + * Attempts to remove existing final modifier of the given field + * This method should always return true. + * + * @param field The field whose final modifier to remove + * @return true if the field most definitely has no final modifier after this call + * @throws NullPointerException if field is null + */ + public static boolean removeFinalModifier(Field field) { + Objects.requireNonNull(field); + try { + int modifiers = (int) fieldModifiersField.get(field); + if (modifiers != (modifiers &= ~Modifier.FINAL)) { + fieldModifiersField.set(field, modifiers); + } + return true; + } catch (Exception ex) { + return false; + } + } + + /** + * Gets field value of the field named fieldName and the given instance + * To find the field, {@link #deepSearchField(Class, String)} is used (DEEP search method). + *

+ * If a {@link ReflectiveOperationException} occurs, this is printed to {@link System#out} + * + * @param instance The instance whose field value to get + * @param fieldName the name of the field + * @param The expected/known field type + * @return The field value + * @throws IllegalArgumentException if the field doesn't exist + * @see #deepSearchField(Class, String) + * @see #getFieldValue(Class, String, Object) + */ + public static T getFieldValue(Object instance, String fieldName) { + return getFieldValue(deepSearchField(instance.getClass(), fieldName), instance); + } + + /** + * Gets field value of the field named fieldName and the given instance + * To find the field, {@link #restrictedSearchField(Class, String)} is used (RESTRICTED search method). + *

+ * If a {@link ReflectiveOperationException} occurs, this is printed to {@link System#out} + * + * @param clazz The class to search for the field + * @param instance The instance whose field value to get + * @param fieldName the name of the field + * @param The expected/known field type + * @return The field value + * @throws IllegalArgumentException if the field doesn't exist + * @see #restrictedSearchField(Class, String) + * @see #getFieldValue(Field, Object) + */ + public static T getFieldValue(Class clazz, String fieldName, Object instance) { + return getFieldValue(restrictedSearchField(clazz, fieldName), instance); + } + + /** + * Gets field value of the field named fieldName and the given instance + * To find the field, {@link #searchField(int, Class, String)} is used. + *

+ * If a {@link ReflectiveOperationException} occurs, this is printed to {@link System#out} + * + * @param modifiers The modifiers for field search. Can have {@link #DEEP_SEARCH} and {@link #REMOVE_FINAL} + * @param clazz The class to search for the field + * @param instance The instance whose field value to get + * @param fieldName the name of the field + * @param The expected/known field type + * @return The field value + * @throws IllegalArgumentException if the field doesn't exist + * @see #searchField(int, Class, String) + * @see #getFieldValue(Field, Object) + */ + public static T getFieldValue(int modifiers, Class clazz, String fieldName, Object instance) { + return getFieldValue(searchField(modifiers, clazz, fieldName), instance); + } + + /** + * Gets field value of the given field and the given instance + *

+ * If a {@link ReflectiveOperationException} occurs, this is printed to {@link System#out} + * + * @param field the field + * @param instance The instance whose field value to get + * @param The expected/known field type + * @return The field value + */ + public static T getFieldValue(Field field, Object instance) { + return exceptionHandler.supplySafe(() -> (T) field.get(instance)); + } + + /** + * Gets static field value of the field named fieldName + * To find the field, {@link #restrictedSearchField(Class, String)} is used (RESTRICTED search method). + *

+ * If a {@link ReflectiveOperationException} occurs, this is printed to {@link System#out} + * + * @param clazz The class to search for the field + * @param fieldName the name of the field + * @param The expected/known field type + * @return The field value + * @throws IllegalArgumentException if the field doesn't exist + * @see #restrictedSearchField(Class, String) + * @see #getStaticFieldValue(Field) + */ + public static T getStaticFieldValue(Class clazz, String fieldName) { + return getStaticFieldValue(restrictedSearchField(clazz, fieldName)); + } + + /** + * Gets static field value of the field named fieldName + * To find the field, {@link #searchField(int, Class, String)} is used. + *

+ * If a {@link ReflectiveOperationException} occurs, this is printed to {@link System#out} + * + * @param modifiers The modifiers for field search. Can have {@link #DEEP_SEARCH} and {@link #REMOVE_FINAL} + * @param clazz The class to search for the field + * @param fieldName the name of the field + * @param The expected/known field type + * @return The field value + * @throws IllegalArgumentException if the field doesn't exist + * @see #deepSearchField(Class, String) + * @see #getStaticFieldValue(Field) + */ + public static T getStaticFieldValue(int modifiers, Class clazz, String fieldName) { + return getStaticFieldValue(searchField(modifiers, clazz, fieldName)); + } + + /** + * Gets static field value + *

+ * If a {@link ReflectiveOperationException} occurs, this is printed to {@link System#out} + *

+ * Equivalent to the call {@code getFieldValue(field, (Object) null)} + * + * @param field the field + * @param The expected/known field type + * @return The field value + * @see #getFieldValue(Field, Object) + */ + public static T getStaticFieldValue(Field field) { + return getFieldValue(field, (Object) null); + } + + /** + * Sets field value of the field named fieldName and the given instance + * To find the field, {@link #deepSearchField(Class, String)} is used (DEEP search method). + *

+ * If a {@link ReflectiveOperationException} occurs, this is printed to {@link System#out} + * + * @param instance The instance whose field value to set + * @param fieldName the name of the field + * @param newValue the new field value + * @throws IllegalArgumentException if the field doesn't exist + * @see #deepSearchField(Class, String) + * @see #setFieldValue(Class, String, Object, Object) + */ + public static void setFieldValue(Object instance, String fieldName, Object newValue) { + setFieldValue(deepSearchField(instance.getClass(), fieldName), instance, newValue); + } + + /** + * Sets field value of the field named fieldName and the given instance + * To find the field, {@link #restrictedSearchField(Class, String)} is used (RESTRICTED search method). + *

+ * If a {@link ReflectiveOperationException} occurs, this is printed to {@link System#out} + * + * @param clazz The class to search for the field + * @param fieldName the name of the field + * @param instance The field owner + * @param newValue The new field value + * @throws IllegalArgumentException if the field doesn't exist + * @see #restrictedSearchField(Class, String) + * @see #setFieldValue(Field, Object, Object) + */ + public static void setFieldValue(Class clazz, String fieldName, Object instance, Object newValue) { + setFieldValue(restrictedSearchField(clazz, fieldName), instance, newValue); + } + + /** + * Sets field value of the field named fieldName and the given instance + * To find the field, {@link #searchField(int, Class, String)} is used. + *

+ * If a {@link ReflectiveOperationException} occurs, this is printed to {@link System#out} + * + * @param modifiers The modifiers for field search. Can have {@link #DEEP_SEARCH} and {@link #REMOVE_FINAL} + * @param clazz The class to search for the field + * @param instance The instance whose field value to set + * @param fieldName the name of the field + * @param newValue The new field value + * @throws IllegalArgumentException if the field doesn't exist + * @see #searchField(int, Class, String) + * @see #setFieldValue(Field, Object, Object) + */ + public static void setFieldValue(int modifiers, Class clazz, String fieldName, Object instance, Object newValue) { + setFieldValue(searchField(modifiers, clazz, fieldName), instance, newValue); + } + + /** + * Sets a field value + *

+ * If a {@link ReflectiveOperationException} occurs, this is printed to {@link System#out} + * + * @param field The field + * @param instance The field owner + * @param newValue The new field value + */ + public static void setFieldValue(Field field, Object instance, Object newValue) { + exceptionHandler.runSafe(() -> field.set(instance, newValue)); + } + + /** + * Sets static field value of the field name fieldName + * To find the field, {@link #restrictedSearchField(Class, String)} is used (RESTRICTED search method). + *

+ * If a {@link ReflectiveOperationException} occurs, this is printed to {@link System#out} + * + * @param clazz The class to search for the field + * @param fieldName the name of the field + * @param newValue The new field value + * @throws IllegalArgumentException if the field doesn't exist + * @see #restrictedSearchField(Class, String) + * @see #setStaticFieldValue(Field, Object) + */ + public static void setStaticFieldValue(Class clazz, String fieldName, Object newValue) { + setStaticFieldValue(restrictedSearchField(clazz, fieldName), newValue); + } + + /** + * Sets static field value of the field named fieldName + * To find the field, {@link #searchField(int, Class, String)} is used. + *

+ * If a {@link ReflectiveOperationException} occurs, this is printed to {@link System#out} + * + * @param modifiers The modifiers for field search. Can have {@link #DEEP_SEARCH} and {@link #REMOVE_FINAL} + * @param clazz The class to search for the field + * @param fieldName the name of the field + * @param newValue The new field value + * @throws IllegalArgumentException if the field doesn't exist + * @see #searchField(int, Class, String) + * @see #setStaticFieldValue(Field, Object) + */ + public static void setStaticFieldValue(int modifiers, Class clazz, String fieldName, Object newValue) { + setStaticFieldValue(searchField(modifiers, clazz, fieldName), newValue); + } + + /** + * Sets a static field value + *

+ * If a {@link ReflectiveOperationException} occurs, this is printed to {@link System#out} + * + * @param field The field + * @param newValue The new field value + */ + public static void setStaticFieldValue(Field field, Object newValue) { + setFieldValue(field, (Object) null, newValue); + } + + /* + ### METHOD METHODS ### + */ + + /** + * Search a method of any accessibility within the class or any of its superclasses. + * The first method with the given name that is found will be returned. + *

+ * If a method is found and it is not accessible, this method attempts to make it accessible. + * If a {@link SecurityException} is thrown in the process, that is ignored and the method will be returned nonetheless. + *

+ * This method throws IllegalArgumentException if the Method is not found, because, in most cases, that should never happen, + * and it should simplify debugging. In some cases, if you want to know if the method exists, you'll have to use try/catch for that. + * + * @param clazz The lowest class in the ladder to start searching from + * @param methodName The name of the method + * @param parameterTypes the parameter types of the sought method. + * @return The method + * @throws NullPointerException if clazz is null or methodName is null + * @throws IllegalArgumentException if the method doesn't exist + * @see #restrictedSearchMethod(Class, String, Class[]) + */ + public static Method deepSearchMethod(Class clazz, String methodName, Class... parameterTypes) { + return deepSearchMethod(0, clazz, methodName, parameterTypes); + } + + /** + * Search a method of any accessibility within the class or any of its superclasses. + * The first method with the given name that is found will be returned. + *

+ * If a method is found and it is not accessible, this method attempts to make it accessible. + * If a {@link SecurityException} is thrown in the process, that is ignored and the method will be returned nonetheless. + *

+ * This method throws IllegalArgumentException if the Method is not found, because, in most cases, that should never happen, + * and it should simplify debugging. In some cases, if you want to know if the method exists, you'll have to use try/catch for that. + * + * @param modifiers The modifiers for method search. Can have {@link #IGNORE_PARAMS} + * @param clazz The lowest class in the ladder to start searching from + * @param methodName The name of the method + * @param parameterTypes the parameter types of the sought method. + * @return The method + * @throws NullPointerException if clazz is null or methodName is null + * @throws IllegalArgumentException if the method doesn't exist + * @see #restrictedSearchMethod(Class, String, Class[]) + */ + public static Method deepSearchMethod(int modifiers, Class clazz, String methodName, Class... parameterTypes) { + Class currentClass = clazz; + Method result; + do { + // throws NPE if class or methodName is null + result = internalSearchMethod(modifiers, currentClass, methodName, parameterTypes); + if (result != null) { + return result; + } + currentClass = currentClass.getSuperclass(); + } while (currentClass != null); + + throw new IllegalArgumentException("method not found in " + clazz.getCanonicalName() + " and superclasses: " + methodName); + } + + /** + * Search a method of any accessibility within the class, but not its superclasses. + *

+ * If a method is found and it is not accessible, this method attempts to make it accessible. + * If a {@link SecurityException} is thrown in the process, that is ignored and the method will be returned nonetheless. + *

+ * This method throws IllegalArgumentException if the Method is not found, because, in most cases, that should never happen, + * and it should simplify debugging. In some cases, if you want to know if the method exists, you'll have to use try/catch for that. + * + * @param clazz The only class to search for the method + * @param methodName The name of the method + * @param parameterTypes the parameter types of the sought method. + * @return The method + * @throws NullPointerException if clazz or methodName is null + * @throws IllegalArgumentException if the method does not exist + */ + public static Method restrictedSearchMethod(Class clazz, String methodName, Class... parameterTypes) { + return restrictedSearchMethod(0, clazz, methodName, parameterTypes); + } + + /** + * Search a method of any accessibility within the class, but not its superclasses. + *

+ * If a method is found and it is not accessible, this method attempts to make it accessible. + * If a {@link SecurityException} is thrown in the process, that is ignored and the method will be returned nonetheless. + *

+ * This method throws IllegalArgumentException if the Method is not found, because, in most cases, that should never happen, + * and it should simplify debugging. In some cases, if you want to know if the method exists, you'll have to use try/catch for that. + * + * @param modifiers The modifiers for method search. Can have {@link #IGNORE_PARAMS} + * @param clazz The only class to search for the method + * @param methodName The name of the method + * @param parameterTypes the parameter types of the sought method. + * @return The method + * @throws NullPointerException if clazz or methodName is null + * @throws IllegalArgumentException if the method does not exist + */ + public static Method restrictedSearchMethod(int modifiers, Class clazz, String methodName, Class... parameterTypes) { + Method result = internalSearchMethod(modifiers, clazz, methodName, parameterTypes); + if (result == null) { + throw new IllegalArgumentException("method not found in " + clazz.getCanonicalName() + ": " + methodName); + } + return result; + } + + /** + * Searches for a method using the given search method. + *

+ * If a method is found and it is not accessible, this method attempts to make it accessible. + * If a {@link SecurityException} is thrown in the process, that is ignored and the method will be returned nonetheless. + *

+ * This method throws IllegalArgumentException if the Method is not found, because, in most cases, that should never happen, + * and it should simplify debugging. In some cases, if you want to know if the method exists, you'll have to use try/catch for that. + * + * @param modifiers The modifiers for method search. Can have {@link #DEEP_SEARCH} and {@link #IGNORE_PARAMS} + * @param clazz The class to search in/from + * @param methodName Name of the method + * @param parameterTypes the parameter types of the sought method. + * @return The method + * @throws NullPointerException if clazz or methodName is null + * @throws IllegalArgumentException if the method is not found + */ + public static Method searchMethod(int modifiers, Class clazz, String methodName, Class... parameterTypes) { + if ((modifiers & DEEP_SEARCH) != 0) { + return deepSearchMethod(modifiers, clazz, methodName, parameterTypes); + } else { + return restrictedSearchMethod(modifiers, clazz, methodName, parameterTypes); + } + } + + /** + * @return The same as {@link #restrictedSearchMethod(Class, String, Class[]) }, but returns null instead of throwing IllegalArgumentException + * @see #restrictedSearchMethod(Class, String, Class[]) + */ + private static Method internalSearchMethod(int modifiers, Class clazz, String methodName, Class... parameterTypes) { + Method result = null; + + if ((modifiers & IGNORE_PARAMS) != 0) { + + // throws NullPointerException if either clazz or methodName are null. + methodName = methodName.intern(); + for (Method method : clazz.getDeclaredMethods()) { + // all method names are interned. Identity comparison is much faster. + if (method.getName() == methodName) { + result = method; + break; + } + } + + if (result == null) { + return null; + } + + } else { + + try { + // throws NullPointerException if either clazz or methodName are null. + result = clazz.getDeclaredMethod(methodName, parameterTypes); + } catch (NoSuchMethodException | SecurityException ex) { + return null; + } + + } + + if (!result.isAccessible()) try { + result.setAccessible(true); + } catch (SecurityException ignored) { + + } + + return result; + } + + /** + * Invokes the method named methodName with the given instance and arguments + * To find the method, {@link #searchMethod(int, Class, String, Class[])} is used with no type parameters, + * modifiers {@link #DEEP_SEARCH} and {@link #IGNORE_PARAMS}, and the class {@link Object#getClass() instance.getClass()} + *

+ * To search the method with type parameters, you should search the method using {@link #searchMethod(int, Class, String, Class[])} or similar, + * and call {@link #invokeMethod(Method, Object, Object...)} + *

+ * If a {@link ReflectiveOperationException} occurs, this is printed to {@link System#out} + * + * @param methodName Name of the method + * @param instance The instance to invoke the method on + * @param args The arguments to use in the method call + * @param The expected/known method return type + * @return The result of calling the method + * @throws NullPointerException if instance or methodName is null + * @throws IllegalArgumentException if the method is not found + * @see #invokeMethod(Method, Object, Object...) + */ + public static T invokeMethod(Object instance, String methodName, Object... args) { + return invokeMethod(searchMethod(DEEP_SEARCH | IGNORE_PARAMS, instance.getClass(), methodName), instance, args); + } + + /** + * Invokes the method named methodName with the given instance and arguments + * To find the method, {@link #searchMethod(int, Class, String, Class[])} is used with no type parameters, + * as well as the modifier {@link #IGNORE_PARAMS} + *

+ * To search the method with type parameters, you should search the method using {@link #searchMethod(int, Class, String, Class[])} or similar, + * and call {@link #invokeMethod(Method, Object, Object...)} + *

+ * If a {@link ReflectiveOperationException} occurs, this is printed to {@link System#out} + * + * @param clazz The class to search in/from + * @param methodName Name of the method + * @param instance The instance to invoke the method on + * @param args The arguments to use in the method call + * @param The expected/known method return type + * @return The result of calling the method + * @throws NullPointerException if clazz or methodName is null + * @throws IllegalArgumentException if the method is not found + * @see #invokeMethod(Method, Object, Object...) + */ + public static T invokeMethod(Class clazz, String methodName, Object instance, Object... args) { + return invokeMethod(searchMethod(IGNORE_PARAMS, clazz, methodName), instance, args); + } + + /** + * Invokes the method named methodName with the given instance and arguments + * To find the method, {@link #searchMethod(int, Class, String, Class[])} is used with no type parameters. + * For this search, the result of calling {@link Object#getClass() instance.getClass()} is used. + *

+ * To search the method with type parameters, you should search the method using {@link #searchMethod(int, Class, String, Class[])} or similar, + * and call {@link #invokeMethod(Method, Object, Object...)} + *

+ * If a {@link ReflectiveOperationException} occurs, this is printed to {@link System#out} + * + * @param modifiers The modifiers for method search. Can have {@link #DEEP_SEARCH} and {@link #IGNORE_PARAMS} + * @param methodName Name of the method + * @param instance The instance to invoke the method on + * @param args The arguments to use in the method call + * @param The expected/known method return type + * @return The result of calling the method + * @throws NullPointerException if instance or methodName is null + * @throws IllegalArgumentException if the method is not found + * @see #invokeMethod(Method, Object, Object...) + */ + public static T invokeMethod(int modifiers, Object instance, String methodName, Object... args) { + return invokeMethod(searchMethod(modifiers, instance.getClass(), methodName), instance, args); + } + + /** + * Invokes the method named methodName with the given instance and arguments + * To find the method, {@link #searchMethod(int, Class, String, Class[])} is used with no type parameters. + *

+ * To search the method with type parameters, you should search the method using {@link #searchMethod(int, Class, String, Class[])} or similar, + * and call {@link #invokeMethod(Method, Object, Object...)} + *

+ * If a {@link ReflectiveOperationException} occurs, this is printed to {@link System#out} + * + * @param modifiers The modifiers for method search. Can have {@link #DEEP_SEARCH} and {@link #IGNORE_PARAMS} + * @param clazz The class to search in/from + * @param methodName Name of the method + * @param instance The instance to invoke the method on + * @param args The arguments to use in the method call + * @param The expected/known method return type + * @return The result of calling the method + * @throws NullPointerException if clazz or methodName is null + * @throws IllegalArgumentException if the method is not found + * @see #invokeMethod(Method, Object, Object...) + */ + public static T invokeMethod(int modifiers, Class clazz, String methodName, Object instance, Object... args) { + return invokeMethod(searchMethod(modifiers, clazz, methodName), instance, args); + } + + /** + * Invokes the method with the given instance and arguments + *

+ * If a {@link ReflectiveOperationException} occurs, this is printed to {@link System#out} + * + * @param method The method to invoke + * @param instance The instance to invoke the method on + * @param args The arguments to use in the method call + * @param The expected/known method return type + * @return The result of calling the method + */ + public static T invokeMethod(Method method, Object instance, Object... args) { + return exceptionHandler.supplySafe(() -> (T) method.invoke(instance, args)); + } + + /** + * Invokes the static method named methodName with the given arguments + * To find the method, {@link #searchMethod(int, Class, String, Class[])} is used with no type parameters, + * as well as the modifier {@link #IGNORE_PARAMS} + *

+ * To search the method with type parameters, you should search the method using {@link #searchMethod(int, Class, String, Class[])} or similar, + * and call {@link #invokeMethod(Method, Object, Object...)} + *

+ * If a {@link ReflectiveOperationException} occurs, this is printed to {@link System#out} + * + * @param clazz The class to search in/from + * @param methodName Name of the method + * @param args The arguments to use in the method call + * @param The expected/known method return type + * @return The result of calling the method + * @throws NullPointerException if clazz or methodName is null + * @throws IllegalArgumentException if the method is not found + * @see #invokeStaticMethod(Method, Object...) + */ + public static T invokeStaticMethod(Class clazz, String methodName, Object... args) { + return invokeStaticMethod(searchMethod(IGNORE_PARAMS, clazz, methodName), args); + } + + /** + * Invokes the static method named methodName with the given arguments + * To find the method, {@link #searchMethod(int, Class, String, Class[])} is used with no type parameters. + *

+ * To search the method with type parameters, you should search the method using {@link #searchMethod(int, Class, String, Class[])} or similar, + * and call {@link #invokeMethod(Method, Object, Object...)} + *

+ * If a {@link ReflectiveOperationException} occurs, this is printed to {@link System#out} + * + * @param modifiers The modifiers for method search. Can have {@link #DEEP_SEARCH} and {@link #IGNORE_PARAMS} + * @param clazz The class to search in/from + * @param methodName Name of the method + * @param args The arguments to use in the method call + * @param The expected/known method return type + * @return The result of calling the method + * @throws NullPointerException if clazz or methodName is null + * @throws IllegalArgumentException if the method is not found + * @see #invokeStaticMethod(Method, Object...) + */ + public static T invokeStaticMethod(int modifiers, Class clazz, String methodName, Object... args) { + return invokeStaticMethod(searchMethod(modifiers, clazz, methodName), args); + } + + /** + * Invokes the static method with the given arguments + *

+ * If a {@link ReflectiveOperationException} occurs, this is printed to {@link System#out} + * + * @param method The method to invoke + * @param args The arguments to use in the method call + * @param The expected/known method return type + * @return The result of calling the method + * @see #invokeMethod(Method, Object, Object...) + */ + public static T invokeStaticMethod(Method method, Object... args) { + return invokeMethod(method, (Object) null, args); + } + +} diff --git a/dicore3/core/src/main/java/io/dico/dicore/SetBasedWhitelist.java b/dicore3/core/src/main/java/io/dico/dicore/SetBasedWhitelist.java index 6596b65..d4486ed 100644 --- a/dicore3/core/src/main/java/io/dico/dicore/SetBasedWhitelist.java +++ b/dicore3/core/src/main/java/io/dico/dicore/SetBasedWhitelist.java @@ -1,59 +1,59 @@ -package io.dico.dicore; - -import org.bukkit.configuration.ConfigurationSection; - -import java.util.*; -import java.util.function.Function; -import java.util.stream.Collectors; - -public class SetBasedWhitelist implements Whitelist { - private final Set set; - private final boolean blacklist; - - public SetBasedWhitelist(Object[] array, boolean blacklist) { - this(Arrays.asList(array), blacklist); - } - - public SetBasedWhitelist(ConfigurationSection section, Function parser) { - this(section.getStringList("listed").stream().map(parser).filter(Objects::nonNull).collect(Collectors.toList()), - section.getBoolean("blacklist", false)); - } - - @SuppressWarnings("unchecked") - public SetBasedWhitelist(Collection collection, boolean blacklist) { - Set set; - if (collection.isEmpty()) { - set = Collections.emptySet(); - } else if (collection.iterator().next() instanceof Enum) { - set = EnumSet.copyOf(collection); - } else if (collection instanceof Set) { - set = (Set) collection; - } else { - set = new HashSet<>(collection); - } - - this.set = set; - this.blacklist = blacklist; - } - - @Override - public boolean isWhitelisted(Object o) { - return blacklist != set.contains(o); - } - - @SuppressWarnings("unchecked") - @Override - public String toString() { - return (blacklist ? "Blacklist" : "Whitelist") + "{" - + String.join(", ", (CharSequence[]) set.stream().map(String::valueOf).toArray(String[]::new)) + "}"; - } - - public Set getSet() { - return set; - } - - public boolean isBlacklist() { - return blacklist; - } - -} +package io.dico.dicore; + +import org.bukkit.configuration.ConfigurationSection; + +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class SetBasedWhitelist implements Whitelist { + private final Set set; + private final boolean blacklist; + + public SetBasedWhitelist(Object[] array, boolean blacklist) { + this(Arrays.asList(array), blacklist); + } + + public SetBasedWhitelist(ConfigurationSection section, Function parser) { + this(section.getStringList("listed").stream().map(parser).filter(Objects::nonNull).collect(Collectors.toList()), + section.getBoolean("blacklist", false)); + } + + @SuppressWarnings("unchecked") + public SetBasedWhitelist(Collection collection, boolean blacklist) { + Set set; + if (collection.isEmpty()) { + set = Collections.emptySet(); + } else if (collection.iterator().next() instanceof Enum) { + set = EnumSet.copyOf(collection); + } else if (collection instanceof Set) { + set = (Set) collection; + } else { + set = new HashSet<>(collection); + } + + this.set = set; + this.blacklist = blacklist; + } + + @Override + public boolean isWhitelisted(Object o) { + return blacklist != set.contains(o); + } + + @SuppressWarnings("unchecked") + @Override + public String toString() { + return (blacklist ? "Blacklist" : "Whitelist") + "{" + + String.join(", ", (CharSequence[]) set.stream().map(String::valueOf).toArray(String[]::new)) + "}"; + } + + public Set getSet() { + return set; + } + + public boolean isBlacklist() { + return blacklist; + } + +} diff --git a/dicore3/core/src/main/java/io/dico/dicore/SpigotUtil.java b/dicore3/core/src/main/java/io/dico/dicore/SpigotUtil.java index 44659fa..afcae02 100644 --- a/dicore3/core/src/main/java/io/dico/dicore/SpigotUtil.java +++ b/dicore3/core/src/main/java/io/dico/dicore/SpigotUtil.java @@ -1,408 +1,408 @@ -package io.dico.dicore; - -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.World; -import org.bukkit.block.Block; -import org.bukkit.block.BlockFace; -import org.bukkit.block.BlockState; -import org.bukkit.configuration.serialization.ConfigurationSerializable; -import org.bukkit.entity.*; -import org.bukkit.inventory.Inventory; -import org.bukkit.inventory.InventoryHolder; -import org.bukkit.inventory.ItemStack; -import org.bukkit.material.Attachable; -import org.bukkit.material.MaterialData; -import org.bukkit.projectiles.ProjectileSource; - -import java.util.*; -import java.util.function.BiConsumer; -import java.util.function.Consumer; -import java.util.function.Predicate; - -public class SpigotUtil { - - private SpigotUtil() { - throw new UnsupportedOperationException(); - } - - public static World matchWorld(String input) { - try { - UUID uid = UUID.fromString(input); - World world = Bukkit.getWorld(uid); - if (world != null) { - return world; - } - } catch (IllegalArgumentException ignored) { - } - - World result = Bukkit.getWorld(input); - if (result == null) { - input = input.toLowerCase().replace("_", "").replaceAll("[-_]", ""); - for (World world : Bukkit.getWorlds()) { - if (world.getName().toLowerCase().equals(input)) { - result = world; - break; - } - } - } - - return result; - } - - public static Block getSupportingBlock(Block block) { - MaterialData data = block.getState().getData(); - if (data instanceof Attachable) { - BlockFace attachedOn = ((Attachable) data).getAttachedFace(); - return block.getRelative(attachedOn); - } - return null; - } - - public static boolean isItemPresent(ItemStack stack) { - return stack != null && stack.getType() != Material.AIR && stack.getAmount() > 0; - } - - public static boolean removeItems(Inventory from, ItemStack item, int amount) { - for (Map.Entry entry : from.all(item.getType()).entrySet()) { - ItemStack stack = entry.getValue(); - if (item.isSimilar(stack)) { - amount -= stack.getAmount(); - int stackAmount = -Math.min(0, amount); - if (stackAmount == 0) { - from.setItem(entry.getKey(), null); - } else { - stack.setAmount(stackAmount); - } - } - } - return amount <= 0; - } - - public static BlockFace yawToFace(float yaw) { - if ((yaw %= 360) < 0) - yaw += 360; - if (45 <= yaw && yaw < 135) - return BlockFace.WEST; - if (135 <= yaw && yaw < 225) - return BlockFace.NORTH; - if (225 <= yaw && yaw < 315) - return BlockFace.EAST; - return BlockFace.SOUTH; - } - - public static void addItems(InventoryHolder entity, ItemStack... items) { - Location dropLocation; - if (entity instanceof Entity) { - dropLocation = ((Entity) entity).getLocation(); - } else if (entity instanceof BlockState) { - dropLocation = ((BlockState) entity).getLocation().add(0.5, 1, 0.5); - } else { - throw new IllegalArgumentException("Can't find location of this InventoryHolder: " + entity); - } - World world = dropLocation.getWorld(); - for (ItemStack toDrop : entity.getInventory().addItem(items).values()) { - world.dropItemNaturally(dropLocation, toDrop); - } - } - - public static String asJsonString(Object object) { - return asJsonString(null, object, 0); - } - - public static String asJsonString(String key, Object object, int indentation) { - String indent = new String(new char[indentation * 2]).replace('\0', ' '); - StringBuilder builder = new StringBuilder(indent); - if (key != null) { - builder.append(key).append(": "); - } - if (object instanceof ConfigurationSerializable) { - object = ((ConfigurationSerializable) object).serialize(); - } - if (object instanceof Map) { - builder.append("{\n"); - Map map = (Map) object; - for (Map.Entry entry : map.entrySet()) { - builder.append(asJsonString(String.valueOf(entry.getKey()), entry.getValue(), indentation + 1)); - } - builder.append(indent).append("}"); - } else if (object instanceof List) { - builder.append("[\n"); - List list = (List) object; - for (Object entry : list) { - builder.append(asJsonString(null, entry, indentation + 1)); - } - builder.append(indent).append("]"); - } else { - builder.append(String.valueOf(object)); - } - return builder.append(",\n").toString(); - } - - public static String asJsonString(String key, Object object, int indentation, BiConsumer, StringBuilder> listHeader) { - String indent = new String(new char[indentation * 2]).replace('\0', ' '); - StringBuilder builder = new StringBuilder(indent); - if (key != null) { - builder.append(key).append(": "); - } - if (object instanceof ConfigurationSerializable) { - object = ((ConfigurationSerializable) object).serialize(); - } - if (object instanceof Map) { - builder.append("{\n"); - Map map = (Map) object; - for (Map.Entry entry : map.entrySet()) { - builder.append(asJsonString(String.valueOf(entry.getKey()), entry.getValue(), indentation + 1, listHeader)); - } - builder.append(indent).append("}"); - } else if (object instanceof List) { - builder.append("["); - List list = (List) object; - listHeader.accept(list, builder); - builder.append("\n"); - for (Object entry : list) { - builder.append(asJsonString(null, entry, indentation + 1, listHeader)); - } - builder.append(indent).append("]"); - } else { - builder.append(String.valueOf(object)); - } - return builder.append(",\n").toString(); - } - - public static BlockFace estimateDirectionTo(Location from, Location to) { - double dx = from.getX() - to.getX(); - double dz = from.getZ() - to.getZ(); - - boolean xGreater = Math.abs(dx) - Math.abs(dz) > 0; - double f = xGreater ? 2 / Math.abs(dx) : 2 / Math.abs(dz); - dx *= f; - dz *= f; - - double other = Math.abs(xGreater ? dz : dx); - - if (other <= .5) { - return xGreater ? (dx < 0 ? BlockFace.WEST : BlockFace.EAST) : (dz < 0 ? BlockFace.NORTH : BlockFace.SOUTH); - } - - if (other < 1.5) { - if (xGreater) { - return dx < 0 ? (dz < 0 ? BlockFace.WEST_NORTH_WEST : BlockFace.WEST_SOUTH_WEST) : (dz < 0 ? BlockFace.EAST_NORTH_EAST : BlockFace.EAST_SOUTH_EAST); - } - return dx < 0 ? (dz < 0 ? BlockFace.NORTH_NORTH_WEST : BlockFace.SOUTH_SOUTH_WEST) : (dz < 0 ? BlockFace.NORTH_NORTH_EAST : BlockFace.SOUTH_SOUTH_EAST); - } - - return dx < 0 ? (dz < 0 ? BlockFace.NORTH_WEST : BlockFace.SOUTH_WEST) : (dz < 0 ? BlockFace.NORTH_EAST : BlockFace.SOUTH_EAST); - } - - public static Entity findEntityFromDamager(Entity damager, EntityType searched) { - if (damager.getType() == searched) { - return damager; - } - - if (damager instanceof Projectile) { - ProjectileSource shooter = ((Projectile) damager).getShooter(); - if (shooter instanceof Entity && ((Entity) shooter).getType() == searched) { - return (Entity) shooter; - } - return null; - } - - if (damager.getType() == EntityType.PRIMED_TNT) { - Entity source = ((TNTPrimed) damager).getSource(); - if (source.getType() == searched) { - return source; - } - } - - return null; - } - - public static int xpForNextLevel(int currentLevel) { - if (currentLevel >= 30) { - return 112 + (currentLevel - 30) * 9; - } - - if (currentLevel >= 15) { - return 37 + (currentLevel - 15) * 5; - } - - return 7 + currentLevel * 2; - } - - public static int removeExp(Player entity, int xp) { - int total = entity.getTotalExperience(); - if (xp > total) { - xp = total; - } - - int level = entity.getLevel(); - if (level < 0) { - return 0; - } - - int removed = 0; - int xpForNextLevel = xpForNextLevel(level); - int current = (int) entity.getExp() * xpForNextLevel; - - if (xp > current) { - xp -= current; - total -= current; - removed += current; - - if (level == 0) { - entity.setExp(0F); - entity.setTotalExperience(total); - return removed; - } - } else { - current -= xp; - total -= xp; - removed += xp; - - entity.setExp((float) current / xpForNextLevel); - entity.setTotalExperience(total); - return removed; - } - - do { - xpForNextLevel = xpForNextLevel(--level); - if (xpForNextLevel >= xp) { - total -= xp; - removed += xp; - - entity.setExp(1F / xpForNextLevel * (xpForNextLevel - xp)); - entity.setTotalExperience(total); - entity.setLevel(level); - return removed; - } - - xp -= xpForNextLevel; - total -= xpForNextLevel; - removed += xpForNextLevel; - } while (level > 0); - - entity.setExp(0F); - entity.setTotalExperience(0); - entity.setLevel(0); - return removed; - } - - public static int getTotalExp(Player entity) { - int rv = 0; - int level = Math.min(entity.getLevel(), 20000); - for (int i = 0; i < level; i++) { - rv += xpForNextLevel(i); - } - rv += Math.min(1F, Math.max(0F, entity.getExp())) * xpForNextLevel(level); - return rv; - } - - public static double getTotalExpLevels(Player entity) { - int xp = entity.getTotalExperience(); - - int level = 0; - while (xp > 0 && level < 20000) { - int needed = xpForNextLevel(level); - if (needed > xp) { - return level + ((double) xp / needed); - } - xp -= needed; - level++; - } - - return level; - } - - public static int getNearbyPlayerCount(Player origin, double range, Predicate predicate) { - List entities = origin.getNearbyEntities(range, range, range); - int result = 0; - for (Entity entity : entities) { - if (entity.getType() == EntityType.PLAYER && predicate.test((Player) entity)) { - result++; - } - } - return result; - } - - public static void getNearbyPlayers(Player origin, double range, Collection collection, Predicate predicate) { - List entities = origin.getNearbyEntities(range, range, range); - for (Entity entity : entities) { - if (entity.getType() == EntityType.PLAYER && predicate.test((Player) entity)) { - collection.add((Player) entity); - } - } - } - - public static void forEachNearbyPlayer(Player origin, double range, Consumer action) { - List entities = origin.getNearbyEntities(range, range, range); - for (Entity entity : entities) { - if (entity.getType() == EntityType.PLAYER) { - action.accept((Player) entity); - } - } - } - - public static double distanceSquared(Location first, Location second) { - double dx = first.getX() - second.getX(); - double dy = first.getY() - second.getY(); - double dz = first.getZ() - second.getZ(); - - return dx * dx + dy * dy + dz * dz; - } - - - public static Iterator findNearbyEntities(Entity origin, boolean includeSelf, Predicate predicate, double horizontalRange, double verticalRange) { - Objects.requireNonNull(origin); - return new Iterator() { - Entity next; - List nearby; - int index = 0; - int size; - - { - if (includeSelf) { - next = origin; - } else { - next = findNext(); - } - } - - Entity findNext() { - if (nearby == null) { - nearby = origin.getNearbyEntities(horizontalRange, verticalRange, horizontalRange); - size = nearby.size(); - } - - while (index < size) { - Entity e = nearby.get(index++); - if (predicate.test(e)) { - return e; - } - } - - return null; - } - - @Override - public boolean hasNext() { - return next != null; - } - - @Override - public T next() { - if (next == null) { - throw new NoSuchElementException(); - } - Entity result = next; - next = findNext(); - //noinspection unchecked - return (T) result; - } - - }; - } - - -} +package io.dico.dicore; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.block.BlockState; +import org.bukkit.configuration.serialization.ConfigurationSerializable; +import org.bukkit.entity.*; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.InventoryHolder; +import org.bukkit.inventory.ItemStack; +import org.bukkit.material.Attachable; +import org.bukkit.material.MaterialData; +import org.bukkit.projectiles.ProjectileSource; + +import java.util.*; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.Predicate; + +public class SpigotUtil { + + private SpigotUtil() { + throw new UnsupportedOperationException(); + } + + public static World matchWorld(String input) { + try { + UUID uid = UUID.fromString(input); + World world = Bukkit.getWorld(uid); + if (world != null) { + return world; + } + } catch (IllegalArgumentException ignored) { + } + + World result = Bukkit.getWorld(input); + if (result == null) { + input = input.toLowerCase().replace("_", "").replaceAll("[-_]", ""); + for (World world : Bukkit.getWorlds()) { + if (world.getName().toLowerCase().equals(input)) { + result = world; + break; + } + } + } + + return result; + } + + public static Block getSupportingBlock(Block block) { + MaterialData data = block.getState().getData(); + if (data instanceof Attachable) { + BlockFace attachedOn = ((Attachable) data).getAttachedFace(); + return block.getRelative(attachedOn); + } + return null; + } + + public static boolean isItemPresent(ItemStack stack) { + return stack != null && stack.getType() != Material.AIR && stack.getAmount() > 0; + } + + public static boolean removeItems(Inventory from, ItemStack item, int amount) { + for (Map.Entry entry : from.all(item.getType()).entrySet()) { + ItemStack stack = entry.getValue(); + if (item.isSimilar(stack)) { + amount -= stack.getAmount(); + int stackAmount = -Math.min(0, amount); + if (stackAmount == 0) { + from.setItem(entry.getKey(), null); + } else { + stack.setAmount(stackAmount); + } + } + } + return amount <= 0; + } + + public static BlockFace yawToFace(float yaw) { + if ((yaw %= 360) < 0) + yaw += 360; + if (45 <= yaw && yaw < 135) + return BlockFace.WEST; + if (135 <= yaw && yaw < 225) + return BlockFace.NORTH; + if (225 <= yaw && yaw < 315) + return BlockFace.EAST; + return BlockFace.SOUTH; + } + + public static void addItems(InventoryHolder entity, ItemStack... items) { + Location dropLocation; + if (entity instanceof Entity) { + dropLocation = ((Entity) entity).getLocation(); + } else if (entity instanceof BlockState) { + dropLocation = ((BlockState) entity).getLocation().add(0.5, 1, 0.5); + } else { + throw new IllegalArgumentException("Can't find location of this InventoryHolder: " + entity); + } + World world = dropLocation.getWorld(); + for (ItemStack toDrop : entity.getInventory().addItem(items).values()) { + world.dropItemNaturally(dropLocation, toDrop); + } + } + + public static String asJsonString(Object object) { + return asJsonString(null, object, 0); + } + + public static String asJsonString(String key, Object object, int indentation) { + String indent = new String(new char[indentation * 2]).replace('\0', ' '); + StringBuilder builder = new StringBuilder(indent); + if (key != null) { + builder.append(key).append(": "); + } + if (object instanceof ConfigurationSerializable) { + object = ((ConfigurationSerializable) object).serialize(); + } + if (object instanceof Map) { + builder.append("{\n"); + Map map = (Map) object; + for (Map.Entry entry : map.entrySet()) { + builder.append(asJsonString(String.valueOf(entry.getKey()), entry.getValue(), indentation + 1)); + } + builder.append(indent).append("}"); + } else if (object instanceof List) { + builder.append("[\n"); + List list = (List) object; + for (Object entry : list) { + builder.append(asJsonString(null, entry, indentation + 1)); + } + builder.append(indent).append("]"); + } else { + builder.append(String.valueOf(object)); + } + return builder.append(",\n").toString(); + } + + public static String asJsonString(String key, Object object, int indentation, BiConsumer, StringBuilder> listHeader) { + String indent = new String(new char[indentation * 2]).replace('\0', ' '); + StringBuilder builder = new StringBuilder(indent); + if (key != null) { + builder.append(key).append(": "); + } + if (object instanceof ConfigurationSerializable) { + object = ((ConfigurationSerializable) object).serialize(); + } + if (object instanceof Map) { + builder.append("{\n"); + Map map = (Map) object; + for (Map.Entry entry : map.entrySet()) { + builder.append(asJsonString(String.valueOf(entry.getKey()), entry.getValue(), indentation + 1, listHeader)); + } + builder.append(indent).append("}"); + } else if (object instanceof List) { + builder.append("["); + List list = (List) object; + listHeader.accept(list, builder); + builder.append("\n"); + for (Object entry : list) { + builder.append(asJsonString(null, entry, indentation + 1, listHeader)); + } + builder.append(indent).append("]"); + } else { + builder.append(String.valueOf(object)); + } + return builder.append(",\n").toString(); + } + + public static BlockFace estimateDirectionTo(Location from, Location to) { + double dx = from.getX() - to.getX(); + double dz = from.getZ() - to.getZ(); + + boolean xGreater = Math.abs(dx) - Math.abs(dz) > 0; + double f = xGreater ? 2 / Math.abs(dx) : 2 / Math.abs(dz); + dx *= f; + dz *= f; + + double other = Math.abs(xGreater ? dz : dx); + + if (other <= .5) { + return xGreater ? (dx < 0 ? BlockFace.WEST : BlockFace.EAST) : (dz < 0 ? BlockFace.NORTH : BlockFace.SOUTH); + } + + if (other < 1.5) { + if (xGreater) { + return dx < 0 ? (dz < 0 ? BlockFace.WEST_NORTH_WEST : BlockFace.WEST_SOUTH_WEST) : (dz < 0 ? BlockFace.EAST_NORTH_EAST : BlockFace.EAST_SOUTH_EAST); + } + return dx < 0 ? (dz < 0 ? BlockFace.NORTH_NORTH_WEST : BlockFace.SOUTH_SOUTH_WEST) : (dz < 0 ? BlockFace.NORTH_NORTH_EAST : BlockFace.SOUTH_SOUTH_EAST); + } + + return dx < 0 ? (dz < 0 ? BlockFace.NORTH_WEST : BlockFace.SOUTH_WEST) : (dz < 0 ? BlockFace.NORTH_EAST : BlockFace.SOUTH_EAST); + } + + public static Entity findEntityFromDamager(Entity damager, EntityType searched) { + if (damager.getType() == searched) { + return damager; + } + + if (damager instanceof Projectile) { + ProjectileSource shooter = ((Projectile) damager).getShooter(); + if (shooter instanceof Entity && ((Entity) shooter).getType() == searched) { + return (Entity) shooter; + } + return null; + } + + if (damager.getType() == EntityType.PRIMED_TNT) { + Entity source = ((TNTPrimed) damager).getSource(); + if (source.getType() == searched) { + return source; + } + } + + return null; + } + + public static int xpForNextLevel(int currentLevel) { + if (currentLevel >= 30) { + return 112 + (currentLevel - 30) * 9; + } + + if (currentLevel >= 15) { + return 37 + (currentLevel - 15) * 5; + } + + return 7 + currentLevel * 2; + } + + public static int removeExp(Player entity, int xp) { + int total = entity.getTotalExperience(); + if (xp > total) { + xp = total; + } + + int level = entity.getLevel(); + if (level < 0) { + return 0; + } + + int removed = 0; + int xpForNextLevel = xpForNextLevel(level); + int current = (int) entity.getExp() * xpForNextLevel; + + if (xp > current) { + xp -= current; + total -= current; + removed += current; + + if (level == 0) { + entity.setExp(0F); + entity.setTotalExperience(total); + return removed; + } + } else { + current -= xp; + total -= xp; + removed += xp; + + entity.setExp((float) current / xpForNextLevel); + entity.setTotalExperience(total); + return removed; + } + + do { + xpForNextLevel = xpForNextLevel(--level); + if (xpForNextLevel >= xp) { + total -= xp; + removed += xp; + + entity.setExp(1F / xpForNextLevel * (xpForNextLevel - xp)); + entity.setTotalExperience(total); + entity.setLevel(level); + return removed; + } + + xp -= xpForNextLevel; + total -= xpForNextLevel; + removed += xpForNextLevel; + } while (level > 0); + + entity.setExp(0F); + entity.setTotalExperience(0); + entity.setLevel(0); + return removed; + } + + public static int getTotalExp(Player entity) { + int rv = 0; + int level = Math.min(entity.getLevel(), 20000); + for (int i = 0; i < level; i++) { + rv += xpForNextLevel(i); + } + rv += Math.min(1F, Math.max(0F, entity.getExp())) * xpForNextLevel(level); + return rv; + } + + public static double getTotalExpLevels(Player entity) { + int xp = entity.getTotalExperience(); + + int level = 0; + while (xp > 0 && level < 20000) { + int needed = xpForNextLevel(level); + if (needed > xp) { + return level + ((double) xp / needed); + } + xp -= needed; + level++; + } + + return level; + } + + public static int getNearbyPlayerCount(Player origin, double range, Predicate predicate) { + List entities = origin.getNearbyEntities(range, range, range); + int result = 0; + for (Entity entity : entities) { + if (entity.getType() == EntityType.PLAYER && predicate.test((Player) entity)) { + result++; + } + } + return result; + } + + public static void getNearbyPlayers(Player origin, double range, Collection collection, Predicate predicate) { + List entities = origin.getNearbyEntities(range, range, range); + for (Entity entity : entities) { + if (entity.getType() == EntityType.PLAYER && predicate.test((Player) entity)) { + collection.add((Player) entity); + } + } + } + + public static void forEachNearbyPlayer(Player origin, double range, Consumer action) { + List entities = origin.getNearbyEntities(range, range, range); + for (Entity entity : entities) { + if (entity.getType() == EntityType.PLAYER) { + action.accept((Player) entity); + } + } + } + + public static double distanceSquared(Location first, Location second) { + double dx = first.getX() - second.getX(); + double dy = first.getY() - second.getY(); + double dz = first.getZ() - second.getZ(); + + return dx * dx + dy * dy + dz * dz; + } + + + public static Iterator findNearbyEntities(Entity origin, boolean includeSelf, Predicate predicate, double horizontalRange, double verticalRange) { + Objects.requireNonNull(origin); + return new Iterator() { + Entity next; + List nearby; + int index = 0; + int size; + + { + if (includeSelf) { + next = origin; + } else { + next = findNext(); + } + } + + Entity findNext() { + if (nearby == null) { + nearby = origin.getNearbyEntities(horizontalRange, verticalRange, horizontalRange); + size = nearby.size(); + } + + while (index < size) { + Entity e = nearby.get(index++); + if (predicate.test(e)) { + return e; + } + } + + return null; + } + + @Override + public boolean hasNext() { + return next != null; + } + + @Override + public T next() { + if (next == null) { + throw new NoSuchElementException(); + } + Entity result = next; + next = findNext(); + //noinspection unchecked + return (T) result; + } + + }; + } + + +} diff --git a/dicore3/core/src/main/java/io/dico/dicore/StringUtil.java b/dicore3/core/src/main/java/io/dico/dicore/StringUtil.java index 62a389e..fb76755 100644 --- a/dicore3/core/src/main/java/io/dico/dicore/StringUtil.java +++ b/dicore3/core/src/main/java/io/dico/dicore/StringUtil.java @@ -1,473 +1,473 @@ -package io.dico.dicore; - -import java.util.*; -import java.util.concurrent.TimeUnit; -import java.util.stream.IntStream; - -public class StringUtil { - - public static String capitalize(String input) { - if (input.length() > 0) { - char first = input.charAt(0); - if (first != (first = Character.toUpperCase(first))) { - char[] result = input.toCharArray(); - result[0] = first; - return String.valueOf(result); - } - } - return input; - } - - /** - * Capitalizes the first character of the string or the first character of each word - * - * @param input the string to capitalize - * @param spaceChar the character separating each word. If @code '\0' is passed, only the first character of - * the input is capitalized. - * @return the capitalized string - */ - public static String capitalize(String input, char spaceChar) { - if (spaceChar == '\0') { - return capitalize(input); - } - - char[] result = null; - boolean capitalize = true; - for (int n = input.length(), i = 0; i < n; i++) { - char c = input.charAt(i); - if (capitalize && c != (c = Character.toUpperCase(c))) { - if (result == null) result = input.toCharArray(); - result[i] = c; - } - capitalize = c == spaceChar; - } - return result != null ? String.valueOf(result) : input; - } - - public static String capitalize(String input, char spaceChar, char newSpaceChar) { - if (newSpaceChar == '\0') { - return capitalize(input, spaceChar); - } - - char[] result = null; - boolean capitalize = true; - for (int n = input.length(), i = 0; i < n; i++) { - char c = input.charAt(i); - if (capitalize && c != (c = Character.toUpperCase(c))) { - if (result == null) result = input.toCharArray(); - result[i] = c; - } - if (capitalize = c == spaceChar) { - if (result == null) result = input.toCharArray(); - result[i] = newSpaceChar; - } - } - return result != null ? String.valueOf(result) : input; - } - - /** - * Returns a lowercase version of the input with _ replaced with a space. - * Mainly used for making names of enum constants readable. - * - * @param input - * @return a humanified version of @code input - */ - public static String humanify(String input) { - return input == null ? null : input.toLowerCase().replace('_', ' '); - } - - /** - * Enumerate the given items, separating them by ", " and finally by " and " - * - * @param words the items to enumerate (it's not really enumerating....) - * @return the enumerated string - */ - public static String enumerate(String... words) { - StringBuilder result = new StringBuilder(); - int size = words.length; - int secondLastIndex = size - 2; - for (int i = 0; i < size; i++) { - String word = words[i]; - if (word.isEmpty()) - continue; - result.append(word); - if (i < secondLastIndex) - result.append(", "); - else if (i == secondLastIndex) - result.append(" and "); - } - return result.toString(); - } - - public static String enumerate(String list, String regex) { - return enumerate(list.split(regex)); - } - - /** - * Return a formatted string of the length in millis, containing days, hours and minutes. - * - * @param length The delay in milliseconds - * @return the formatted string - */ - public static String getTimeLength(long length) { - int minute = 60000; // in millis - int hour = 60 * minute; - int day = 24 * hour; - - int minutes = (int) ((length / minute) % 60); - int hours = (int) ((length / hour) % 24); - int days = (int) (length / day); //returns floor - - String result = ""; // It will be splitted at "|" - if (days != 0) - result += days + " days|"; - if (hours != 0) - result += hours + " hours|"; - if (minutes != 0) - result += minutes + " minutes|"; - return enumerate(result.split("\\|")); - } - - /** - * Return a formatted String to represent the given time length, in the given units - * - * @param sourceAmount Amount of delay - * @param sourceUnit Unit of delay - * @param ifEmpty the String to return if the - * @param displayedUnits units displayed - * @return the formatted string - * @throws IllegalArgumentException if there are no displayed units - */ - public static String getTimeLength(long sourceAmount, TimeUnit sourceUnit, String ifEmpty, TimeUnit... displayedUnits) { - if (displayedUnits.length == 0) { - throw new IllegalArgumentException("No displayed units"); - } - Arrays.sort(displayedUnits, Collections.reverseOrder(TimeUnit::compareTo)); // sort by opposite of enum declaration order (largest -> smallest) - List segments = new ArrayList<>(displayedUnits.length); - for (TimeUnit unit : displayedUnits) { - long displayedAmount = unit.convert(sourceAmount, sourceUnit); - sourceAmount -= sourceUnit.convert(displayedAmount, unit); - if (displayedAmount > 0) { - String unitWord = unit.name().toLowerCase(); // plural - if (displayedAmount == 1) { - unitWord = unitWord.substring(0, unitWord.length() - 1); // remove s at the end - } - segments.add(displayedAmount + " " + unitWord); - } - } - return segments.isEmpty() ? ifEmpty : enumerate(segments.toArray(new String[segments.size()])); - } - - /** - * Returns the delay represented by a ban-like delay representation, in milliseconds - * Example: "5d2h5m3s" for 5 days, 2 hours, 5 minutes and 3 seconds. - *

- * Supported characters are s, m, h, d, w. - * Negative numbers are supported. - * - * @param input The input string - * @return The delay in milliseconds - * @throws IllegalArgumentException if the input string isn't properly formatted, or any non-digit character isn't recognized (capitals are not recognized). - */ - public static long getTimeLength(String input) { //if -1: error - long count = 0; - int i = 0; - while (i < input.length()) { - int num = 0; - char unit = '\0'; - boolean negate; - if (negate = input.charAt(i) == '-') { - i++; - } - do { - char c = input.charAt(i); - int digit = c - '0'; - if (0 <= digit && digit < 10) { - num = 10 * num + digit; - } else { - unit = c; - break; - } - } while (i < input.length()); - - long unitTime = getUnitTime(unit); - if (unitTime == -1) - throw new IllegalArgumentException(); - if (negate) { - unitTime = -unitTime; - } - count += (num * unitTime); - } - return count; - } - - /** - * Returns the time represented by the given unit character in milliseconds. - *

- * 's' -> 1000 - * 'm' -> 1000 * 60 - * 'h' -> 1000 * 60 * 60 - * 'd' -> 1000 * 60 * 60 * 24 - * 'w' -> 1000 * 60 * 60 * 24 * 7 - * anything else -> -1 - * - * @param unit The unit character, as shown above - * @return the millisecond delay represented by the unit - */ - public static long getUnitTime(char unit) { //if -1: no value found - switch (Character.toLowerCase(unit)) { - case 's': - return 1000; - case 'm': - return 1000 * 60; - case 'h': - return 1000 * 60 * 60; - case 'd': - return 1000 * 60 * 60 * 24; - case 'w': - return 1000 * 60 * 60 * 24 * 7; - default: - return -1; - } - } - - /** - * Computes a binary representation of the value. - * The returned representation always displays 64 bits. - * Every 8 bits, the digits are seperated by an _ - * The representation is prefixed by 0b. - *

- * Example: 0b00000000_11111111_00000001_11110000_00001111_11001100_00001111_10111010 - * - * @param entry the value to represent in binary - * @return A binary representation of the long value - */ - public static String toBinaryString(long entry) { - String binary = Long.toBinaryString(entry); - String binary64 = String.valueOf(new char[64 - binary.length()]).replace('\0', '0') + binary; - String withUnderscores = String.join("_", IntStream.range(0, 8).mapToObj(x -> binary64.substring(x * 8, x * 8 + 8)).toArray(String[]::new)); - return "0b" + withUnderscores; - } - - /** - * Turns a generic java classname into a name formatted properly to be an enum constant. - * - * @param name The string value I'd describe as a generic java classname (so we have CapitalCase) - * @return An enum constant version of it (ENUM_FORMAT: CAPITAL_CASE) - */ - public static String toEnumFormat(String name) { - StringBuilder result = new StringBuilder(name.length() + 2); - - boolean capital = true; - for (int i = 0, n = name.length(); i < n; i++) { - char c = name.charAt(i); - if (capital) { - capital = Character.isUpperCase(c); - } else if (Character.isUpperCase(c)) { - capital = true; - result.append('_'); - } - result.append(capital ? c : Character.toUpperCase(c)); - } - - return result.toString(); - } - - /** - * Replaces any occurrence of toReplace with another string. - * Any colours that occured before the occurence of toReplace, are copied to the end of the replacement. - * - * @param target The String to query - * @param toReplace The sequence to replace - * @param with the replacing sequence - * @return the result - */ - public static String replaceKeepColours(String target, String toReplace, String with) { - int index = -toReplace.length(); - while ((index = target.indexOf(toReplace, index + toReplace.length())) != -1) { - String start = target.substring(0, index); - Formatting coloursBefore = Formatting.getFormats(start); - String after; - try { - after = target.substring(index + toReplace.length()); - } catch (IndexOutOfBoundsException e) { - after = ""; - } - target = start + with + coloursBefore + after; - } - return target; - } - - public static String replParam(String target, String param, Object repl) { - return replParam(target, param, repl, false); - } - - public static String replParams(String target, String[] params, Object[] repls) { - return replParams(target, params, repls, false, false); - } - - public static boolean replParams(String[] target, String[] params, Object[] repls) { - return replParams(target, 0, target.length, params, repls); - } - - public static boolean replParams(String[] target, int from, int to, String[] params, Object[] repls) { - return replParams(target, from, to, params, repls, false); - } - - public static boolean replParams(List target, String[] params, Object[] repls) { - return replParams(target, 0, target.size(), params, repls); - } - - public static boolean replParams(List target, int from, int to, String[] params, Object[] repls) { - return replParams(target, from, to, params, repls, false); - } - - public static String replParamAndTranslate(String target, String param, Object repl) { - return replParam(target, param, repl, true); - } - - public static String replParamsAndTranslate(String target, String[] params, Object[] repls) { - return replParams(target, params, repls, false, true); - } - - public static boolean replParamsAndTranslate(String[] target, String[] params, Object[] repls) { - return replParamsAndTranslate(target, 0, target.length, params, repls); - } - - public static boolean replParamsAndTranslate(String[] target, int from, int to, String[] params, Object[] repls) { - return replParams(target, from, to, params, repls, true); - } - - public static boolean replParamsAndTranslate(List target, String[] params, Object[] repls) { - return replParamsAndTranslate(target, 0, target.size(), params, repls); - } - - public static boolean replParamsAndTranslate(List target, int from, int to, String[] params, Object[] repls) { - return replParams(target, from, to, params, repls, true); - } - - private static String replParam(String target, String param, Object replacementObj, boolean translate) { - int idx = target.indexOf(param, 0); - if (idx == -1) { - return translate ? Formatting.translate(target) : target; - } - - String rep = replacementObj.toString(); - StringBuilder builder = new StringBuilder(target); - do { - builder.replace(idx, idx + param.length(), rep); - idx = builder.indexOf(param, idx + rep.length()); - } while (idx != -1); - - if (translate) { - Formatting.translate(builder); - } - - return builder.toString(); - } - - @SuppressWarnings("StringEquality") - private static boolean replParams(String[] target, int from, int to, String[] params, Object[] repls, boolean translate) { - if (from < 0 || to < from || to > target.length) { - throw new IllegalArgumentException("Invalid from-to for array size " + target.length + ": " + from + "-" + to); - } - - boolean change = false; - for (int i = from; i < to; i++) { - String val = target[i]; - if (val != (val = replParams(val, params, repls, true, translate))) { - target[i] = val; - change = true; - } - } - return change; - } - - @SuppressWarnings("StringEquality") - private static boolean replParams(List target, int from, int to, String[] params, Object[] repls, boolean translate) { - if (from < 0 || to < from || to > target.size()) { - throw new IllegalArgumentException("Invalid from-to for list size " + target.size() + ": " + from + "-" + to); - } - - boolean change = false; - if (target instanceof RandomAccess) { - for (int i = from; i < to; i++) { - String val = target.get(i); - if (val != (val = replParams(val, params, repls, true, translate))) { - target.set(i, val); - change = true; - } - } - } else { - ListIterator itr = target.listIterator(from); - for (int n = to - from, i = 0; i < n && itr.hasNext(); i++) { - String val = itr.next(); - if (val != (val = replParams(val, params, repls, true, translate))) { - itr.set(val); - change = true; - } - } - } - return change; - } - - private static String replParams(String target, String[] params, Object[] repls, boolean updateRepls, boolean translate) { - int n = params.length; - if (n != repls.length) { - throw new IllegalArgumentException(); - } - - String param = null; - int idx = -1; - int i; - for (i = 0; i < n; i++) { - param = params[i]; - if (param == null) { - continue; - } - idx = target.indexOf(param, 0); - if (idx != -1) { - break; - } - } - - if (idx == -1) { - return translate ? Formatting.translate(target) : target; - } - - String repl = repls[i].toString(); - if (updateRepls) { - repls[i] = repl; - } - - StringBuilder builder = new StringBuilder(target); - do { - builder.replace(idx, idx + param.length(), repl); - idx = builder.indexOf(param, idx + repl.length()); - } while (idx != -1); - - for (i++; i < n; i++) { - param = params[i]; - if (param == null || (idx = builder.indexOf(param, 0)) == -1) { - continue; - } - - repl = repls[i].toString(); - if (updateRepls) { - repls[i] = repl; - } - - do { - builder.replace(idx, idx + param.length(), repl); - idx = builder.indexOf(param, idx + repl.length()); - } while (idx != -1); - } - - if (translate) { - Formatting.translate(builder); - } - - return builder.toString(); - } - -} +package io.dico.dicore; + +import java.util.*; +import java.util.concurrent.TimeUnit; +import java.util.stream.IntStream; + +public class StringUtil { + + public static String capitalize(String input) { + if (input.length() > 0) { + char first = input.charAt(0); + if (first != (first = Character.toUpperCase(first))) { + char[] result = input.toCharArray(); + result[0] = first; + return String.valueOf(result); + } + } + return input; + } + + /** + * Capitalizes the first character of the string or the first character of each word + * + * @param input the string to capitalize + * @param spaceChar the character separating each word. If @code '\0' is passed, only the first character of + * the input is capitalized. + * @return the capitalized string + */ + public static String capitalize(String input, char spaceChar) { + if (spaceChar == '\0') { + return capitalize(input); + } + + char[] result = null; + boolean capitalize = true; + for (int n = input.length(), i = 0; i < n; i++) { + char c = input.charAt(i); + if (capitalize && c != (c = Character.toUpperCase(c))) { + if (result == null) result = input.toCharArray(); + result[i] = c; + } + capitalize = c == spaceChar; + } + return result != null ? String.valueOf(result) : input; + } + + public static String capitalize(String input, char spaceChar, char newSpaceChar) { + if (newSpaceChar == '\0') { + return capitalize(input, spaceChar); + } + + char[] result = null; + boolean capitalize = true; + for (int n = input.length(), i = 0; i < n; i++) { + char c = input.charAt(i); + if (capitalize && c != (c = Character.toUpperCase(c))) { + if (result == null) result = input.toCharArray(); + result[i] = c; + } + if (capitalize = c == spaceChar) { + if (result == null) result = input.toCharArray(); + result[i] = newSpaceChar; + } + } + return result != null ? String.valueOf(result) : input; + } + + /** + * Returns a lowercase version of the input with _ replaced with a space. + * Mainly used for making names of enum constants readable. + * + * @param input + * @return a humanified version of @code input + */ + public static String humanify(String input) { + return input == null ? null : input.toLowerCase().replace('_', ' '); + } + + /** + * Enumerate the given items, separating them by ", " and finally by " and " + * + * @param words the items to enumerate (it's not really enumerating....) + * @return the enumerated string + */ + public static String enumerate(String... words) { + StringBuilder result = new StringBuilder(); + int size = words.length; + int secondLastIndex = size - 2; + for (int i = 0; i < size; i++) { + String word = words[i]; + if (word.isEmpty()) + continue; + result.append(word); + if (i < secondLastIndex) + result.append(", "); + else if (i == secondLastIndex) + result.append(" and "); + } + return result.toString(); + } + + public static String enumerate(String list, String regex) { + return enumerate(list.split(regex)); + } + + /** + * Return a formatted string of the length in millis, containing days, hours and minutes. + * + * @param length The delay in milliseconds + * @return the formatted string + */ + public static String getTimeLength(long length) { + int minute = 60000; // in millis + int hour = 60 * minute; + int day = 24 * hour; + + int minutes = (int) ((length / minute) % 60); + int hours = (int) ((length / hour) % 24); + int days = (int) (length / day); //returns floor + + String result = ""; // It will be splitted at "|" + if (days != 0) + result += days + " days|"; + if (hours != 0) + result += hours + " hours|"; + if (minutes != 0) + result += minutes + " minutes|"; + return enumerate(result.split("\\|")); + } + + /** + * Return a formatted String to represent the given time length, in the given units + * + * @param sourceAmount Amount of delay + * @param sourceUnit Unit of delay + * @param ifEmpty the String to return if the + * @param displayedUnits units displayed + * @return the formatted string + * @throws IllegalArgumentException if there are no displayed units + */ + public static String getTimeLength(long sourceAmount, TimeUnit sourceUnit, String ifEmpty, TimeUnit... displayedUnits) { + if (displayedUnits.length == 0) { + throw new IllegalArgumentException("No displayed units"); + } + Arrays.sort(displayedUnits, Collections.reverseOrder(TimeUnit::compareTo)); // sort by opposite of enum declaration order (largest -> smallest) + List segments = new ArrayList<>(displayedUnits.length); + for (TimeUnit unit : displayedUnits) { + long displayedAmount = unit.convert(sourceAmount, sourceUnit); + sourceAmount -= sourceUnit.convert(displayedAmount, unit); + if (displayedAmount > 0) { + String unitWord = unit.name().toLowerCase(); // plural + if (displayedAmount == 1) { + unitWord = unitWord.substring(0, unitWord.length() - 1); // remove s at the end + } + segments.add(displayedAmount + " " + unitWord); + } + } + return segments.isEmpty() ? ifEmpty : enumerate(segments.toArray(new String[segments.size()])); + } + + /** + * Returns the delay represented by a ban-like delay representation, in milliseconds + * Example: "5d2h5m3s" for 5 days, 2 hours, 5 minutes and 3 seconds. + *

+ * Supported characters are s, m, h, d, w. + * Negative numbers are supported. + * + * @param input The input string + * @return The delay in milliseconds + * @throws IllegalArgumentException if the input string isn't properly formatted, or any non-digit character isn't recognized (capitals are not recognized). + */ + public static long getTimeLength(String input) { //if -1: error + long count = 0; + int i = 0; + while (i < input.length()) { + int num = 0; + char unit = '\0'; + boolean negate; + if (negate = input.charAt(i) == '-') { + i++; + } + do { + char c = input.charAt(i); + int digit = c - '0'; + if (0 <= digit && digit < 10) { + num = 10 * num + digit; + } else { + unit = c; + break; + } + } while (i < input.length()); + + long unitTime = getUnitTime(unit); + if (unitTime == -1) + throw new IllegalArgumentException(); + if (negate) { + unitTime = -unitTime; + } + count += (num * unitTime); + } + return count; + } + + /** + * Returns the time represented by the given unit character in milliseconds. + *

+ * 's' -> 1000 + * 'm' -> 1000 * 60 + * 'h' -> 1000 * 60 * 60 + * 'd' -> 1000 * 60 * 60 * 24 + * 'w' -> 1000 * 60 * 60 * 24 * 7 + * anything else -> -1 + * + * @param unit The unit character, as shown above + * @return the millisecond delay represented by the unit + */ + public static long getUnitTime(char unit) { //if -1: no value found + switch (Character.toLowerCase(unit)) { + case 's': + return 1000; + case 'm': + return 1000 * 60; + case 'h': + return 1000 * 60 * 60; + case 'd': + return 1000 * 60 * 60 * 24; + case 'w': + return 1000 * 60 * 60 * 24 * 7; + default: + return -1; + } + } + + /** + * Computes a binary representation of the value. + * The returned representation always displays 64 bits. + * Every 8 bits, the digits are seperated by an _ + * The representation is prefixed by 0b. + *

+ * Example: 0b00000000_11111111_00000001_11110000_00001111_11001100_00001111_10111010 + * + * @param entry the value to represent in binary + * @return A binary representation of the long value + */ + public static String toBinaryString(long entry) { + String binary = Long.toBinaryString(entry); + String binary64 = String.valueOf(new char[64 - binary.length()]).replace('\0', '0') + binary; + String withUnderscores = String.join("_", IntStream.range(0, 8).mapToObj(x -> binary64.substring(x * 8, x * 8 + 8)).toArray(String[]::new)); + return "0b" + withUnderscores; + } + + /** + * Turns a generic java classname into a name formatted properly to be an enum constant. + * + * @param name The string value I'd describe as a generic java classname (so we have CapitalCase) + * @return An enum constant version of it (ENUM_FORMAT: CAPITAL_CASE) + */ + public static String toEnumFormat(String name) { + StringBuilder result = new StringBuilder(name.length() + 2); + + boolean capital = true; + for (int i = 0, n = name.length(); i < n; i++) { + char c = name.charAt(i); + if (capital) { + capital = Character.isUpperCase(c); + } else if (Character.isUpperCase(c)) { + capital = true; + result.append('_'); + } + result.append(capital ? c : Character.toUpperCase(c)); + } + + return result.toString(); + } + + /** + * Replaces any occurrence of toReplace with another string. + * Any colours that occured before the occurence of toReplace, are copied to the end of the replacement. + * + * @param target The String to query + * @param toReplace The sequence to replace + * @param with the replacing sequence + * @return the result + */ + public static String replaceKeepColours(String target, String toReplace, String with) { + int index = -toReplace.length(); + while ((index = target.indexOf(toReplace, index + toReplace.length())) != -1) { + String start = target.substring(0, index); + Formatting coloursBefore = Formatting.getFormats(start); + String after; + try { + after = target.substring(index + toReplace.length()); + } catch (IndexOutOfBoundsException e) { + after = ""; + } + target = start + with + coloursBefore + after; + } + return target; + } + + public static String replParam(String target, String param, Object repl) { + return replParam(target, param, repl, false); + } + + public static String replParams(String target, String[] params, Object[] repls) { + return replParams(target, params, repls, false, false); + } + + public static boolean replParams(String[] target, String[] params, Object[] repls) { + return replParams(target, 0, target.length, params, repls); + } + + public static boolean replParams(String[] target, int from, int to, String[] params, Object[] repls) { + return replParams(target, from, to, params, repls, false); + } + + public static boolean replParams(List target, String[] params, Object[] repls) { + return replParams(target, 0, target.size(), params, repls); + } + + public static boolean replParams(List target, int from, int to, String[] params, Object[] repls) { + return replParams(target, from, to, params, repls, false); + } + + public static String replParamAndTranslate(String target, String param, Object repl) { + return replParam(target, param, repl, true); + } + + public static String replParamsAndTranslate(String target, String[] params, Object[] repls) { + return replParams(target, params, repls, false, true); + } + + public static boolean replParamsAndTranslate(String[] target, String[] params, Object[] repls) { + return replParamsAndTranslate(target, 0, target.length, params, repls); + } + + public static boolean replParamsAndTranslate(String[] target, int from, int to, String[] params, Object[] repls) { + return replParams(target, from, to, params, repls, true); + } + + public static boolean replParamsAndTranslate(List target, String[] params, Object[] repls) { + return replParamsAndTranslate(target, 0, target.size(), params, repls); + } + + public static boolean replParamsAndTranslate(List target, int from, int to, String[] params, Object[] repls) { + return replParams(target, from, to, params, repls, true); + } + + private static String replParam(String target, String param, Object replacementObj, boolean translate) { + int idx = target.indexOf(param, 0); + if (idx == -1) { + return translate ? Formatting.translate(target) : target; + } + + String rep = replacementObj.toString(); + StringBuilder builder = new StringBuilder(target); + do { + builder.replace(idx, idx + param.length(), rep); + idx = builder.indexOf(param, idx + rep.length()); + } while (idx != -1); + + if (translate) { + Formatting.translate(builder); + } + + return builder.toString(); + } + + @SuppressWarnings("StringEquality") + private static boolean replParams(String[] target, int from, int to, String[] params, Object[] repls, boolean translate) { + if (from < 0 || to < from || to > target.length) { + throw new IllegalArgumentException("Invalid from-to for array size " + target.length + ": " + from + "-" + to); + } + + boolean change = false; + for (int i = from; i < to; i++) { + String val = target[i]; + if (val != (val = replParams(val, params, repls, true, translate))) { + target[i] = val; + change = true; + } + } + return change; + } + + @SuppressWarnings("StringEquality") + private static boolean replParams(List target, int from, int to, String[] params, Object[] repls, boolean translate) { + if (from < 0 || to < from || to > target.size()) { + throw new IllegalArgumentException("Invalid from-to for list size " + target.size() + ": " + from + "-" + to); + } + + boolean change = false; + if (target instanceof RandomAccess) { + for (int i = from; i < to; i++) { + String val = target.get(i); + if (val != (val = replParams(val, params, repls, true, translate))) { + target.set(i, val); + change = true; + } + } + } else { + ListIterator itr = target.listIterator(from); + for (int n = to - from, i = 0; i < n && itr.hasNext(); i++) { + String val = itr.next(); + if (val != (val = replParams(val, params, repls, true, translate))) { + itr.set(val); + change = true; + } + } + } + return change; + } + + private static String replParams(String target, String[] params, Object[] repls, boolean updateRepls, boolean translate) { + int n = params.length; + if (n != repls.length) { + throw new IllegalArgumentException(); + } + + String param = null; + int idx = -1; + int i; + for (i = 0; i < n; i++) { + param = params[i]; + if (param == null) { + continue; + } + idx = target.indexOf(param, 0); + if (idx != -1) { + break; + } + } + + if (idx == -1) { + return translate ? Formatting.translate(target) : target; + } + + String repl = repls[i].toString(); + if (updateRepls) { + repls[i] = repl; + } + + StringBuilder builder = new StringBuilder(target); + do { + builder.replace(idx, idx + param.length(), repl); + idx = builder.indexOf(param, idx + repl.length()); + } while (idx != -1); + + for (i++; i < n; i++) { + param = params[i]; + if (param == null || (idx = builder.indexOf(param, 0)) == -1) { + continue; + } + + repl = repls[i].toString(); + if (updateRepls) { + repls[i] = repl; + } + + do { + builder.replace(idx, idx + param.length(), repl); + idx = builder.indexOf(param, idx + repl.length()); + } while (idx != -1); + } + + if (translate) { + Formatting.translate(builder); + } + + return builder.toString(); + } + +} diff --git a/dicore3/core/src/main/java/io/dico/dicore/Whitelist.java b/dicore3/core/src/main/java/io/dico/dicore/Whitelist.java index 5f8f4e2..e467d91 100644 --- a/dicore3/core/src/main/java/io/dico/dicore/Whitelist.java +++ b/dicore3/core/src/main/java/io/dico/dicore/Whitelist.java @@ -1,91 +1,91 @@ -package io.dico.dicore; - -import org.bukkit.configuration.ConfigurationSection; - -import java.util.*; -import java.util.function.Function; -import java.util.function.Predicate; -import java.util.stream.Collectors; - -@FunctionalInterface -public interface Whitelist extends Predicate { - - Whitelist EVERYTHING = item -> true; - Whitelist NOTHING = item -> false; - Whitelist NOT_NULL = Objects::nonNull; - - static Predicate everythingAsPredicate() { - return (Predicate) EVERYTHING; - } - - static Predicate nothingAsPredicate() { - return (Predicate) NOTHING; - } - - static Predicate notNullAsPredicate() { - return (Predicate) NOT_NULL; - } - - static Whitelist only(Object item) { - return item::equals; - } - - static Whitelist not(Object item) { - return o -> !item.equals(o); - } - - static Whitelist only(Object item1, Object item2) { - return item -> item1.equals(item) || item2.equals(item); - } - - static Whitelist not(Object item1, Object item2) { - return item -> !(item1.equals(item) || item2.equals(item)); - } - - static Whitelist only(Object[] objects) { - return new SetBasedWhitelist(objects, false); - } - - static Whitelist not(Object[] objects) { - return new SetBasedWhitelist(objects, true); - } - - static Whitelist fromConfig(ConfigurationSection section, Function parser) { - if (section == null) { - return NOTHING; - } - boolean blacklist = section.getBoolean("blacklist", false); - Set list = section.getStringList("listed").stream().map(parser).filter(Objects::nonNull).collect(Collectors.toSet()); - switch (list.size()) { - case 0: - return blacklist ? EVERYTHING : NOTHING; - case 1: { - Iterator iterator = list.iterator(); - return blacklist ? not(iterator.next()) : only(iterator.next()); - } - case 2: { - Iterator iterator = list.iterator(); - return blacklist ? not(iterator.next(), iterator.next()) : only(iterator.next(), iterator.next()); - } - default: - Object item = list.iterator().next(); - if (item instanceof Enum) { - list = EnumSet.copyOf(list); - } - return new SetBasedWhitelist(list, blacklist); - } - } - - static void copyIntoConfig(ConfigurationSection target, Function mapper, boolean blacklist, Object... objects) { - target.set("blacklist", blacklist); - target.set("listed", Arrays.stream(objects).map(mapper).unordered().distinct().collect(Collectors.toList())); - } - - @Override - default boolean test(Object o) { - return isWhitelisted(o); - } - - boolean isWhitelisted(Object o); -} - +package io.dico.dicore; + +import org.bukkit.configuration.ConfigurationSection; + +import java.util.*; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +@FunctionalInterface +public interface Whitelist extends Predicate { + + Whitelist EVERYTHING = item -> true; + Whitelist NOTHING = item -> false; + Whitelist NOT_NULL = Objects::nonNull; + + static Predicate everythingAsPredicate() { + return (Predicate) EVERYTHING; + } + + static Predicate nothingAsPredicate() { + return (Predicate) NOTHING; + } + + static Predicate notNullAsPredicate() { + return (Predicate) NOT_NULL; + } + + static Whitelist only(Object item) { + return item::equals; + } + + static Whitelist not(Object item) { + return o -> !item.equals(o); + } + + static Whitelist only(Object item1, Object item2) { + return item -> item1.equals(item) || item2.equals(item); + } + + static Whitelist not(Object item1, Object item2) { + return item -> !(item1.equals(item) || item2.equals(item)); + } + + static Whitelist only(Object[] objects) { + return new SetBasedWhitelist(objects, false); + } + + static Whitelist not(Object[] objects) { + return new SetBasedWhitelist(objects, true); + } + + static Whitelist fromConfig(ConfigurationSection section, Function parser) { + if (section == null) { + return NOTHING; + } + boolean blacklist = section.getBoolean("blacklist", false); + Set list = section.getStringList("listed").stream().map(parser).filter(Objects::nonNull).collect(Collectors.toSet()); + switch (list.size()) { + case 0: + return blacklist ? EVERYTHING : NOTHING; + case 1: { + Iterator iterator = list.iterator(); + return blacklist ? not(iterator.next()) : only(iterator.next()); + } + case 2: { + Iterator iterator = list.iterator(); + return blacklist ? not(iterator.next(), iterator.next()) : only(iterator.next(), iterator.next()); + } + default: + Object item = list.iterator().next(); + if (item instanceof Enum) { + list = EnumSet.copyOf(list); + } + return new SetBasedWhitelist(list, blacklist); + } + } + + static void copyIntoConfig(ConfigurationSection target, Function mapper, boolean blacklist, Object... objects) { + target.set("blacklist", blacklist); + target.set("listed", Arrays.stream(objects).map(mapper).unordered().distinct().collect(Collectors.toList())); + } + + @Override + default boolean test(Object o) { + return isWhitelisted(o); + } + + boolean isWhitelisted(Object o); +} + diff --git a/dicore3/core/src/main/java/io/dico/dicore/event/ChainedListener.java b/dicore3/core/src/main/java/io/dico/dicore/event/ChainedListener.java index 93584ea..378424d 100644 --- a/dicore3/core/src/main/java/io/dico/dicore/event/ChainedListener.java +++ b/dicore3/core/src/main/java/io/dico/dicore/event/ChainedListener.java @@ -1,46 +1,46 @@ -package io.dico.dicore.event; - -import io.dico.dicore.InterfaceChain; - -public interface ChainedListener extends InterfaceChain, ChainedListener>, SimpleListener { - - @Override - default ChainedListener getEmptyInstance() { - return ChainedListeners.empty(); - } - - @Override - default ChainedListener withElement(SimpleListener element) { - if (element == null) { - return this; - } - - int count = getElementCount() + 1; - return new ChainedListener() { - @Override - public void accept(T event) { - try { - ChainedListener.this.accept(event); - } finally { - element.accept(event); - } - } - - @Override - public ChainedListener withoutLastNode() { - return ChainedListener.this; - } - - @Override - public SimpleListener getDelegateOfLastNode() { - return element; - } - - @Override - public int getElementCount() { - return count; - } - }; - } - -} +package io.dico.dicore.event; + +import io.dico.dicore.InterfaceChain; + +public interface ChainedListener extends InterfaceChain, ChainedListener>, SimpleListener { + + @Override + default ChainedListener getEmptyInstance() { + return ChainedListeners.empty(); + } + + @Override + default ChainedListener withElement(SimpleListener element) { + if (element == null) { + return this; + } + + int count = getElementCount() + 1; + return new ChainedListener() { + @Override + public void accept(T event) { + try { + ChainedListener.this.accept(event); + } finally { + element.accept(event); + } + } + + @Override + public ChainedListener withoutLastNode() { + return ChainedListener.this; + } + + @Override + public SimpleListener getDelegateOfLastNode() { + return element; + } + + @Override + public int getElementCount() { + return count; + } + }; + } + +} diff --git a/dicore3/core/src/main/java/io/dico/dicore/event/ChainedListenerHandle.java b/dicore3/core/src/main/java/io/dico/dicore/event/ChainedListenerHandle.java index 86b8448..875c131 100644 --- a/dicore3/core/src/main/java/io/dico/dicore/event/ChainedListenerHandle.java +++ b/dicore3/core/src/main/java/io/dico/dicore/event/ChainedListenerHandle.java @@ -1,55 +1,55 @@ -package io.dico.dicore.event; - -import io.dico.dicore.InterfaceChain; - -public interface ChainedListenerHandle extends InterfaceChain, ListenerHandle { - - @Override - default ChainedListenerHandle getEmptyInstance() { - return ChainedListenerHandles.empty(); - } - - @Override - default ChainedListenerHandle withElement(ListenerHandle element) { - if (element == null) { - return this; - } - - int count = getElementCount() + 1; - return new ChainedListenerHandle() { - @Override - public void register() { - try { - ChainedListenerHandle.this.register(); - } finally { - element.register(); - } - } - - @Override - public void unregister() { - try { - ChainedListenerHandle.this.unregister(); - } finally { - element.unregister(); - } - } - - @Override - public ChainedListenerHandle withoutLastNode() { - return ChainedListenerHandle.this; - } - - @Override - public ListenerHandle getDelegateOfLastNode() { - return element; - } - - @Override - public int getElementCount() { - return count; - } - }; - } - -} +package io.dico.dicore.event; + +import io.dico.dicore.InterfaceChain; + +public interface ChainedListenerHandle extends InterfaceChain, ListenerHandle { + + @Override + default ChainedListenerHandle getEmptyInstance() { + return ChainedListenerHandles.empty(); + } + + @Override + default ChainedListenerHandle withElement(ListenerHandle element) { + if (element == null) { + return this; + } + + int count = getElementCount() + 1; + return new ChainedListenerHandle() { + @Override + public void register() { + try { + ChainedListenerHandle.this.register(); + } finally { + element.register(); + } + } + + @Override + public void unregister() { + try { + ChainedListenerHandle.this.unregister(); + } finally { + element.unregister(); + } + } + + @Override + public ChainedListenerHandle withoutLastNode() { + return ChainedListenerHandle.this; + } + + @Override + public ListenerHandle getDelegateOfLastNode() { + return element; + } + + @Override + public int getElementCount() { + return count; + } + }; + } + +} diff --git a/dicore3/core/src/main/java/io/dico/dicore/event/ChainedListenerHandles.java b/dicore3/core/src/main/java/io/dico/dicore/event/ChainedListenerHandles.java index 0be0508..15c4553 100644 --- a/dicore3/core/src/main/java/io/dico/dicore/event/ChainedListenerHandles.java +++ b/dicore3/core/src/main/java/io/dico/dicore/event/ChainedListenerHandles.java @@ -1,63 +1,63 @@ -package io.dico.dicore.event; - -public class ChainedListenerHandles { - - private ChainedListenerHandles() { - - } - - private static final ChainedListenerHandle empty = new ChainedListenerHandle() { - @Override - public void register() { - - } - - public void unregister() { - - } - - @Override - public ChainedListenerHandle withElement(ListenerHandle other) { - return ChainedListenerHandles.singleton(other); - } - - @Override - public int getElementCount() { - return 0; - } - - @Override - public ListenerHandle getDelegateOfLastNode() { - return null; - } - }; - - public static ChainedListenerHandle empty() { - return empty; - } - - public static ChainedListenerHandle singleton(ListenerHandle element) { - if (element instanceof ChainedListenerHandle) { - return (ChainedListenerHandle) element; - } - if (element == null) { - return empty(); - } - return new ChainedListenerHandle() { - @Override - public void register() { - element.register(); - } - - public void unregister() { - element.unregister(); - } - - @Override - public ListenerHandle getDelegateOfLastNode() { - return element; - } - }; - } - -} +package io.dico.dicore.event; + +public class ChainedListenerHandles { + + private ChainedListenerHandles() { + + } + + private static final ChainedListenerHandle empty = new ChainedListenerHandle() { + @Override + public void register() { + + } + + public void unregister() { + + } + + @Override + public ChainedListenerHandle withElement(ListenerHandle other) { + return ChainedListenerHandles.singleton(other); + } + + @Override + public int getElementCount() { + return 0; + } + + @Override + public ListenerHandle getDelegateOfLastNode() { + return null; + } + }; + + public static ChainedListenerHandle empty() { + return empty; + } + + public static ChainedListenerHandle singleton(ListenerHandle element) { + if (element instanceof ChainedListenerHandle) { + return (ChainedListenerHandle) element; + } + if (element == null) { + return empty(); + } + return new ChainedListenerHandle() { + @Override + public void register() { + element.register(); + } + + public void unregister() { + element.unregister(); + } + + @Override + public ListenerHandle getDelegateOfLastNode() { + return element; + } + }; + } + +} diff --git a/dicore3/core/src/main/java/io/dico/dicore/event/ChainedListeners.java b/dicore3/core/src/main/java/io/dico/dicore/event/ChainedListeners.java index 1d2bcd4..44050a2 100644 --- a/dicore3/core/src/main/java/io/dico/dicore/event/ChainedListeners.java +++ b/dicore3/core/src/main/java/io/dico/dicore/event/ChainedListeners.java @@ -1,56 +1,56 @@ -package io.dico.dicore.event; - -@SuppressWarnings("unchecked") -public class ChainedListeners { - - private static final ChainedListener empty = new ChainedListener() { - @Override - public void accept(Object event) { - - } - - @Override - public ChainedListener withElement(SimpleListener other) { - return ChainedListeners.singleton(other); - } - - @Override - public int getElementCount() { - return 0; - } - - @Override - public SimpleListener getDelegateOfLastNode() { - return null; - } - }; - - private ChainedListeners() { - - } - - public static ChainedListener empty() { - return (ChainedListener) empty; - } - - public static ChainedListener singleton(SimpleListener element) { - if (element instanceof ChainedListener) { - return (ChainedListener) element; - } - if (element == null) { - return empty(); - } - return new ChainedListener() { - @Override - public void accept(T event) { - element.accept(event); - } - - @Override - public SimpleListener getDelegateOfLastNode() { - return element; - } - }; - } - -} +package io.dico.dicore.event; + +@SuppressWarnings("unchecked") +public class ChainedListeners { + + private static final ChainedListener empty = new ChainedListener() { + @Override + public void accept(Object event) { + + } + + @Override + public ChainedListener withElement(SimpleListener other) { + return ChainedListeners.singleton(other); + } + + @Override + public int getElementCount() { + return 0; + } + + @Override + public SimpleListener getDelegateOfLastNode() { + return null; + } + }; + + private ChainedListeners() { + + } + + public static ChainedListener empty() { + return (ChainedListener) empty; + } + + public static ChainedListener singleton(SimpleListener element) { + if (element instanceof ChainedListener) { + return (ChainedListener) element; + } + if (element == null) { + return empty(); + } + return new ChainedListener() { + @Override + public void accept(T event) { + element.accept(event); + } + + @Override + public SimpleListener getDelegateOfLastNode() { + return element; + } + }; + } + +} diff --git a/dicore3/core/src/main/java/io/dico/dicore/event/HandlerList.java b/dicore3/core/src/main/java/io/dico/dicore/event/HandlerList.java index 56265bb..fa290c0 100644 --- a/dicore3/core/src/main/java/io/dico/dicore/event/HandlerList.java +++ b/dicore3/core/src/main/java/io/dico/dicore/event/HandlerList.java @@ -1,91 +1,91 @@ -package io.dico.dicore.event; - -import org.bukkit.event.Cancellable; -import org.bukkit.event.EventPriority; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import java.util.function.Consumer; - -public final class HandlerList { - private final List> source = new ArrayList<>(); - private Listener[] listeners = newArray(0); - - public void refresh() { - source.sort(Comparator.comparingInt(l -> l.getPriority().ordinal())); - listeners = source.toArray(newArray(source.size())); - } - - @SuppressWarnings("unchecked") - private static Listener[] newArray(int length) { - return new Listener[length]; - } - - public void register(Listener listener) { - if (!source.contains(listener) && source.add(listener)) { - refresh(); - } - } - - public ListenerHandle getListenerHandle(Listener listener) { - return new ListenerHandle() { - @Override - public void register() { - HandlerList.this.register(listener); - } - - @Override - public void unregister() { - HandlerList.this.unregister(listener); - } - }; - } - - public void register(EventPriority priority, Consumer listener) { - register(new Listener() { - @Override - public EventPriority getPriority() { - return priority; - } - - @Override - public void accept(T event) { - listener.accept(event); - } - }); - } - - public List> getRegistrations() { - return Collections.unmodifiableList(source); - } - - public void unregister(Listener listener) { - if (source.remove(listener)) { - refresh(); - } - } - - public void callEvent(T event) { - if (event instanceof Cancellable) { - Cancellable c = (Cancellable) event; - boolean cancelled = c.isCancelled(); - for (Listener listener : listeners) { - if (listener.listensToCancelledState(cancelled)) { - //EnchantsPlugin.getInstance().debug("Listener acceptance: " + listener.getClass().getSimpleName()); - listener.accept(event); - cancelled = c.isCancelled(); - } /*else { - EnchantsPlugin.getInstance().debug("Listener does not listen to cancelled state of " + cancelled + ": " + listener.getClass().getSimpleName()); - }*/ - } - } else { - for (Listener listener : listeners) { - //EnchantsPlugin.getInstance().debug("Listener acceptance: " + listener.getClass().getSimpleName()); - listener.accept(event); - } - } - } - -} +package io.dico.dicore.event; + +import org.bukkit.event.Cancellable; +import org.bukkit.event.EventPriority; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.function.Consumer; + +public final class HandlerList { + private final List> source = new ArrayList<>(); + private Listener[] listeners = newArray(0); + + public void refresh() { + source.sort(Comparator.comparingInt(l -> l.getPriority().ordinal())); + listeners = source.toArray(newArray(source.size())); + } + + @SuppressWarnings("unchecked") + private static Listener[] newArray(int length) { + return new Listener[length]; + } + + public void register(Listener listener) { + if (!source.contains(listener) && source.add(listener)) { + refresh(); + } + } + + public ListenerHandle getListenerHandle(Listener listener) { + return new ListenerHandle() { + @Override + public void register() { + HandlerList.this.register(listener); + } + + @Override + public void unregister() { + HandlerList.this.unregister(listener); + } + }; + } + + public void register(EventPriority priority, Consumer listener) { + register(new Listener() { + @Override + public EventPriority getPriority() { + return priority; + } + + @Override + public void accept(T event) { + listener.accept(event); + } + }); + } + + public List> getRegistrations() { + return Collections.unmodifiableList(source); + } + + public void unregister(Listener listener) { + if (source.remove(listener)) { + refresh(); + } + } + + public void callEvent(T event) { + if (event instanceof Cancellable) { + Cancellable c = (Cancellable) event; + boolean cancelled = c.isCancelled(); + for (Listener listener : listeners) { + if (listener.listensToCancelledState(cancelled)) { + //EnchantsPlugin.getInstance().debug("Listener acceptance: " + listener.getClass().getSimpleName()); + listener.accept(event); + cancelled = c.isCancelled(); + } /*else { + EnchantsPlugin.getInstance().debug("Listener does not listen to cancelled state of " + cancelled + ": " + listener.getClass().getSimpleName()); + }*/ + } + } else { + for (Listener listener : listeners) { + //EnchantsPlugin.getInstance().debug("Listener acceptance: " + listener.getClass().getSimpleName()); + listener.accept(event); + } + } + } + +} diff --git a/dicore3/core/src/main/java/io/dico/dicore/event/Listener.java b/dicore3/core/src/main/java/io/dico/dicore/event/Listener.java index c3e5413..064cd28 100644 --- a/dicore3/core/src/main/java/io/dico/dicore/event/Listener.java +++ b/dicore3/core/src/main/java/io/dico/dicore/event/Listener.java @@ -1,17 +1,17 @@ -package io.dico.dicore.event; - -import org.bukkit.event.EventPriority; - -public interface Listener { - - default EventPriority getPriority() { - return EventPriority.NORMAL; - } - - default boolean listensToCancelledState(boolean cancelled) { - return !cancelled; - } - - void accept(T event); - -} +package io.dico.dicore.event; + +import org.bukkit.event.EventPriority; + +public interface Listener { + + default EventPriority getPriority() { + return EventPriority.NORMAL; + } + + default boolean listensToCancelledState(boolean cancelled) { + return !cancelled; + } + + void accept(T event); + +} diff --git a/dicore3/core/src/main/java/io/dico/dicore/event/ListenerHandle.java b/dicore3/core/src/main/java/io/dico/dicore/event/ListenerHandle.java index 6042954..fbedd9f 100644 --- a/dicore3/core/src/main/java/io/dico/dicore/event/ListenerHandle.java +++ b/dicore3/core/src/main/java/io/dico/dicore/event/ListenerHandle.java @@ -1,9 +1,9 @@ -package io.dico.dicore.event; - -public interface ListenerHandle { - - void register(); - - void unregister(); - -} +package io.dico.dicore.event; + +public interface ListenerHandle { + + void register(); + + void unregister(); + +} diff --git a/dicore3/core/src/main/java/io/dico/dicore/event/SimpleListener.java b/dicore3/core/src/main/java/io/dico/dicore/event/SimpleListener.java index 9688975..4e49a55 100644 --- a/dicore3/core/src/main/java/io/dico/dicore/event/SimpleListener.java +++ b/dicore3/core/src/main/java/io/dico/dicore/event/SimpleListener.java @@ -1,7 +1,7 @@ -package io.dico.dicore.event; - -public interface SimpleListener { - - void accept(T event); - -} +package io.dico.dicore.event; + +public interface SimpleListener { + + void accept(T event); + +} diff --git a/dicore3/core/src/main/java/io/dico/dicore/exceptions/ExceptionHandler.java b/dicore3/core/src/main/java/io/dico/dicore/exceptions/ExceptionHandler.java index e95b65e..2777125 100644 --- a/dicore3/core/src/main/java/io/dico/dicore/exceptions/ExceptionHandler.java +++ b/dicore3/core/src/main/java/io/dico/dicore/exceptions/ExceptionHandler.java @@ -1,203 +1,203 @@ -package io.dico.dicore.exceptions; - -import io.dico.dicore.exceptions.checkedfunctions.CheckedRunnable; -import io.dico.dicore.exceptions.checkedfunctions.CheckedSupplier; -import io.dico.dicore.exceptions.checkedfunctions.CheckedFunctionalObject; - -import java.io.PrintWriter; -import java.io.StringWriter; -import java.sql.SQLException; -import java.util.Objects; -import java.util.function.Consumer; -import java.util.function.Supplier; - -@FunctionalInterface -public interface ExceptionHandler { - - /** - * Handle the given exception according to this handler's implementation - * - * @param ex The exception to be handled - * @throws NullPointerException if ex is null, unless the implementation specifies otherwise - * @throws Error ex if ex is an instance of Error, unless the implementation specifies otherwise - */ - void handle(Throwable ex); - - /** - * Handle the given exception according to this handler's implementation - * This method is intended for use by {@link CheckedFunctionalObject} and subinterfaces. - * It supplies exception handlers the option to acquire more information, by overriding this method and calling it from {@link #handle(Throwable)} - * - * @param ex The exception to be handled - * @param args Any arguments passed, this is used by {@link CheckedFunctionalObject} and subinterfaces. - * @return {@code null} (unless specified otherwise by the implementation) - * @throws NullPointerException if ex is null, unless the implementation specifies otherwise - * @throws Error ex if ex is an instance of Error, unless the implementation specifies otherwise - */ - default Object handleGenericException(Throwable ex, Object... args) { - handle(ex); - return null; - } - - /** - * @return true if this {@link ExceptionHandler}'s {@link #handleGenericException(Throwable, Object...)} method is never expected to throw - * an unchecked exception other than {@link Error} - */ - default boolean isSafe() { - return true; - } - - /** - * Runs the given checked action, handling any thrown exceptions using this exception handler. - *

- * Any exceptions thrown by this handler are delegated to the caller. - * - * @param action The action to run - * @throws NullPointerException if action is null - */ - default void runSafe(CheckedRunnable action) { - Objects.requireNonNull(action); - try { - action.checkedRun(); - } catch (Throwable ex) { - handle(ex); - } - } - - /** - * Computes the result of the given checked supplier, handling any thrown exceptions using this exception handler. - *

- * Any exceptions thrown by this handler are delegated to the caller. - * - * @param action The supplier whose result to compute - * @param generic type parameter for the supplier and the result type of this method - * @return The result of this computation, or null if an error occurred - * @throws NullPointerException if action is null - */ - - default T supplySafe(CheckedSupplier action) { - Objects.requireNonNull(action); - try { - return action.checkedGet(); - } catch (Throwable ex) { - handle(ex); - return null; - } - } - - /** - * @param action The action to wrap - * @return A runnable that wraps the given action using this handler's {@link #runSafe(CheckedRunnable)} method. - * @see #runSafe(CheckedRunnable) - */ - default Runnable safeRunnable(CheckedRunnable action) { - return () -> runSafe(action); - } - - /** - * @param supplier The computation to wrap - * @return A supplier that wraps the given computation using this handler's {@link #supplySafe(CheckedSupplier)} method. - * @see #supplySafe(CheckedSupplier) - */ - default Supplier safeSupplier(CheckedSupplier supplier) { - return () -> supplySafe(supplier); - } - - /** - * Logs the given exception as an error to {@code out} - *

- * Format: Error occurred while {@code failedActivityDescription}, followed by additional details and a stack trace - * - * @param out The consumer to accept the error message, for instance {@code {@link java.util.logging.Logger logger}::warning}. - * @param failedActivityDescription A description of the activity that was being executed when the exception was thrown - * @param ex The exception that was thrown - * @throws NullPointerException if any argument is null - */ - static void log(Consumer out, String failedActivityDescription, Throwable ex) { - if (out == null || failedActivityDescription == null || ex == null) { - throw new NullPointerException(); - } - - StringWriter msg = new StringWriter(1024); - msg.append("Error occurred while ").append(failedActivityDescription).append(':'); - - if (ex instanceof SQLException) { - SQLException sqlex = (SQLException) ex; - msg.append('\n').append("Error code: ").append(Integer.toString(sqlex.getErrorCode())); - msg.append('\n').append("SQL State: ").append(sqlex.getSQLState()); - } - - msg.append('\n').append("=======START STACK======="); - try (PrintWriter pw = new PrintWriter(msg)) { - ex.printStackTrace(pw); - } - msg.append('\n').append("========END STACK========"); - - out.accept(msg.toString()); - } - - /** - * @param activityDescription The activity description - * @return An ExceptionHandler that prints to {@link System#out} - * @see #log(Consumer, String) - */ - static ExceptionHandler log(String activityDescription) { - // A method reference would cache the current value in System.out - // This would update if the value in System.out is changed (by for example, applying a PrintStream that handles colours). - return log(msg -> System.out.println(msg), activityDescription); - } - - /** - * @param out The Consumer to be passed to {@link #log(Consumer, String, Throwable)} - * @param activityDescription The activity description to be passed to {@link #log(Consumer, String, Throwable)} - * @return An ExceptionHandler that passes exceptions with given arguments to {@link #log(Consumer, String, Throwable)} - * @see #log(Consumer, String, Throwable) - */ - static ExceptionHandler log(Consumer out, String activityDescription) { - return ex -> log(out, activityDescription, ex); - } - - /** - * This ExceptionHandler turns any Throwable into an unchecked exception, then throws it again. - */ - ExceptionHandler UNCHECKED = new ExceptionHandler() { - @Override - public void handle(Throwable ex) { - errorFilter(ex); - if (ex instanceof RuntimeException) { - throw (RuntimeException) ex; - } - throw new RuntimeException(ex); - } - - @Override - public boolean isSafe() { - return false; - } - }; - - /** - * This ExceptionHandler suppresses all exceptions, - * apart from {@link Error} because that is not usually supposed to be caught - */ - ExceptionHandler SUPPRESS = ExceptionHandler::errorFilter; - - /** - * This ExceptionHandler calls {@link Throwable#printStackTrace()} unless it is a {@link NullPointerException} or {@link Error}. - */ - ExceptionHandler PRINT_UNLESS_NP = ex -> { - errorFilter(ex); - if (!(ex instanceof NullPointerException)) { - ex.printStackTrace(); - } - }; - - static void errorFilter(Throwable ex) { - if (ex instanceof Error) { - throw (Error) ex; - } else if (ex == null) { - throw new NullPointerException(); - } - } - -} +package io.dico.dicore.exceptions; + +import io.dico.dicore.exceptions.checkedfunctions.CheckedRunnable; +import io.dico.dicore.exceptions.checkedfunctions.CheckedSupplier; +import io.dico.dicore.exceptions.checkedfunctions.CheckedFunctionalObject; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.sql.SQLException; +import java.util.Objects; +import java.util.function.Consumer; +import java.util.function.Supplier; + +@FunctionalInterface +public interface ExceptionHandler { + + /** + * Handle the given exception according to this handler's implementation + * + * @param ex The exception to be handled + * @throws NullPointerException if ex is null, unless the implementation specifies otherwise + * @throws Error ex if ex is an instance of Error, unless the implementation specifies otherwise + */ + void handle(Throwable ex); + + /** + * Handle the given exception according to this handler's implementation + * This method is intended for use by {@link CheckedFunctionalObject} and subinterfaces. + * It supplies exception handlers the option to acquire more information, by overriding this method and calling it from {@link #handle(Throwable)} + * + * @param ex The exception to be handled + * @param args Any arguments passed, this is used by {@link CheckedFunctionalObject} and subinterfaces. + * @return {@code null} (unless specified otherwise by the implementation) + * @throws NullPointerException if ex is null, unless the implementation specifies otherwise + * @throws Error ex if ex is an instance of Error, unless the implementation specifies otherwise + */ + default Object handleGenericException(Throwable ex, Object... args) { + handle(ex); + return null; + } + + /** + * @return true if this {@link ExceptionHandler}'s {@link #handleGenericException(Throwable, Object...)} method is never expected to throw + * an unchecked exception other than {@link Error} + */ + default boolean isSafe() { + return true; + } + + /** + * Runs the given checked action, handling any thrown exceptions using this exception handler. + *

+ * Any exceptions thrown by this handler are delegated to the caller. + * + * @param action The action to run + * @throws NullPointerException if action is null + */ + default void runSafe(CheckedRunnable action) { + Objects.requireNonNull(action); + try { + action.checkedRun(); + } catch (Throwable ex) { + handle(ex); + } + } + + /** + * Computes the result of the given checked supplier, handling any thrown exceptions using this exception handler. + *

+ * Any exceptions thrown by this handler are delegated to the caller. + * + * @param action The supplier whose result to compute + * @param generic type parameter for the supplier and the result type of this method + * @return The result of this computation, or null if an error occurred + * @throws NullPointerException if action is null + */ + + default T supplySafe(CheckedSupplier action) { + Objects.requireNonNull(action); + try { + return action.checkedGet(); + } catch (Throwable ex) { + handle(ex); + return null; + } + } + + /** + * @param action The action to wrap + * @return A runnable that wraps the given action using this handler's {@link #runSafe(CheckedRunnable)} method. + * @see #runSafe(CheckedRunnable) + */ + default Runnable safeRunnable(CheckedRunnable action) { + return () -> runSafe(action); + } + + /** + * @param supplier The computation to wrap + * @return A supplier that wraps the given computation using this handler's {@link #supplySafe(CheckedSupplier)} method. + * @see #supplySafe(CheckedSupplier) + */ + default Supplier safeSupplier(CheckedSupplier supplier) { + return () -> supplySafe(supplier); + } + + /** + * Logs the given exception as an error to {@code out} + *

+ * Format: Error occurred while {@code failedActivityDescription}, followed by additional details and a stack trace + * + * @param out The consumer to accept the error message, for instance {@code {@link java.util.logging.Logger logger}::warning}. + * @param failedActivityDescription A description of the activity that was being executed when the exception was thrown + * @param ex The exception that was thrown + * @throws NullPointerException if any argument is null + */ + static void log(Consumer out, String failedActivityDescription, Throwable ex) { + if (out == null || failedActivityDescription == null || ex == null) { + throw new NullPointerException(); + } + + StringWriter msg = new StringWriter(1024); + msg.append("Error occurred while ").append(failedActivityDescription).append(':'); + + if (ex instanceof SQLException) { + SQLException sqlex = (SQLException) ex; + msg.append('\n').append("Error code: ").append(Integer.toString(sqlex.getErrorCode())); + msg.append('\n').append("SQL State: ").append(sqlex.getSQLState()); + } + + msg.append('\n').append("=======START STACK======="); + try (PrintWriter pw = new PrintWriter(msg)) { + ex.printStackTrace(pw); + } + msg.append('\n').append("========END STACK========"); + + out.accept(msg.toString()); + } + + /** + * @param activityDescription The activity description + * @return An ExceptionHandler that prints to {@link System#out} + * @see #log(Consumer, String) + */ + static ExceptionHandler log(String activityDescription) { + // A method reference would cache the current value in System.out + // This would update if the value in System.out is changed (by for example, applying a PrintStream that handles colours). + return log(msg -> System.out.println(msg), activityDescription); + } + + /** + * @param out The Consumer to be passed to {@link #log(Consumer, String, Throwable)} + * @param activityDescription The activity description to be passed to {@link #log(Consumer, String, Throwable)} + * @return An ExceptionHandler that passes exceptions with given arguments to {@link #log(Consumer, String, Throwable)} + * @see #log(Consumer, String, Throwable) + */ + static ExceptionHandler log(Consumer out, String activityDescription) { + return ex -> log(out, activityDescription, ex); + } + + /** + * This ExceptionHandler turns any Throwable into an unchecked exception, then throws it again. + */ + ExceptionHandler UNCHECKED = new ExceptionHandler() { + @Override + public void handle(Throwable ex) { + errorFilter(ex); + if (ex instanceof RuntimeException) { + throw (RuntimeException) ex; + } + throw new RuntimeException(ex); + } + + @Override + public boolean isSafe() { + return false; + } + }; + + /** + * This ExceptionHandler suppresses all exceptions, + * apart from {@link Error} because that is not usually supposed to be caught + */ + ExceptionHandler SUPPRESS = ExceptionHandler::errorFilter; + + /** + * This ExceptionHandler calls {@link Throwable#printStackTrace()} unless it is a {@link NullPointerException} or {@link Error}. + */ + ExceptionHandler PRINT_UNLESS_NP = ex -> { + errorFilter(ex); + if (!(ex instanceof NullPointerException)) { + ex.printStackTrace(); + } + }; + + static void errorFilter(Throwable ex) { + if (ex instanceof Error) { + throw (Error) ex; + } else if (ex == null) { + throw new NullPointerException(); + } + } + +} diff --git a/dicore3/core/src/main/java/io/dico/dicore/exceptions/checkedfunctions/CheckedBiConsumer.java b/dicore3/core/src/main/java/io/dico/dicore/exceptions/checkedfunctions/CheckedBiConsumer.java index badf05b..bfcafe8 100644 --- a/dicore3/core/src/main/java/io/dico/dicore/exceptions/checkedfunctions/CheckedBiConsumer.java +++ b/dicore3/core/src/main/java/io/dico/dicore/exceptions/checkedfunctions/CheckedBiConsumer.java @@ -1,69 +1,69 @@ -package io.dico.dicore.exceptions.checkedfunctions; - -import io.dico.dicore.exceptions.ExceptionHandler; - -import java.util.function.BiConsumer; - -/** - * checked mimic of {@link BiConsumer} - * - * @param - * @param - * @param - */ -@FunctionalInterface -public interface CheckedBiConsumer - extends CheckedFunctionalObject, BiConsumer { - - /** - * The consuming action - * - * @param t the first argument to consume - * @param u the second argument to consume - * @throws TException if an exception occurs - */ - void checkedAccept(TParam1 t, TParam2 u) throws TException; - - /** - * unchecked wrapper for {@link #checkedAccept(Object, Object)} - * If a {@link TException} occurs, an unchecked one might be thrown by {@link #resultOnError(Throwable, Object...)} - * - * @param t the first input - * @param u the second input - * @see #checkedAccept(Object, Object) - * @see #resultOnError(Throwable, Object...) - */ - @Override - default void accept(TParam1 t, TParam2 u) { - try { - checkedAccept(t, u); - } catch (Throwable ex) { - handleGenericException(ex, t, u); - } - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedBiConsumer handleExceptionsWith(ExceptionHandler handler) { - return new CheckedBiConsumer() { - @Override - public void checkedAccept(TParam1 t, TParam2 u) throws TException { - CheckedBiConsumer.this.checkedAccept(t, u); - } - - @Override - public Void handleGenericException(Throwable thrown, Object... args) { - handler.handleGenericException(thrown, args); - return null; - } - - @Override - public CheckedBiConsumer handleExceptionsWith(ExceptionHandler handler) { - return CheckedBiConsumer.this.handleExceptionsWith(handler); - } - }; - } - -} +package io.dico.dicore.exceptions.checkedfunctions; + +import io.dico.dicore.exceptions.ExceptionHandler; + +import java.util.function.BiConsumer; + +/** + * checked mimic of {@link BiConsumer} + * + * @param + * @param + * @param + */ +@FunctionalInterface +public interface CheckedBiConsumer + extends CheckedFunctionalObject, BiConsumer { + + /** + * The consuming action + * + * @param t the first argument to consume + * @param u the second argument to consume + * @throws TException if an exception occurs + */ + void checkedAccept(TParam1 t, TParam2 u) throws TException; + + /** + * unchecked wrapper for {@link #checkedAccept(Object, Object)} + * If a {@link TException} occurs, an unchecked one might be thrown by {@link #resultOnError(Throwable, Object...)} + * + * @param t the first input + * @param u the second input + * @see #checkedAccept(Object, Object) + * @see #resultOnError(Throwable, Object...) + */ + @Override + default void accept(TParam1 t, TParam2 u) { + try { + checkedAccept(t, u); + } catch (Throwable ex) { + handleGenericException(ex, t, u); + } + } + + /** + * {@inheritDoc} + */ + @Override + default CheckedBiConsumer handleExceptionsWith(ExceptionHandler handler) { + return new CheckedBiConsumer() { + @Override + public void checkedAccept(TParam1 t, TParam2 u) throws TException { + CheckedBiConsumer.this.checkedAccept(t, u); + } + + @Override + public Void handleGenericException(Throwable thrown, Object... args) { + handler.handleGenericException(thrown, args); + return null; + } + + @Override + public CheckedBiConsumer handleExceptionsWith(ExceptionHandler handler) { + return CheckedBiConsumer.this.handleExceptionsWith(handler); + } + }; + } + +} diff --git a/dicore3/core/src/main/java/io/dico/dicore/exceptions/checkedfunctions/CheckedBiFunction.java b/dicore3/core/src/main/java/io/dico/dicore/exceptions/checkedfunctions/CheckedBiFunction.java index 9b39325..11fca3f 100644 --- a/dicore3/core/src/main/java/io/dico/dicore/exceptions/checkedfunctions/CheckedBiFunction.java +++ b/dicore3/core/src/main/java/io/dico/dicore/exceptions/checkedfunctions/CheckedBiFunction.java @@ -1,76 +1,76 @@ -package io.dico.dicore.exceptions.checkedfunctions; - -import io.dico.dicore.exceptions.ExceptionHandler; - -import java.util.function.BiFunction; - -/** - * checked mimic of {@link BiFunction} - * - * @param - * @param - * @param - * @param - */ -@FunctionalInterface -public interface CheckedBiFunction - extends CheckedFunctionalObject, BiFunction { - - /** - * the functional method - * - * @param t the first input - * @param u the second input - * @return the function output - * @throws TException if an exception occurs - */ - TResult checkedApply(TParam1 t, TParam2 u) throws TException; - - /** - * unchecked wrapper for {@link #checkedApply(Object, Object)} - * If a {@link TException} occurs, an unchecked one might be thrown by {@link #resultOnError(Throwable, Object...)} - * - * @param t the first input - * @param u the second input - * @return the function output, or the result from {@link #resultOnError(Throwable, Object...)} if an exception was thrown - * @see #checkedApply(Object, Object) - * @see #resultOnError(Throwable, Object...) - */ - @Override - default TResult apply(TParam1 t, TParam2 u) { - try { - return checkedApply(t, u); - } catch (Throwable ex) { - return handleGenericException(ex, t, u); - } - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedBiFunction handleExceptionsWith(ExceptionHandler handler) { - return new CheckedBiFunction() { - @Override - public TResult checkedApply(TParam1 t, TParam2 u) throws TException { - return CheckedBiFunction.this.checkedApply(t, u); - } - - @Override - @SuppressWarnings("unchecked") - public TResult handleGenericException(Throwable thrown, Object... args) { - Object result = handler.handleGenericException(thrown, args); - try { - return (TResult) result; - } catch (Exception ex) { - return null; - } - } - - @Override - public CheckedBiFunction handleExceptionsWith(ExceptionHandler handler) { - return CheckedBiFunction.this.handleExceptionsWith(handler); - } - }; - } -} +package io.dico.dicore.exceptions.checkedfunctions; + +import io.dico.dicore.exceptions.ExceptionHandler; + +import java.util.function.BiFunction; + +/** + * checked mimic of {@link BiFunction} + * + * @param + * @param + * @param + * @param + */ +@FunctionalInterface +public interface CheckedBiFunction + extends CheckedFunctionalObject, BiFunction { + + /** + * the functional method + * + * @param t the first input + * @param u the second input + * @return the function output + * @throws TException if an exception occurs + */ + TResult checkedApply(TParam1 t, TParam2 u) throws TException; + + /** + * unchecked wrapper for {@link #checkedApply(Object, Object)} + * If a {@link TException} occurs, an unchecked one might be thrown by {@link #resultOnError(Throwable, Object...)} + * + * @param t the first input + * @param u the second input + * @return the function output, or the result from {@link #resultOnError(Throwable, Object...)} if an exception was thrown + * @see #checkedApply(Object, Object) + * @see #resultOnError(Throwable, Object...) + */ + @Override + default TResult apply(TParam1 t, TParam2 u) { + try { + return checkedApply(t, u); + } catch (Throwable ex) { + return handleGenericException(ex, t, u); + } + } + + /** + * {@inheritDoc} + */ + @Override + default CheckedBiFunction handleExceptionsWith(ExceptionHandler handler) { + return new CheckedBiFunction() { + @Override + public TResult checkedApply(TParam1 t, TParam2 u) throws TException { + return CheckedBiFunction.this.checkedApply(t, u); + } + + @Override + @SuppressWarnings("unchecked") + public TResult handleGenericException(Throwable thrown, Object... args) { + Object result = handler.handleGenericException(thrown, args); + try { + return (TResult) result; + } catch (Exception ex) { + return null; + } + } + + @Override + public CheckedBiFunction handleExceptionsWith(ExceptionHandler handler) { + return CheckedBiFunction.this.handleExceptionsWith(handler); + } + }; + } +} diff --git a/dicore3/core/src/main/java/io/dico/dicore/exceptions/checkedfunctions/CheckedConsumer.java b/dicore3/core/src/main/java/io/dico/dicore/exceptions/checkedfunctions/CheckedConsumer.java index fa48ae8..abe6d53 100644 --- a/dicore3/core/src/main/java/io/dico/dicore/exceptions/checkedfunctions/CheckedConsumer.java +++ b/dicore3/core/src/main/java/io/dico/dicore/exceptions/checkedfunctions/CheckedConsumer.java @@ -1,67 +1,67 @@ -package io.dico.dicore.exceptions.checkedfunctions; - -import io.dico.dicore.exceptions.ExceptionHandler; - -import java.util.function.Consumer; - -/** - * checked mimic of {@link Consumer} - * - * @param - * @param - */ -@FunctionalInterface -public interface CheckedConsumer - extends CheckedFunctionalObject, Consumer { - - /** - * The consuming action - * - * @param t the argument to consume - * @throws TException if an error occurs - */ - void checkedAccept(TParam t) throws TException; - - /** - * Unchecked version of {@link #checkedAccept(Object)} - * If a {@link TException} occurs, an unchecked one might be thrown by {@link #resultOnError(Throwable, Object...)} - * - * @param t the argument to consume - * @see #checkedAccept(Object) - * @see #resultOnError(Throwable, Object...) - */ - @Override - default void accept(TParam t) { - try { - checkedAccept(t); - } catch (Throwable ex) { - handleGenericException(ex, t); - } - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedConsumer handleExceptionsWith(ExceptionHandler handler) { - return new CheckedConsumer() { - @Override - public void checkedAccept(TParam t) throws TException { - CheckedConsumer.this.checkedAccept(t); - } - - @Override - @SuppressWarnings("unchecked") - public Void handleGenericException(Throwable thrown, Object... args) { - handler.handleGenericException(thrown, args); - return null; - } - - @Override - public CheckedConsumer handleExceptionsWith(ExceptionHandler handler) { - return CheckedConsumer.this.handleExceptionsWith(handler); - } - }; - } - -} +package io.dico.dicore.exceptions.checkedfunctions; + +import io.dico.dicore.exceptions.ExceptionHandler; + +import java.util.function.Consumer; + +/** + * checked mimic of {@link Consumer} + * + * @param + * @param + */ +@FunctionalInterface +public interface CheckedConsumer + extends CheckedFunctionalObject, Consumer { + + /** + * The consuming action + * + * @param t the argument to consume + * @throws TException if an error occurs + */ + void checkedAccept(TParam t) throws TException; + + /** + * Unchecked version of {@link #checkedAccept(Object)} + * If a {@link TException} occurs, an unchecked one might be thrown by {@link #resultOnError(Throwable, Object...)} + * + * @param t the argument to consume + * @see #checkedAccept(Object) + * @see #resultOnError(Throwable, Object...) + */ + @Override + default void accept(TParam t) { + try { + checkedAccept(t); + } catch (Throwable ex) { + handleGenericException(ex, t); + } + } + + /** + * {@inheritDoc} + */ + @Override + default CheckedConsumer handleExceptionsWith(ExceptionHandler handler) { + return new CheckedConsumer() { + @Override + public void checkedAccept(TParam t) throws TException { + CheckedConsumer.this.checkedAccept(t); + } + + @Override + @SuppressWarnings("unchecked") + public Void handleGenericException(Throwable thrown, Object... args) { + handler.handleGenericException(thrown, args); + return null; + } + + @Override + public CheckedConsumer handleExceptionsWith(ExceptionHandler handler) { + return CheckedConsumer.this.handleExceptionsWith(handler); + } + }; + } + +} diff --git a/dicore3/core/src/main/java/io/dico/dicore/exceptions/checkedfunctions/CheckedFunction.java b/dicore3/core/src/main/java/io/dico/dicore/exceptions/checkedfunctions/CheckedFunction.java index 9ff806a..48ac207 100644 --- a/dicore3/core/src/main/java/io/dico/dicore/exceptions/checkedfunctions/CheckedFunction.java +++ b/dicore3/core/src/main/java/io/dico/dicore/exceptions/checkedfunctions/CheckedFunction.java @@ -1,74 +1,74 @@ -package io.dico.dicore.exceptions.checkedfunctions; - -import io.dico.dicore.exceptions.ExceptionHandler; - -import java.util.function.Function; - -/** - * checked mimic of {@link Function} - * - * @param - * @param - * @param - */ -@FunctionalInterface -public interface CheckedFunction - extends CheckedFunctionalObject, Function { - - /** - * the functional method - * - * @param t the input - * @return the function output - * @throws TException if an exception occurs - */ - TResult checkedApply(TParam t) throws TException; - - /** - * unchecked wrapper for {@link #checkedApply(Object)} - * If a {@link TException} occurs, an unchecked one might be thrown by {@link #resultOnError(Throwable, Object...)} - * - * @param t the input - * @return the function output, or the result from {@link #resultOnError(Throwable, Object...)} if an exception was thrown - * @see #checkedApply(Object) - * @see #resultOnError(Throwable, Object...) - */ - @Override - default TResult apply(TParam t) { - try { - return checkedApply(t); - } catch (Throwable ex) { - return handleGenericException(ex, t); - } - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedFunction handleExceptionsWith(ExceptionHandler handler) { - return new CheckedFunction() { - @Override - public TResult checkedApply(TParam t) throws TException { - return CheckedFunction.this.checkedApply(t); - } - - @Override - @SuppressWarnings("unchecked") - public TResult handleGenericException(Throwable thrown, Object... args) { - Object result = handler.handleGenericException(thrown, args); - try { - return (TResult) result; - } catch (Exception ex) { - return null; - } - } - - @Override - public CheckedFunction handleExceptionsWith(ExceptionHandler handler) { - return CheckedFunction.this.handleExceptionsWith(handler); - } - }; - } - -} +package io.dico.dicore.exceptions.checkedfunctions; + +import io.dico.dicore.exceptions.ExceptionHandler; + +import java.util.function.Function; + +/** + * checked mimic of {@link Function} + * + * @param + * @param + * @param + */ +@FunctionalInterface +public interface CheckedFunction + extends CheckedFunctionalObject, Function { + + /** + * the functional method + * + * @param t the input + * @return the function output + * @throws TException if an exception occurs + */ + TResult checkedApply(TParam t) throws TException; + + /** + * unchecked wrapper for {@link #checkedApply(Object)} + * If a {@link TException} occurs, an unchecked one might be thrown by {@link #resultOnError(Throwable, Object...)} + * + * @param t the input + * @return the function output, or the result from {@link #resultOnError(Throwable, Object...)} if an exception was thrown + * @see #checkedApply(Object) + * @see #resultOnError(Throwable, Object...) + */ + @Override + default TResult apply(TParam t) { + try { + return checkedApply(t); + } catch (Throwable ex) { + return handleGenericException(ex, t); + } + } + + /** + * {@inheritDoc} + */ + @Override + default CheckedFunction handleExceptionsWith(ExceptionHandler handler) { + return new CheckedFunction() { + @Override + public TResult checkedApply(TParam t) throws TException { + return CheckedFunction.this.checkedApply(t); + } + + @Override + @SuppressWarnings("unchecked") + public TResult handleGenericException(Throwable thrown, Object... args) { + Object result = handler.handleGenericException(thrown, args); + try { + return (TResult) result; + } catch (Exception ex) { + return null; + } + } + + @Override + public CheckedFunction handleExceptionsWith(ExceptionHandler handler) { + return CheckedFunction.this.handleExceptionsWith(handler); + } + }; + } + +} diff --git a/dicore3/core/src/main/java/io/dico/dicore/exceptions/checkedfunctions/CheckedFunctionalObject.java b/dicore3/core/src/main/java/io/dico/dicore/exceptions/checkedfunctions/CheckedFunctionalObject.java index e84b33d..d9d7a53 100644 --- a/dicore3/core/src/main/java/io/dico/dicore/exceptions/checkedfunctions/CheckedFunctionalObject.java +++ b/dicore3/core/src/main/java/io/dico/dicore/exceptions/checkedfunctions/CheckedFunctionalObject.java @@ -1,85 +1,85 @@ -package io.dico.dicore.exceptions.checkedfunctions; - -import io.dico.dicore.exceptions.ExceptionHandler; - -/** - * Base interface for all checked functional interfaces - * Most subinterfaces will mimic interfaces in the package {@link java.util.function} - *

- * Checked functional interfaces are functions with throws declarations. - * The name comes from the fact that they can throw checked exceptions. - *

- * They extend their non-checked counterparts, whose methods are implemented by - * returning the result of {@link #resultOnError(TException, Object...)} when an exception is thrown - *

- * Made public to allow more specialized checked functional interfaces to subclass it. - * Making primitive versions shouldn't provide a significant performance increase because we're checking for exceptions, - * the performance impact of which is probably a few magnitudes larger. Don't quote me on this. - * - * @param The return type of this functional interface's method - * @param The type of exception that might be thrown - */ -public interface CheckedFunctionalObject extends ExceptionHandler { - - /** - * {@inheritDoc} - * - * @param ex The exception to be handled - */ - @Override - default void handle(Throwable ex) { - handleGenericException(ex); - } - - /** - * {@inheritDoc} - *

- * Method to handle exceptions thrown by the default implementations of subinterfaces. - * Since you can't catch a type parameter as exception, this code is in place to take care of it. - *

- * If the thrown exception is not a TException, an unchecked version is thrown by calling this method. - * - * @param thrown The thrown exception - * @param args the arguments supplied to the method that threw the exception, if any. These are not guaranteed to be given if parameters are present. - * @return The result computed by {@link #resultOnError(Throwable, Object...)} - * @see #resultOnError(Throwable, Object...) - */ - @Override - @SuppressWarnings("unchecked") - default TResult handleGenericException(Throwable thrown, Object... args) { - - // check if the throwable is a TException - TException castedException; - try { - castedException = (TException) thrown; - } catch (ClassCastException ex) { - // if not, throw an unchecked version of it - ExceptionHandler.UNCHECKED.handleGenericException(thrown); - // this code is never reached. - return null; - } - - // if it is a TException, use resultOnError to compute result. - return resultOnError(castedException, args); - } - - /** - * This method handles the exceptions thrown by the checked method of this object, when called by its unchecked wrapper. - * - * @param ex The exception thrown - * @param args The (typed) arguments passed, if any - * @return The result to return, if any - */ - default TResult resultOnError(TException ex, Object... args) { - return null; - } - - /** - * Creates a new functional object that uses the given exception handler to handle exceptions. - * - * @param handler The handler to handle exceptions - * @return a new functional object that uses the given exception handler to handle exceptions - */ - CheckedFunctionalObject handleExceptionsWith(ExceptionHandler handler); - -} +package io.dico.dicore.exceptions.checkedfunctions; + +import io.dico.dicore.exceptions.ExceptionHandler; + +/** + * Base interface for all checked functional interfaces + * Most subinterfaces will mimic interfaces in the package {@link java.util.function} + *

+ * Checked functional interfaces are functions with throws declarations. + * The name comes from the fact that they can throw checked exceptions. + *

+ * They extend their non-checked counterparts, whose methods are implemented by + * returning the result of {@link #resultOnError(TException, Object...)} when an exception is thrown + *

+ * Made public to allow more specialized checked functional interfaces to subclass it. + * Making primitive versions shouldn't provide a significant performance increase because we're checking for exceptions, + * the performance impact of which is probably a few magnitudes larger. Don't quote me on this. + * + * @param The return type of this functional interface's method + * @param The type of exception that might be thrown + */ +public interface CheckedFunctionalObject extends ExceptionHandler { + + /** + * {@inheritDoc} + * + * @param ex The exception to be handled + */ + @Override + default void handle(Throwable ex) { + handleGenericException(ex); + } + + /** + * {@inheritDoc} + *

+ * Method to handle exceptions thrown by the default implementations of subinterfaces. + * Since you can't catch a type parameter as exception, this code is in place to take care of it. + *

+ * If the thrown exception is not a TException, an unchecked version is thrown by calling this method. + * + * @param thrown The thrown exception + * @param args the arguments supplied to the method that threw the exception, if any. These are not guaranteed to be given if parameters are present. + * @return The result computed by {@link #resultOnError(Throwable, Object...)} + * @see #resultOnError(Throwable, Object...) + */ + @Override + @SuppressWarnings("unchecked") + default TResult handleGenericException(Throwable thrown, Object... args) { + + // check if the throwable is a TException + TException castedException; + try { + castedException = (TException) thrown; + } catch (ClassCastException ex) { + // if not, throw an unchecked version of it + ExceptionHandler.UNCHECKED.handleGenericException(thrown); + // this code is never reached. + return null; + } + + // if it is a TException, use resultOnError to compute result. + return resultOnError(castedException, args); + } + + /** + * This method handles the exceptions thrown by the checked method of this object, when called by its unchecked wrapper. + * + * @param ex The exception thrown + * @param args The (typed) arguments passed, if any + * @return The result to return, if any + */ + default TResult resultOnError(TException ex, Object... args) { + return null; + } + + /** + * Creates a new functional object that uses the given exception handler to handle exceptions. + * + * @param handler The handler to handle exceptions + * @return a new functional object that uses the given exception handler to handle exceptions + */ + CheckedFunctionalObject handleExceptionsWith(ExceptionHandler handler); + +} diff --git a/dicore3/core/src/main/java/io/dico/dicore/exceptions/checkedfunctions/CheckedRunnable.java b/dicore3/core/src/main/java/io/dico/dicore/exceptions/checkedfunctions/CheckedRunnable.java index 55de6f8..110c988 100644 --- a/dicore3/core/src/main/java/io/dico/dicore/exceptions/checkedfunctions/CheckedRunnable.java +++ b/dicore3/core/src/main/java/io/dico/dicore/exceptions/checkedfunctions/CheckedRunnable.java @@ -1,62 +1,62 @@ -package io.dico.dicore.exceptions.checkedfunctions; - -import io.dico.dicore.exceptions.ExceptionHandler; - -/** - * checked mimic of {@link Runnable} - * - * @param - */ -@FunctionalInterface -public interface CheckedRunnable - extends CheckedFunctionalObject, Runnable { - - /** - * The runnable action - * - * @throws TException if an exception occurs - */ - void checkedRun() throws TException; - - /** - * Unchecked version of {@link #checkedRun()} - * If a {@link TException} occurs, an unchecked one might be thrown by {@link #resultOnError(Throwable, Object...)} - * - * @see #checkedRun() - * @see #resultOnError(Throwable, Object...) - */ - @Override - default void run() { - try { - checkedRun(); - } catch (Throwable ex) { - handleGenericException(ex); - } - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedRunnable handleExceptionsWith(ExceptionHandler handler) { - return new CheckedRunnable() { - @Override - public void checkedRun() throws TException { - CheckedRunnable.this.checkedRun(); - } - - @Override - @SuppressWarnings("unchecked") - public Void handleGenericException(Throwable thrown, Object... args) { - handler.handleGenericException(thrown, args); - return null; - } - - @Override - public CheckedRunnable handleExceptionsWith(ExceptionHandler handler) { - return CheckedRunnable.this.handleExceptionsWith(handler); - } - }; - } - -} +package io.dico.dicore.exceptions.checkedfunctions; + +import io.dico.dicore.exceptions.ExceptionHandler; + +/** + * checked mimic of {@link Runnable} + * + * @param + */ +@FunctionalInterface +public interface CheckedRunnable + extends CheckedFunctionalObject, Runnable { + + /** + * The runnable action + * + * @throws TException if an exception occurs + */ + void checkedRun() throws TException; + + /** + * Unchecked version of {@link #checkedRun()} + * If a {@link TException} occurs, an unchecked one might be thrown by {@link #resultOnError(Throwable, Object...)} + * + * @see #checkedRun() + * @see #resultOnError(Throwable, Object...) + */ + @Override + default void run() { + try { + checkedRun(); + } catch (Throwable ex) { + handleGenericException(ex); + } + } + + /** + * {@inheritDoc} + */ + @Override + default CheckedRunnable handleExceptionsWith(ExceptionHandler handler) { + return new CheckedRunnable() { + @Override + public void checkedRun() throws TException { + CheckedRunnable.this.checkedRun(); + } + + @Override + @SuppressWarnings("unchecked") + public Void handleGenericException(Throwable thrown, Object... args) { + handler.handleGenericException(thrown, args); + return null; + } + + @Override + public CheckedRunnable handleExceptionsWith(ExceptionHandler handler) { + return CheckedRunnable.this.handleExceptionsWith(handler); + } + }; + } + +} diff --git a/dicore3/core/src/main/java/io/dico/dicore/exceptions/checkedfunctions/CheckedSupplier.java b/dicore3/core/src/main/java/io/dico/dicore/exceptions/checkedfunctions/CheckedSupplier.java index dec2e7e..7820428 100644 --- a/dicore3/core/src/main/java/io/dico/dicore/exceptions/checkedfunctions/CheckedSupplier.java +++ b/dicore3/core/src/main/java/io/dico/dicore/exceptions/checkedfunctions/CheckedSupplier.java @@ -1,70 +1,70 @@ -package io.dico.dicore.exceptions.checkedfunctions; - -import io.dico.dicore.exceptions.ExceptionHandler; - -import java.util.function.Supplier; - -/** - * checked mimic of {@link Supplier} - * - * @param - * @param - */ -@FunctionalInterface -public interface CheckedSupplier - extends CheckedFunctionalObject, Supplier { - - /** - * The computation - * - * @return the result of this computation - * @throws TException if an error occurs - */ - TResult checkedGet() throws TException; - - /** - * Unchecked version of {@link #checkedGet()} - * If a {@link TException} occurs, an unchecked one might be thrown by {@link #resultOnError(Throwable, Object...)} - * - * @return the result of this computation - * @see #checkedGet() - * @see #resultOnError(Throwable, Object...) - */ - @Override - default TResult get() { - try { - return checkedGet(); - } catch (Throwable ex) { - return handleGenericException(ex); - } - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedSupplier handleExceptionsWith(ExceptionHandler handler) { - return new CheckedSupplier() { - @Override - public TResult checkedGet() throws TException { - return CheckedSupplier.this.checkedGet(); - } - - @Override - @SuppressWarnings("unchecked") - public TResult handleGenericException(Throwable thrown, Object... args) { - Object result = handler.handleGenericException(thrown, args); - try { - return (TResult) result; - } catch (Exception ex) { - return null; - } - } - - @Override - public CheckedSupplier handleExceptionsWith(ExceptionHandler handler) { - return CheckedSupplier.this.handleExceptionsWith(handler); - } - }; - } -} +package io.dico.dicore.exceptions.checkedfunctions; + +import io.dico.dicore.exceptions.ExceptionHandler; + +import java.util.function.Supplier; + +/** + * checked mimic of {@link Supplier} + * + * @param + * @param + */ +@FunctionalInterface +public interface CheckedSupplier + extends CheckedFunctionalObject, Supplier { + + /** + * The computation + * + * @return the result of this computation + * @throws TException if an error occurs + */ + TResult checkedGet() throws TException; + + /** + * Unchecked version of {@link #checkedGet()} + * If a {@link TException} occurs, an unchecked one might be thrown by {@link #resultOnError(Throwable, Object...)} + * + * @return the result of this computation + * @see #checkedGet() + * @see #resultOnError(Throwable, Object...) + */ + @Override + default TResult get() { + try { + return checkedGet(); + } catch (Throwable ex) { + return handleGenericException(ex); + } + } + + /** + * {@inheritDoc} + */ + @Override + default CheckedSupplier handleExceptionsWith(ExceptionHandler handler) { + return new CheckedSupplier() { + @Override + public TResult checkedGet() throws TException { + return CheckedSupplier.this.checkedGet(); + } + + @Override + @SuppressWarnings("unchecked") + public TResult handleGenericException(Throwable thrown, Object... args) { + Object result = handler.handleGenericException(thrown, args); + try { + return (TResult) result; + } catch (Exception ex) { + return null; + } + } + + @Override + public CheckedSupplier handleExceptionsWith(ExceptionHandler handler) { + return CheckedSupplier.this.handleExceptionsWith(handler); + } + }; + } +} diff --git a/dicore3/core/src/main/java/io/dico/dicore/task/BaseTask.java b/dicore3/core/src/main/java/io/dico/dicore/task/BaseTask.java index b400cce..43db459 100644 --- a/dicore3/core/src/main/java/io/dico/dicore/task/BaseTask.java +++ b/dicore3/core/src/main/java/io/dico/dicore/task/BaseTask.java @@ -1,108 +1,108 @@ -package io.dico.dicore.task; - -import org.bukkit.Bukkit; -import org.bukkit.plugin.Plugin; - -import java.util.NoSuchElementException; - -public abstract class BaseTask { - private boolean running = false; - private Integer taskId = null; - private long workTime = 5L; - private int workCount; - - public void start(Plugin plugin, int delay, int period, long workTime) { - doStartChecks(); - this.workTime = workTime; - workCount = 0; - running = true; - - if (delay == -1) { - run(); - if (!running) { - return; - } - delay = period; - } - - taskId = plugin.getServer().getScheduler().scheduleSyncRepeatingTask(plugin, this::run, delay, period); - } - - public void startImmediately(Plugin plugin, int period, long workTime) { - start(plugin, -1, period, workTime); - } - - protected void doStartChecks() { - if (isRunning()) { - throw new IllegalStateException("Can't start when already running"); - } - } - - public void start(Plugin plugin) { - start(plugin, -1, 20, 5L); - } - - protected void onFinish(boolean early) { - } - - protected long getWorkTime() { - return workTime; - } - - protected abstract boolean process(T object); - - private void run() { - workCount++; - final long stop = System.currentTimeMillis() + getWorkTime(); - do { - if (!processNext()) { - return; - } - } while (System.currentTimeMillis() < stop); - } - - public int getTaskId() { - return running ? taskId : -1; - } - - public int getWorkCount() { - return workCount; - } - - public boolean isRunning() { - return running; - } - - protected abstract T supply() throws NoSuchElementException; - - private void cancelTask(boolean early) { - if (taskId != null) { - Bukkit.getScheduler().cancelTask(taskId); - } - running = false; - taskId = null; - onFinish(early); - } - - private boolean processNext() { - T object; - try { - object = supply(); - } catch (NoSuchElementException e) { - cancelTask(false); - return false; - } - - try { - if (process(object)) { - return true; - } - } catch (RuntimeException e) { - e.printStackTrace(); - } - - cancelTask(true); - return false; - } - -} +package io.dico.dicore.task; + +import org.bukkit.Bukkit; +import org.bukkit.plugin.Plugin; + +import java.util.NoSuchElementException; + +public abstract class BaseTask { + private boolean running = false; + private Integer taskId = null; + private long workTime = 5L; + private int workCount; + + public void start(Plugin plugin, int delay, int period, long workTime) { + doStartChecks(); + this.workTime = workTime; + workCount = 0; + running = true; + + if (delay == -1) { + run(); + if (!running) { + return; + } + delay = period; + } + + taskId = plugin.getServer().getScheduler().scheduleSyncRepeatingTask(plugin, this::run, delay, period); + } + + public void startImmediately(Plugin plugin, int period, long workTime) { + start(plugin, -1, period, workTime); + } + + protected void doStartChecks() { + if (isRunning()) { + throw new IllegalStateException("Can't start when already running"); + } + } + + public void start(Plugin plugin) { + start(plugin, -1, 20, 5L); + } + + protected void onFinish(boolean early) { + } + + protected long getWorkTime() { + return workTime; + } + + protected abstract boolean process(T object); + + private void run() { + workCount++; + final long stop = System.currentTimeMillis() + getWorkTime(); + do { + if (!processNext()) { + return; + } + } while (System.currentTimeMillis() < stop); + } + + public int getTaskId() { + return running ? taskId : -1; + } + + public int getWorkCount() { + return workCount; + } + + public boolean isRunning() { + return running; + } + + protected abstract T supply() throws NoSuchElementException; + + private void cancelTask(boolean early) { + if (taskId != null) { + Bukkit.getScheduler().cancelTask(taskId); + } + running = false; + taskId = null; + onFinish(early); + } + + private boolean processNext() { + T object; + try { + object = supply(); + } catch (NoSuchElementException e) { + cancelTask(false); + return false; + } + + try { + if (process(object)) { + return true; + } + } catch (RuntimeException e) { + e.printStackTrace(); + } + + cancelTask(true); + return false; + } + +} diff --git a/dicore3/core/src/main/java/io/dico/dicore/task/IteratorTask.java b/dicore3/core/src/main/java/io/dico/dicore/task/IteratorTask.java index e58814c..3ff7be7 100644 --- a/dicore3/core/src/main/java/io/dico/dicore/task/IteratorTask.java +++ b/dicore3/core/src/main/java/io/dico/dicore/task/IteratorTask.java @@ -1,120 +1,120 @@ -package io.dico.dicore.task; - -import java.util.*; -import java.util.function.BiConsumer; -import java.util.function.BiPredicate; -import java.util.function.Consumer; -import java.util.function.Predicate; - -public abstract class IteratorTask extends BaseTask { - - private Iterator iterator; - - public IteratorTask() { - } - - @SuppressWarnings("unchecked") - public IteratorTask(Iterable iterable, boolean clone) { - refresh(iterable, clone); - } - - public IteratorTask(Iterable iterable) { - this(iterable, false); - } - - public IteratorTask(Iterator iterator) { - refresh(iterator); - } - - @Override - protected void doStartChecks() { - super.doStartChecks(); - if (iterator == null) { - throw new IllegalStateException("An iterator must be supplied first"); - } - } - - protected final void refresh(Iterable iterable, boolean clone) { - if (clone) { - Collection collection; - if (!(iterable instanceof Collection)) { - collection = new LinkedList<>(); - for (T next : iterable) { - collection.add(next); - } - } else { - collection = new ArrayList((Collection) iterable); - } - iterator = collection.iterator(); - } else { - iterator = iterable.iterator(); - } - } - - protected final void refresh(Iterator iterator) { - Objects.requireNonNull(iterator); - this.iterator = iterator; - } - - @Override - protected T supply() { - return iterator.next(); - } - - protected void remove() { - iterator.remove(); - } - - // One argument: The processed object - - public static IteratorTask create(Iterable iterable, Consumer processor) { - return create(iterable, false, processor); - } - - public static IteratorTask create(Iterable iterable, boolean clone, Consumer processor) { - return create(iterable, clone, object -> { - processor.accept(object); - return true; - }); - } - - public static IteratorTask create(Iterable iterable, Predicate processor) { - return create(iterable, false, processor); - } - - public static IteratorTask create(Iterable iterable, boolean clone, Predicate processor) { - return new IteratorTask(iterable, clone) { - @Override - protected boolean process(T object) { - return processor.test(object); - } - }; - } - - // Two arguments: the processed object, and a runnable to remove it from the iterator. - - public static IteratorTask create(Iterable iterable, BiConsumer processor) { - return create(iterable, false, processor); - } - - public static IteratorTask create(Iterable iterable, boolean clone, BiConsumer processor) { - return create(iterable, clone, (object, runnable) -> { - processor.accept(object, runnable); - return true; - }); - } - - public static IteratorTask create(Iterable iterable, BiPredicate processor) { - return create(iterable, false, processor); - } - - public static IteratorTask create(Iterable iterable, boolean clone, BiPredicate processor) { - return new IteratorTask(iterable, clone) { - @Override - protected boolean process(T object) { - return processor.test(object, this::remove); - } - }; - } - -} +package io.dico.dicore.task; + +import java.util.*; +import java.util.function.BiConsumer; +import java.util.function.BiPredicate; +import java.util.function.Consumer; +import java.util.function.Predicate; + +public abstract class IteratorTask extends BaseTask { + + private Iterator iterator; + + public IteratorTask() { + } + + @SuppressWarnings("unchecked") + public IteratorTask(Iterable iterable, boolean clone) { + refresh(iterable, clone); + } + + public IteratorTask(Iterable iterable) { + this(iterable, false); + } + + public IteratorTask(Iterator iterator) { + refresh(iterator); + } + + @Override + protected void doStartChecks() { + super.doStartChecks(); + if (iterator == null) { + throw new IllegalStateException("An iterator must be supplied first"); + } + } + + protected final void refresh(Iterable iterable, boolean clone) { + if (clone) { + Collection collection; + if (!(iterable instanceof Collection)) { + collection = new LinkedList<>(); + for (T next : iterable) { + collection.add(next); + } + } else { + collection = new ArrayList((Collection) iterable); + } + iterator = collection.iterator(); + } else { + iterator = iterable.iterator(); + } + } + + protected final void refresh(Iterator iterator) { + Objects.requireNonNull(iterator); + this.iterator = iterator; + } + + @Override + protected T supply() { + return iterator.next(); + } + + protected void remove() { + iterator.remove(); + } + + // One argument: The processed object + + public static IteratorTask create(Iterable iterable, Consumer processor) { + return create(iterable, false, processor); + } + + public static IteratorTask create(Iterable iterable, boolean clone, Consumer processor) { + return create(iterable, clone, object -> { + processor.accept(object); + return true; + }); + } + + public static IteratorTask create(Iterable iterable, Predicate processor) { + return create(iterable, false, processor); + } + + public static IteratorTask create(Iterable iterable, boolean clone, Predicate processor) { + return new IteratorTask(iterable, clone) { + @Override + protected boolean process(T object) { + return processor.test(object); + } + }; + } + + // Two arguments: the processed object, and a runnable to remove it from the iterator. + + public static IteratorTask create(Iterable iterable, BiConsumer processor) { + return create(iterable, false, processor); + } + + public static IteratorTask create(Iterable iterable, boolean clone, BiConsumer processor) { + return create(iterable, clone, (object, runnable) -> { + processor.accept(object, runnable); + return true; + }); + } + + public static IteratorTask create(Iterable iterable, BiPredicate processor) { + return create(iterable, false, processor); + } + + public static IteratorTask create(Iterable iterable, boolean clone, BiPredicate processor) { + return new IteratorTask(iterable, clone) { + @Override + protected boolean process(T object) { + return processor.test(object, this::remove); + } + }; + } + +} diff --git a/dicore3/core/src/main/java/io/dico/dicore/task/VoidTask.java b/dicore3/core/src/main/java/io/dico/dicore/task/VoidTask.java index 1298c4c..6204bee 100644 --- a/dicore3/core/src/main/java/io/dico/dicore/task/VoidTask.java +++ b/dicore3/core/src/main/java/io/dico/dicore/task/VoidTask.java @@ -1,19 +1,19 @@ -package io.dico.dicore.task; - -import java.util.NoSuchElementException; - -public abstract class VoidTask extends BaseTask { - - @Override - protected final boolean process(Void object) { - return process(); - } - - @Override - protected final Void supply() throws NoSuchElementException { - return null; - } - - protected abstract boolean process(); - -} +package io.dico.dicore.task; + +import java.util.NoSuchElementException; + +public abstract class VoidTask extends BaseTask { + + @Override + protected final boolean process(Void object) { + return process(); + } + + @Override + protected final Void supply() throws NoSuchElementException { + return null; + } + + protected abstract boolean process(); + +} -- cgit v1.2.3