Reflect wrapper initialization does not crash anymore on the first exception. It accumulates all the exceptions and shows everything at the end.
This commit is contained in:
parent
3e0297c8af
commit
9b83f9699c
@ -58,6 +58,8 @@ import java.util.Set;
|
|||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static fr.pandacube.lib.util.ThrowableUtil.wrapEx;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract class to hold a command to be integrated into a Paper server vanilla command dispatcher.
|
* Abstract class to hold a command to be integrated into a Paper server vanilla command dispatcher.
|
||||||
*/
|
*/
|
||||||
@ -67,7 +69,7 @@ public abstract class PaperBrigadierCommand extends BrigadierCommand<BukkitBriga
|
|||||||
private static final CommandDispatcher<BukkitBrigadierCommandSource> nmsDispatcher;
|
private static final CommandDispatcher<BukkitBrigadierCommandSource> nmsDispatcher;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
PandalibPaperReflect.init();
|
wrapEx(PandalibPaperReflect::init);
|
||||||
vanillaCommandDispatcher = ReflectWrapper.wrapTyped(Bukkit.getServer(), CraftServer.class)
|
vanillaCommandDispatcher = ReflectWrapper.wrapTyped(Bukkit.getServer(), CraftServer.class)
|
||||||
.getServer()
|
.getServer()
|
||||||
.vanillaCommandDispatcher();
|
.vanillaCommandDispatcher();
|
||||||
|
@ -74,6 +74,7 @@ import fr.pandacube.lib.paper.reflect.wrapper.paper.PaperAdventure;
|
|||||||
import fr.pandacube.lib.paper.reflect.wrapper.paper.QueuedChangesMapLong2Object;
|
import fr.pandacube.lib.paper.reflect.wrapper.paper.QueuedChangesMapLong2Object;
|
||||||
import fr.pandacube.lib.paper.reflect.wrapper.paper.configuration.FallbackValue_Int;
|
import fr.pandacube.lib.paper.reflect.wrapper.paper.configuration.FallbackValue_Int;
|
||||||
import fr.pandacube.lib.paper.reflect.wrapper.paper.configuration.WorldConfiguration;
|
import fr.pandacube.lib.paper.reflect.wrapper.paper.configuration.WorldConfiguration;
|
||||||
|
import fr.pandacube.lib.util.ThrowableAccumulator;
|
||||||
|
|
||||||
import static fr.pandacube.lib.reflect.wrapper.WrapperRegistry.initWrapper;
|
import static fr.pandacube.lib.reflect.wrapper.WrapperRegistry.initWrapper;
|
||||||
|
|
||||||
@ -86,8 +87,9 @@ public class PandalibPaperReflect {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the reflect tools in {@code pandalib-paper-reflect} module.
|
* Initializes the reflect tools in {@code pandalib-paper-reflect} module.
|
||||||
|
* @throws Exception if a problem occurs when initializing wrapper classes.
|
||||||
*/
|
*/
|
||||||
public static void init() {
|
public static void init() throws Exception {
|
||||||
NMSReflect.init();
|
NMSReflect.init();
|
||||||
synchronized (PandalibPaperReflect.class) {
|
synchronized (PandalibPaperReflect.class) {
|
||||||
if (isInit)
|
if (isInit)
|
||||||
@ -97,105 +99,112 @@ public class PandalibPaperReflect {
|
|||||||
initWrapperClasses();
|
initWrapperClasses();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void initWrapperClasses() {
|
private static void initWrapperClasses() throws Exception {
|
||||||
|
|
||||||
|
ThrowableAccumulator<Throwable> thAcc = new ThrowableAccumulator<>(Throwable.class);
|
||||||
|
|
||||||
// brigadier
|
// brigadier
|
||||||
initWrapper(CommandNode.class, CommandNode.REFLECT.get());
|
thAcc.catchThrowable(() -> initWrapper(CommandNode.class, CommandNode.REFLECT.get()));
|
||||||
|
|
||||||
// craftbukkit
|
// craftbukkit
|
||||||
initWrapper(CraftItemStack.class, CraftItemStack.REFLECT.get());
|
thAcc.catchThrowable(() -> initWrapper(CraftItemStack.class, CraftItemStack.REFLECT.get()));
|
||||||
initWrapper(CraftMapView.class, CraftMapView.REFLECT.get());
|
thAcc.catchThrowable(() -> initWrapper(CraftMapView.class, CraftMapView.REFLECT.get()));
|
||||||
initWrapper(CraftNamespacedKey.class, CraftNamespacedKey.REFLECT.get());
|
thAcc.catchThrowable(() -> initWrapper(CraftNamespacedKey.class, CraftNamespacedKey.REFLECT.get()));
|
||||||
initWrapper(CraftPlayer.class, CraftPlayer.REFLECT.get());
|
thAcc.catchThrowable(() -> initWrapper(CraftPlayer.class, CraftPlayer.REFLECT.get()));
|
||||||
initWrapper(CraftServer.class, CraftServer.REFLECT.get());
|
thAcc.catchThrowable(() -> initWrapper(CraftServer.class, CraftServer.REFLECT.get()));
|
||||||
initWrapper(CraftVector.class, CraftVector.REFLECT.get());
|
thAcc.catchThrowable(() -> initWrapper(CraftVector.class, CraftVector.REFLECT.get()));
|
||||||
initWrapper(CraftWorld.class, CraftWorld.REFLECT.get());
|
thAcc.catchThrowable(() -> initWrapper(CraftWorld.class, CraftWorld.REFLECT.get()));
|
||||||
initWrapper(RenderData.class, RenderData.REFLECT.get());
|
thAcc.catchThrowable(() -> initWrapper(RenderData.class, RenderData.REFLECT.get()));
|
||||||
initWrapper(VanillaCommandWrapper.class, VanillaCommandWrapper.REFLECT.get());
|
thAcc.catchThrowable(() -> initWrapper(VanillaCommandWrapper.class, VanillaCommandWrapper.REFLECT.get()));
|
||||||
|
|
||||||
// dataconverter
|
// dataconverter
|
||||||
initWrapper(MCDataConverter.class, MCDataConverter.REFLECT.get());
|
thAcc.catchThrowable(() -> initWrapper(MCDataConverter.class, MCDataConverter.REFLECT.get()));
|
||||||
initWrapper(MCDataType.class, MCDataType.REFLECT.get());
|
thAcc.catchThrowable(() -> initWrapper(MCDataType.class, MCDataType.REFLECT.get()));
|
||||||
initWrapper(MCTypeRegistry.class, MCTypeRegistry.REFLECT.get());
|
thAcc.catchThrowable(() -> initWrapper(MCTypeRegistry.class, MCTypeRegistry.REFLECT.get()));
|
||||||
|
|
||||||
// minecraft.commands
|
// minecraft.commands
|
||||||
initWrapper(BlockPosArgument.class, BlockPosArgument.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(BlockPosArgument.class, BlockPosArgument.MAPPING.runtimeClass()));
|
||||||
initWrapper(Commands.class, Commands.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(Commands.class, Commands.MAPPING.runtimeClass()));
|
||||||
initWrapper(CommandSourceStack.class, CommandSourceStack.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(CommandSourceStack.class, CommandSourceStack.MAPPING.runtimeClass()));
|
||||||
initWrapper(ComponentArgument.class, ComponentArgument.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(ComponentArgument.class, ComponentArgument.MAPPING.runtimeClass()));
|
||||||
initWrapper(Coordinates.class, Coordinates.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(Coordinates.class, Coordinates.MAPPING.runtimeClass()));
|
||||||
initWrapper(EntityArgument.class, EntityArgument.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(EntityArgument.class, EntityArgument.MAPPING.runtimeClass()));
|
||||||
initWrapper(EntitySelector.class, EntitySelector.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(EntitySelector.class, EntitySelector.MAPPING.runtimeClass()));
|
||||||
initWrapper(GameProfileArgument.class, GameProfileArgument.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(GameProfileArgument.class, GameProfileArgument.MAPPING.runtimeClass()));
|
||||||
initWrapper(ResourceLocationArgument.class, ResourceLocationArgument.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(ResourceLocationArgument.class, ResourceLocationArgument.MAPPING.runtimeClass()));
|
||||||
initWrapper(Vec3Argument.class, Vec3Argument.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(Vec3Argument.class, Vec3Argument.MAPPING.runtimeClass()));
|
||||||
// minecraft.core
|
// minecraft.core
|
||||||
initWrapper(BlockPos.class, BlockPos.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(BlockPos.class, BlockPos.MAPPING.runtimeClass()));
|
||||||
initWrapper(Vec3i.class, Vec3i.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(Vec3i.class, Vec3i.MAPPING.runtimeClass()));
|
||||||
// minecraft.nbt
|
// minecraft.nbt
|
||||||
initWrapper(CollectionTag.class, CollectionTag.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(CollectionTag.class, CollectionTag.MAPPING.runtimeClass()));
|
||||||
initWrapper(CompoundTag.class, CompoundTag.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(CompoundTag.class, CompoundTag.MAPPING.runtimeClass()));
|
||||||
initWrapper(ListTag.class, ListTag.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(ListTag.class, ListTag.MAPPING.runtimeClass()));
|
||||||
initWrapper(NbtIo.class, NbtIo.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(NbtIo.class, NbtIo.MAPPING.runtimeClass()));
|
||||||
initWrapper(StringTag.class, StringTag.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(StringTag.class, StringTag.MAPPING.runtimeClass()));
|
||||||
initWrapper(Tag.class, Tag.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(Tag.class, Tag.MAPPING.runtimeClass()));
|
||||||
// minecraft.network.chat
|
// minecraft.network.chat
|
||||||
initWrapper(Component.class, Component.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(Component.class, Component.MAPPING.runtimeClass()));
|
||||||
// minecraft.network.protocol
|
// minecraft.network.protocol
|
||||||
initWrapper(ClientboundCustomPayloadPacket.class, ClientboundCustomPayloadPacket.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(ClientboundCustomPayloadPacket.class, ClientboundCustomPayloadPacket.MAPPING.runtimeClass()));
|
||||||
initWrapper(ClientboundGameEventPacket.class, ClientboundGameEventPacket.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(ClientboundGameEventPacket.class, ClientboundGameEventPacket.MAPPING.runtimeClass()));
|
||||||
initWrapper(ClientboundGameEventPacket.Type.class, ClientboundGameEventPacket.Type.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(ClientboundGameEventPacket.Type.class, ClientboundGameEventPacket.Type.MAPPING.runtimeClass()));
|
||||||
initWrapper(Packet.class, Packet.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(Packet.class, Packet.MAPPING.runtimeClass()));
|
||||||
// minecraft.network
|
// minecraft.network
|
||||||
initWrapper(FriendlyByteBuf.class, FriendlyByteBuf.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(FriendlyByteBuf.class, FriendlyByteBuf.MAPPING.runtimeClass()));
|
||||||
// minecraft.resources
|
// minecraft.resources
|
||||||
initWrapper(ResourceLocation.class, ResourceLocation.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(ResourceLocation.class, ResourceLocation.MAPPING.runtimeClass()));
|
||||||
// minecraft.server
|
// minecraft.server
|
||||||
initWrapper(ChunkMap.class, ChunkMap.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(ChunkMap.class, ChunkMap.MAPPING.runtimeClass()));
|
||||||
initWrapper(DedicatedPlayerList.class, DedicatedPlayerList.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(DedicatedPlayerList.class, DedicatedPlayerList.MAPPING.runtimeClass()));
|
||||||
initWrapper(DedicatedServer.class, DedicatedServer.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(DedicatedServer.class, DedicatedServer.MAPPING.runtimeClass()));
|
||||||
initWrapper(DedicatedServerProperties.class, DedicatedServerProperties.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(DedicatedServerProperties.class, DedicatedServerProperties.MAPPING.runtimeClass()));
|
||||||
initWrapper(MinecraftServer.class, MinecraftServer.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(MinecraftServer.class, MinecraftServer.MAPPING.runtimeClass()));
|
||||||
initWrapper(PlayerList.class, PlayerList.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(PlayerList.class, PlayerList.MAPPING.runtimeClass()));
|
||||||
initWrapper(ServerChunkCache.class, ServerChunkCache.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(ServerChunkCache.class, ServerChunkCache.MAPPING.runtimeClass()));
|
||||||
initWrapper(ServerGamePacketListenerImpl.class, ServerGamePacketListenerImpl.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(ServerGamePacketListenerImpl.class, ServerGamePacketListenerImpl.MAPPING.runtimeClass()));
|
||||||
initWrapper(ServerLevel.class, ServerLevel.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(ServerLevel.class, ServerLevel.MAPPING.runtimeClass()));
|
||||||
initWrapper(ServerPlayer.class, ServerPlayer.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(ServerPlayer.class, ServerPlayer.MAPPING.runtimeClass()));
|
||||||
initWrapper(Settings.class, Settings.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(Settings.class, Settings.MAPPING.runtimeClass()));
|
||||||
// minecraft.util
|
// minecraft.util
|
||||||
initWrapper(ProgressListener.class, ProgressListener.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(ProgressListener.class, ProgressListener.MAPPING.runtimeClass()));
|
||||||
// minecraft.world.block
|
// minecraft.world.block
|
||||||
initWrapper(BambooStalkBlock.class, BambooStalkBlock.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(BambooStalkBlock.class, BambooStalkBlock.MAPPING.runtimeClass()));
|
||||||
// minecraft.world
|
// minecraft.world
|
||||||
initWrapper(AABB.class, AABB.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(AABB.class, AABB.MAPPING.runtimeClass()));
|
||||||
initWrapper(ChunkPos.class, ChunkPos.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(ChunkPos.class, ChunkPos.MAPPING.runtimeClass()));
|
||||||
initWrapper(ChunkStorage.class, ChunkStorage.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(ChunkStorage.class, ChunkStorage.MAPPING.runtimeClass()));
|
||||||
initWrapper(DamageSource.class, DamageSource.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(DamageSource.class, DamageSource.MAPPING.runtimeClass()));
|
||||||
initWrapper(DamageSources.class, DamageSources.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(DamageSources.class, DamageSources.MAPPING.runtimeClass()));
|
||||||
initWrapper(Entity.class, Entity.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(Entity.class, Entity.MAPPING.runtimeClass()));
|
||||||
initWrapper(ItemStack.class, ItemStack.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(ItemStack.class, ItemStack.MAPPING.runtimeClass()));
|
||||||
initWrapper(Level.class, Level.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(Level.class, Level.MAPPING.runtimeClass()));
|
||||||
initWrapper(MapItemSavedData.class, MapItemSavedData.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(MapItemSavedData.class, MapItemSavedData.MAPPING.runtimeClass()));
|
||||||
initWrapper(PlayerDataStorage.class, PlayerDataStorage.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(PlayerDataStorage.class, PlayerDataStorage.MAPPING.runtimeClass()));
|
||||||
initWrapper(SavedData.class, SavedData.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(SavedData.class, SavedData.MAPPING.runtimeClass()));
|
||||||
initWrapper(Vec3.class, Vec3.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(Vec3.class, Vec3.MAPPING.runtimeClass()));
|
||||||
initWrapper(VoxelShape.class, VoxelShape.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(VoxelShape.class, VoxelShape.MAPPING.runtimeClass()));
|
||||||
// minecraft
|
// minecraft
|
||||||
initWrapper(DetectedVersion.class, DetectedVersion.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(DetectedVersion.class, DetectedVersion.MAPPING.runtimeClass()));
|
||||||
initWrapper(GameVersion.class, GameVersion.REFLECT.get());
|
thAcc.catchThrowable(() -> initWrapper(GameVersion.class, GameVersion.REFLECT.get()));
|
||||||
initWrapper(SharedConstants.class, SharedConstants.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(SharedConstants.class, SharedConstants.MAPPING.runtimeClass()));
|
||||||
initWrapper(WorldVersion.class, WorldVersion.MAPPING.runtimeClass());
|
thAcc.catchThrowable(() -> initWrapper(WorldVersion.class, WorldVersion.MAPPING.runtimeClass()));
|
||||||
|
|
||||||
// netty
|
// netty
|
||||||
initWrapper(ByteBuf.class, ByteBuf.REFLECT.get());
|
thAcc.catchThrowable(() -> initWrapper(ByteBuf.class, ByteBuf.REFLECT.get()));
|
||||||
initWrapper(Unpooled.class, Unpooled.REFLECT.get());
|
thAcc.catchThrowable(() -> initWrapper(Unpooled.class, Unpooled.REFLECT.get()));
|
||||||
|
|
||||||
// paper.configuration
|
// paper.configuration
|
||||||
initWrapper(FallbackValue_Int.class, FallbackValue_Int.REFLECT.get());
|
thAcc.catchThrowable(() -> initWrapper(FallbackValue_Int.class, FallbackValue_Int.REFLECT.get()));
|
||||||
initWrapper(WorldConfiguration.class, WorldConfiguration.REFLECT.get());
|
thAcc.catchThrowable(() -> initWrapper(WorldConfiguration.class, WorldConfiguration.REFLECT.get()));
|
||||||
initWrapper(WorldConfiguration.Chunks.class, WorldConfiguration.Chunks.REFLECT.get());
|
thAcc.catchThrowable(() -> initWrapper(WorldConfiguration.Chunks.class, WorldConfiguration.Chunks.REFLECT.get()));
|
||||||
// paper
|
// paper
|
||||||
initWrapper(AABBVoxelShape.class, AABBVoxelShape.REFLECT.get());
|
thAcc.catchThrowable(() -> initWrapper(AABBVoxelShape.class, AABBVoxelShape.REFLECT.get()));
|
||||||
initWrapper(PaperAdventure.class, PaperAdventure.REFLECT.get());
|
thAcc.catchThrowable(() -> initWrapper(PaperAdventure.class, PaperAdventure.REFLECT.get()));
|
||||||
initWrapper(QueuedChangesMapLong2Object.class, QueuedChangesMapLong2Object.REFLECT.get());
|
thAcc.catchThrowable(() -> initWrapper(QueuedChangesMapLong2Object.class, QueuedChangesMapLong2Object.REFLECT.get()));
|
||||||
|
|
||||||
|
|
||||||
|
thAcc.throwCatched();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,9 +7,9 @@ import java.util.function.ToIntBiFunction;
|
|||||||
/**
|
/**
|
||||||
* Implementation of the <a href="https://en.wikipedia.org/wiki/Levenshtein_distance">Levenshtein distance algorithm</a>
|
* Implementation of the <a href="https://en.wikipedia.org/wiki/Levenshtein_distance">Levenshtein distance algorithm</a>
|
||||||
* that operate on characters. Its purpose is to compute a "distance" between two strings of characters, that represents
|
* that operate on characters. Its purpose is to compute a "distance" between two strings of characters, that represents
|
||||||
* how many edition operation it is needed to perform on the first string ({@code initialString}) to optain the second
|
* how many edition operations must be performed on the first string ({@code initialString}) to optain the second
|
||||||
* one ({@code finalString}).
|
* one ({@code finalString}).
|
||||||
*
|
* <p>
|
||||||
* All the parameters of the algorithm are configurable:
|
* All the parameters of the algorithm are configurable:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>The score of adding a character</li>
|
* <li>The score of adding a character</li>
|
||||||
@ -21,15 +21,13 @@ import java.util.function.ToIntBiFunction;
|
|||||||
* ToIntBiFunction)} (for a full control of the parameters) or {@link #LevenshteinDistance(String, String)} (to keep the
|
* ToIntBiFunction)} (for a full control of the parameters) or {@link #LevenshteinDistance(String, String)} (to keep the
|
||||||
* default parameters value); then to call the method {@link #getCurrentDistance()} to compute the Levenshtein distance
|
* default parameters value); then to call the method {@link #getCurrentDistance()} to compute the Levenshtein distance
|
||||||
* between the two strings.
|
* between the two strings.
|
||||||
*
|
* <p>
|
||||||
* A more advanced usage offer the possibility to progressively compute a distance from a predefined
|
* A more advanced usage offer the possibility to progressively compute a distance from a predefined
|
||||||
* {@code initialString} to a {@code finalString} that is feeded progressively using {@link #add(char)} or
|
* {@code initialString} to a {@code finalString} that is feeded progressively using {@link #add(char)} or
|
||||||
* {@link #add(String)}. This is useful if the {@code finalString} is an input that is currently being typed by the
|
* {@link #add(String)}. This is useful if the {@code finalString} is an input that is currently being typed by the
|
||||||
* user, so the application can progressively update a list of suggested words based on the distance.
|
* user, so the application can progressively update a list of suggested words based on the distance.
|
||||||
* For this usage, you can use those constructors to avoid initializing the {@code finalString}:
|
* For this usage, you can use those constructors to avoid initializing the {@code finalString}:
|
||||||
* {@link #LevenshteinDistance(String, int, int, ToIntBiFunction)} or {@link #LevenshteinDistance(String)}.
|
* {@link #LevenshteinDistance(String, int, int, ToIntBiFunction)} or {@link #LevenshteinDistance(String)}.
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class LevenshteinDistance {
|
public class LevenshteinDistance {
|
||||||
|
|
||||||
|
@ -0,0 +1,104 @@
|
|||||||
|
package fr.pandacube.lib.util;
|
||||||
|
|
||||||
|
import fr.pandacube.lib.util.ThrowableUtil.RunnableException;
|
||||||
|
import fr.pandacube.lib.util.ThrowableUtil.SupplierException;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class that delay and accumulate thown exceptions, that can be thrown later using {@link #throwCatched()}.
|
||||||
|
* @param <T> the type of {@link Throwable} to accumulate.
|
||||||
|
*/
|
||||||
|
public class ThrowableAccumulator<T extends Throwable> {
|
||||||
|
T base = null;
|
||||||
|
final Class<T> throwableType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link ThrowableAccumulator} with the specified throwable type.
|
||||||
|
* @param throwableType The type of the {@link Throwable} to accumulate.
|
||||||
|
*/
|
||||||
|
public ThrowableAccumulator(Class<T> throwableType) {
|
||||||
|
this.throwableType = throwableType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the provided {@link RunnableException}, catching an eventual exception to accumulate for later use.
|
||||||
|
* @param run the {@link RunnableException} to run.
|
||||||
|
* @throws Exception if an exception not handled by this accumulator is thrown.
|
||||||
|
*/
|
||||||
|
public void catchThrowable(RunnableException<Exception> run) throws Exception {
|
||||||
|
try {
|
||||||
|
run.run();
|
||||||
|
} catch (Throwable t) {
|
||||||
|
accumulateThrowable(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the provided {@link SupplierException}, catching an eventual exception to accumulate for later use.
|
||||||
|
* @param supp the {@link SupplierException} to run.
|
||||||
|
* @param returnValueIfException The value to return if this accumulator catch an exception.
|
||||||
|
* @return The return value of the supplier, or {@code returnValueIfException} if this accumulator catch an exception.
|
||||||
|
* @throws Exception if an exception not handled by this accumulator is thrown.
|
||||||
|
* @param <R> the type of the return value of the supplier.
|
||||||
|
*/
|
||||||
|
public <R> R catchThrowable(SupplierException<R, Exception> supp, R returnValueIfException) throws Exception {
|
||||||
|
return catchThrowable(supp, (Supplier<R>) () -> returnValueIfException);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the provided {@link SupplierException}, catching an eventual exception to accumulate for later use.
|
||||||
|
* @param supp the {@link SupplierException} to run.
|
||||||
|
* @param returnValueIfException The value to return if this accumulator catch an exception.
|
||||||
|
* @return The return value of the supplier, or the return value of {@code returnValueIfException} if this
|
||||||
|
* accumulator catch an exception.
|
||||||
|
* @throws Exception if an exception not handled by this accumulator is thrown.
|
||||||
|
* @param <R> the type of the return value of both suppliers.
|
||||||
|
*/
|
||||||
|
public <R> R catchThrowable(SupplierException<R, Exception> supp, Supplier<R> returnValueIfException) throws Exception {
|
||||||
|
try {
|
||||||
|
return supp.get();
|
||||||
|
} catch (Throwable t) {
|
||||||
|
accumulateThrowable(t);
|
||||||
|
}
|
||||||
|
return returnValueIfException.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void accumulateThrowable(Throwable t) throws Exception {
|
||||||
|
if (throwableType.isInstance(t)) {
|
||||||
|
synchronized (this) {
|
||||||
|
if (base == null)
|
||||||
|
base = throwableType.cast(t);
|
||||||
|
else {
|
||||||
|
base.addSuppressed(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throwEx(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Throws an exception if there is at least one catched by this accumulator.
|
||||||
|
* If multiple exception where catched, all the exception after the first one are added to the first one as
|
||||||
|
* suppressed exceptions.
|
||||||
|
* If no exception were catched, this method does nothing.
|
||||||
|
* @throws Exception the first accumulated throwable, the other ones being suppressed.
|
||||||
|
*/
|
||||||
|
public void throwCatched() throws Exception {
|
||||||
|
synchronized (this) {
|
||||||
|
if (base != null)
|
||||||
|
throwEx(base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void throwEx(Throwable t) throws Exception {
|
||||||
|
if (t instanceof Error e)
|
||||||
|
throw e;
|
||||||
|
else if (t instanceof Exception e)
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user