From eec7b2fcbbe079d34ca4906278b845fb4238c0a1 Mon Sep 17 00:00:00 2001 From: Adrian Victor Date: Sat, 23 May 2026 17:59:40 -0300 Subject: [PATCH 1/2] Remove reflection and add VersionedService to provide multiple versions support --- .../DefaultVersionedServiceFactoryTest.java | 126 ++++++++++++++++++ .../lib/impl/b1_7_3/B1_7_3Registrar.java | 20 +++ ...adrianvictor.lib.VersionedServiceRegistrar | 1 + .../lib/DefaultVersionedServiceFactory.java | 36 +++++ src/main/java/org/adrianvictor/lib/Main.java | 46 +++++++ .../lib/VersionedServiceFactory.java | 8 ++ .../lib/VersionedServiceRegistrar.java | 5 + .../lib/configuration/Configuration.java | 6 +- .../reflection/ImplementationRegistry.java | 34 ----- .../lib/reflection/VersionMatcher.java | 110 ++++++--------- .../org/adrianvictor/lib/text/TextColor.java | 6 +- .../adrianvictor/lib/text/TextColorUtils.java | 6 +- .../lib/impl/r1_21/R1_21Registrar.java | 16 +++ ...adrianvictor.lib.VersionedServiceRegistrar | 1 + 14 files changed, 310 insertions(+), 111 deletions(-) create mode 100644 app/src/test/java/org/adrianvictor/lib/DefaultVersionedServiceFactoryTest.java create mode 100644 src/b1_7_3/java/org/adrianvictor/lib/impl/b1_7_3/B1_7_3Registrar.java create mode 100644 src/b1_7_3/resources/META-INF/services/org.adrianvictor.lib.VersionedServiceRegistrar create mode 100644 src/main/java/org/adrianvictor/lib/DefaultVersionedServiceFactory.java create mode 100644 src/main/java/org/adrianvictor/lib/Main.java create mode 100644 src/main/java/org/adrianvictor/lib/VersionedServiceFactory.java create mode 100644 src/main/java/org/adrianvictor/lib/VersionedServiceRegistrar.java delete mode 100644 src/main/java/org/adrianvictor/lib/reflection/ImplementationRegistry.java create mode 100644 src/r1_21/java/org/adrianvictor/lib/impl/r1_21/R1_21Registrar.java create mode 100644 src/r1_21/resources/META-INF/services/org.adrianvictor.lib.VersionedServiceRegistrar diff --git a/app/src/test/java/org/adrianvictor/lib/DefaultVersionedServiceFactoryTest.java b/app/src/test/java/org/adrianvictor/lib/DefaultVersionedServiceFactoryTest.java new file mode 100644 index 0000000..ca7b1b6 --- /dev/null +++ b/app/src/test/java/org/adrianvictor/lib/DefaultVersionedServiceFactoryTest.java @@ -0,0 +1,126 @@ +package org.adrianvictor.lib; + +import org.adrianvictor.lib.reflection.VersionMatcher; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.function.Supplier; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +// Define dummy interfaces for testing +interface TestService {} +class TestServiceB1_7_3 implements TestService {} +class TestServiceR1_21 implements TestService {} + +// Dummy registrar for testing +class DummyRegistrarB1_7_3 implements VersionedServiceRegistrar { + @Override + public void register(VersionedServiceFactory factory) { + factory.register(TestService.class, "b1_7_3", TestServiceB1_7_3::new); + factory.register(TestService.class, "b1_8_compat", TestServiceB1_7_3::new); // Register for b1_8_compat + } +} + +class DummyRegistrarR1_21 implements VersionedServiceRegistrar { + @Override + public void register(VersionedServiceFactory factory) { + factory.register(TestService.class, "r1_21", TestServiceR1_21::new); + } +} + + +public class DefaultVersionedServiceFactoryTest { + + private VersionMatcher mockVersionMatcher; + private DefaultVersionedServiceFactory factory; + + @BeforeEach + void setUp() { + mockVersionMatcher = mock(VersionMatcher.class); + factory = new DefaultVersionedServiceFactory(mockVersionMatcher); + } + + @Test + void testServiceRegistrationAndRetrievalForB1_7_3() { + // Mock VersionMatcher to return b1_7_3 suffix + when(mockVersionMatcher.getServerVersion()).thenReturn("1.7.3"); + when(mockVersionMatcher.getClassSuffix(eq("1.7.3"))).thenReturn("b1_7_3"); + + // Register the dummy service for b1_7_3 + new DummyRegistrarB1_7_3().register(factory); + + // Retrieve the service + TestService service = factory.getService(TestService.class); + + // Assert that the correct version is returned + assertNotNull(service); + assertTrue(service instanceof TestServiceB1_7_3); + } + + @Test + void testServiceRegistrationAndRetrievalForR1_21() { + // Mock VersionMatcher to return r1_21 suffix + when(mockVersionMatcher.getServerVersion()).thenReturn("1.21.0"); + when(mockVersionMatcher.getClassSuffix(eq("1.21.0"))).thenReturn("r1_21"); + + // Register the dummy service for r1_21 + new DummyRegistrarR1_21().register(factory); + + // Retrieve the service + TestService service = factory.getService(TestService.class); + + // Assert that the correct version is returned + assertNotNull(service); + assertTrue(service instanceof TestServiceR1_21); + } + + @Test + void testServiceRegistrationAndRetrievalForB1_8_Compat() { + // Mock VersionMatcher to return b1_8_compat suffix for a 1.16.5 server + when(mockVersionMatcher.getServerVersion()).thenReturn("1.16.5"); + when(mockVersionMatcher.getClassSuffix(eq("1.16.5"))).thenReturn("b1_8_compat"); + + // Register the dummy service for b1_7_3 (which also covers b1_8_compat) + new DummyRegistrarB1_7_3().register(factory); + + // Retrieve the service + TestService service = factory.getService(TestService.class); + + // Assert that the correct compatible version is returned + assertNotNull(service); + assertTrue(service instanceof TestServiceB1_7_3); + } + + @Test + void testNoServiceRegisteredThrowsException() { + // Mock VersionMatcher to return an unknown suffix + when(mockVersionMatcher.getServerVersion()).thenReturn("unknown"); + when(mockVersionMatcher.getClassSuffix(anyString())).thenReturn("unknown_version"); + + // Attempt to retrieve a service without any registration + IllegalStateException exception = assertThrows(IllegalStateException.class, () -> + factory.getService(TestService.class) + ); + + assertTrue(exception.getMessage().contains("No service registered for type")); + } + + @Test + void testSpecificServiceNotRegisteredForVersionThrowsException() { + // Mock VersionMatcher to return b1_7_3 suffix + when(mockVersionMatcher.getServerVersion()).thenReturn("1.7.3"); + when(mockVersionMatcher.getClassSuffix(eq("1.7.3"))).thenReturn("b1_7_3"); + + // Register R1_21 service, but not B1_7_3 + new DummyRegistrarR1_21().register(factory); + + // Attempt to retrieve b1_7_3 service + IllegalStateException exception = assertThrows(IllegalStateException.class, () -> + factory.getService(TestService.class) + ); + + assertTrue(exception.getMessage().contains("No service registered for type")); + } +} diff --git a/src/b1_7_3/java/org/adrianvictor/lib/impl/b1_7_3/B1_7_3Registrar.java b/src/b1_7_3/java/org/adrianvictor/lib/impl/b1_7_3/B1_7_3Registrar.java new file mode 100644 index 0000000..197a704 --- /dev/null +++ b/src/b1_7_3/java/org/adrianvictor/lib/impl/b1_7_3/B1_7_3Registrar.java @@ -0,0 +1,20 @@ +package org.adrianvictor.lib.impl.b1_7_3; + +import org.adrianvictor.lib.VersionedServiceFactory; +import org.adrianvictor.lib.VersionedServiceRegistrar; +import org.adrianvictor.lib.configuration.provider.ConfigurationProvider; +import org.adrianvictor.lib.impl.b1_7_3.configuration.Configuration; +import org.adrianvictor.lib.text.provider.TextColorProvider; +import org.adrianvictor.lib.impl.b1_7_3.text.TextColor; + +public class B1_7_3Registrar implements VersionedServiceRegistrar { + @Override + public void register(VersionedServiceFactory factory) { + factory.register(ConfigurationProvider.class, "b1_7_3", Configuration::new); + factory.register(TextColorProvider.class, "b1_7_3", TextColor::new); + + // Register for b1_8_compat as well, assuming compatibility + factory.register(ConfigurationProvider.class, "b1_8_compat", Configuration::new); + factory.register(TextColorProvider.class, "b1_8_compat", TextColor::new); + } +} diff --git a/src/b1_7_3/resources/META-INF/services/org.adrianvictor.lib.VersionedServiceRegistrar b/src/b1_7_3/resources/META-INF/services/org.adrianvictor.lib.VersionedServiceRegistrar new file mode 100644 index 0000000..04d62e3 --- /dev/null +++ b/src/b1_7_3/resources/META-INF/services/org.adrianvictor.lib.VersionedServiceRegistrar @@ -0,0 +1 @@ +org.adrianvictor.lib.impl.b1_7_3.B1_7_3Registrar \ No newline at end of file diff --git a/src/main/java/org/adrianvictor/lib/DefaultVersionedServiceFactory.java b/src/main/java/org/adrianvictor/lib/DefaultVersionedServiceFactory.java new file mode 100644 index 0000000..6be8582 --- /dev/null +++ b/src/main/java/org/adrianvictor/lib/DefaultVersionedServiceFactory.java @@ -0,0 +1,36 @@ +package org.adrianvictor.lib; + +import org.adrianvictor.lib.reflection.VersionMatcher; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Supplier; + +public class DefaultVersionedServiceFactory implements VersionedServiceFactory { + private final VersionMatcher versionMatcher; + private final Map, Map>> serviceRegistrations = new HashMap<>(); + + public DefaultVersionedServiceFactory(VersionMatcher versionMatcher) { + this.versionMatcher = versionMatcher; + } + + @Override + public void register(Class serviceType, String versionSuffix, Supplier supplier) { + serviceRegistrations + .computeIfAbsent(serviceType, k -> new HashMap<>()) + .put(versionSuffix, supplier); + } + + @Override + @SuppressWarnings("unchecked") + public T getService(Class serviceType) { + String serverVersion = versionMatcher.getServerVersion(); + // Determine the correct suffix using VersionMatcher (adapted) + String versionSuffix = versionMatcher.getClassSuffix(serverVersion); // Removed "release" parameter + + Map> versionSuppliers = serviceRegistrations.get(serviceType); + if (versionSuppliers == null || !versionSuppliers.containsKey(versionSuffix)) { + throw new IllegalStateException("No service registered for type " + serviceType.getName() + " and version " + versionSuffix + ". Current server version: " + serverVersion); + } + return (T) versionSuppliers.get(versionSuffix).get(); + } +} diff --git a/src/main/java/org/adrianvictor/lib/Main.java b/src/main/java/org/adrianvictor/lib/Main.java new file mode 100644 index 0000000..2371249 --- /dev/null +++ b/src/main/java/org/adrianvictor/lib/Main.java @@ -0,0 +1,46 @@ +package org.adrianvictor.lib; + +import org.adrianvictor.lib.reflection.VersionMatcher; +import org.bukkit.plugin.java.JavaPlugin; + +import java.util.ServiceLoader; + +public class Main extends JavaPlugin { + + private static VersionedServiceFactory versionedServiceFactory; + private static VersionMatcher versionMatcher; + + @Override + public void onEnable() { + // Initialize VersionMatcher + versionMatcher = new VersionMatcher(); + + // Initialize DefaultVersionedServiceFactory + versionedServiceFactory = new DefaultVersionedServiceFactory(versionMatcher); + + // Discover and register version-specific implementations using ServiceLoader + ServiceLoader registrars = ServiceLoader.load(VersionedServiceRegistrar.class); + for (VersionedServiceRegistrar registrar : registrars) { + registrar.register(versionedServiceFactory); + } + + // Example usage (for demonstration, can be removed later) + // ConfigurationProvider configProvider = Configuration.create(versionedServiceFactory); + // TextColorProvider textColorProvider = TextColor.create(versionedServiceFactory); + + getLogger().info("tenkumaLib has been enabled!"); + } + + @Override + public void onDisable() { + getLogger().info("tenkumaLib has been disabled!"); + } + + public static VersionedServiceFactory getVersionedServiceFactory() { + return versionedServiceFactory; + } + + public static VersionMatcher getVersionMatcher() { + return versionMatcher; + } +} diff --git a/src/main/java/org/adrianvictor/lib/VersionedServiceFactory.java b/src/main/java/org/adrianvictor/lib/VersionedServiceFactory.java new file mode 100644 index 0000000..749689d --- /dev/null +++ b/src/main/java/org/adrianvictor/lib/VersionedServiceFactory.java @@ -0,0 +1,8 @@ +package org.adrianvictor.lib; + +import java.util.function.Supplier; + +public interface VersionedServiceFactory { + void register(Class serviceType, String versionSuffix, Supplier supplier); + T getService(Class serviceType); +} diff --git a/src/main/java/org/adrianvictor/lib/VersionedServiceRegistrar.java b/src/main/java/org/adrianvictor/lib/VersionedServiceRegistrar.java new file mode 100644 index 0000000..ed78bc4 --- /dev/null +++ b/src/main/java/org/adrianvictor/lib/VersionedServiceRegistrar.java @@ -0,0 +1,5 @@ +package org.adrianvictor.lib; + +public interface VersionedServiceRegistrar { + void register(VersionedServiceFactory factory); +} diff --git a/src/main/java/org/adrianvictor/lib/configuration/Configuration.java b/src/main/java/org/adrianvictor/lib/configuration/Configuration.java index fa005b5..fa8999b 100644 --- a/src/main/java/org/adrianvictor/lib/configuration/Configuration.java +++ b/src/main/java/org/adrianvictor/lib/configuration/Configuration.java @@ -1,10 +1,10 @@ package org.adrianvictor.lib.configuration; +import org.adrianvictor.lib.VersionedServiceFactory; import org.adrianvictor.lib.configuration.provider.ConfigurationProvider; -import org.adrianvictor.lib.reflection.ImplementationRegistry; public class Configuration { - public static ConfigurationProvider create(ImplementationRegistry registry) { - return registry.getInstance(ConfigurationProvider.class); + public static ConfigurationProvider create(VersionedServiceFactory factory) { + return factory.getService(ConfigurationProvider.class); } } \ No newline at end of file diff --git a/src/main/java/org/adrianvictor/lib/reflection/ImplementationRegistry.java b/src/main/java/org/adrianvictor/lib/reflection/ImplementationRegistry.java deleted file mode 100644 index cac780a..0000000 --- a/src/main/java/org/adrianvictor/lib/reflection/ImplementationRegistry.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.adrianvictor.lib.reflection; - -public class ImplementationRegistry { - - private final String classSuffix; - - public ImplementationRegistry(String classSuffix) { - this.classSuffix = classSuffix; - } - - public T getInstance(Class apiClass, String target, String replacement) { - String base = apiClass.getName(); - - String implName = - base.replaceFirst( - "org\\.adrianvictor\\.lib", - "org.adrianvictor.lib.impl." + classSuffix - ); - - try { - Class implClass = Class.forName(implName); - - return apiClass.cast( - implClass.getDeclaredConstructor().newInstance() - ); - } catch (ReflectiveOperationException e) { - throw new IllegalStateException("Cannot load " + implName, e); - } - } - - public T getInstance(Class apiClass) { - return getInstance(apiClass, "org.adrianvictor.lib", "org.adrianvictor.lib.impl."); - } -} diff --git a/src/main/java/org/adrianvictor/lib/reflection/VersionMatcher.java b/src/main/java/org/adrianvictor/lib/reflection/VersionMatcher.java index 6c80828..1a77a2b 100644 --- a/src/main/java/org/adrianvictor/lib/reflection/VersionMatcher.java +++ b/src/main/java/org/adrianvictor/lib/reflection/VersionMatcher.java @@ -2,54 +2,53 @@ package org.adrianvictor.lib.reflection; import org.bukkit.Bukkit; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; +import java.util.Comparator; import java.util.List; +import java.util.ArrayList; import java.util.Map; +import java.util.Optional; import java.util.regex.Pattern; +import java.util.regex.Matcher; +import java.util.Collections; public class VersionMatcher { public VersionMatcher() {} - private record Entry(String pattern, String classSuffix) {} + private record Entry(String pattern, String classSuffix, int minMajor, int minMinor, int maxMajor, int maxMinor) {} - public String getClassSuffix(String type, String serverVersion) { - if (type == null || serverVersion == null) { + public String getClassSuffix(String serverVersion) { + if (serverVersion == null) { return null; } - Map> map = populateMap(); - List entries = map.get(type.toLowerCase()); - if (entries == null || entries.isEmpty()) { - return null; - } + List entries = populateEntries(); + List applicableEntries = new ArrayList<>(); - // Exact match - for (Entry e : entries) { - if (safeMatches(e.pattern, serverVersion)) { - return e.classSuffix; + int[] parsedServerVersion = parseVersion(serverVersion); + int serverMajor = parsedServerVersion[0]; + int serverMinor = parsedServerVersion[1]; + + for (Entry entry : entries) { + Pattern p = Pattern.compile(entry.pattern()); + if (p.matcher(serverVersion).matches()) { + if (serverMajor >= entry.minMajor() && serverMinor >= entry.minMinor() && + serverMajor <= entry.maxMajor() && serverMinor <= entry.maxMinor()) { + applicableEntries.add(entry); + } } } - // Fallback to closest version - List sorted = new ArrayList<>(entries); - Collections.sort(sorted, (a, b) -> compareVersions(a.pattern, b.pattern)); + // Sort by version (highest minor first for best match within range) + applicableEntries.sort(Comparator + .comparing(Entry::maxMajor).reversed() + .thenComparing(Entry::maxMinor).reversed() + .thenComparing(Entry::minMajor).reversed() + .thenComparing(Entry::minMinor).reversed()); - Entry oldest = sorted.get(0); - Entry newest = sorted.get(sorted.size() - 1); + Optional bestMatch = applicableEntries.stream().findFirst(); - int cmpOldest = compareVersions(serverVersion, oldest.pattern); - int cmpNewest = compareVersions(serverVersion, newest.pattern); - - if (cmpOldest < 0) { - return oldest.classSuffix; - } else if (cmpNewest > 0) { - return newest.classSuffix; - } - - return newest.classSuffix; + return bestMatch.map(Entry::classSuffix).orElse(null); } public String getServerVersion() { @@ -71,46 +70,21 @@ public class VersionMatcher { return rawVersion; } - private Map> populateMap() { - Map> map = new HashMap<>(); - map.put("release", List.of( - new Entry("^1\\.21\\..*$", "r1_21") - )); - map.put("beta", List.of( - new Entry("^1\\.7\\.3$", "b1_7_3") - )); - return map; + private List populateEntries() { + return List.of( + new Entry("^1\\.7\\.3$", "b1_7_3", 1, 7, 1, 7), + // Covers 1.8 up to 1.16 for compatibility (example for user request) + new Entry("^1\\.(8|9|10|11|12|13|14|15|16)\\..*$", "b1_8_compat", 1, 8, 1, 16), + new Entry("^1\\.21\\..*$", "r1_21", 1, 21, Integer.MAX_VALUE, Integer.MAX_VALUE) // Open-ended for future 1.21.x + ); } - private int compareVersions(String v1, String v2) { - String clean1 = v1.replaceAll("[^0-9.]", ""); - String clean2 = v2.replaceAll("[^0-9.]", ""); - - String[] a1 = clean1.split("\\."); - String[] a2 = clean2.split("\\."); - - int len = Math.max(a1.length, a2.length); - for (int i = 0; i < len; i++) { - int n1 = i < a1.length ? parseInt(a1[i]) : 0; - int n2 = i < a2.length ? parseInt(a2[i]) : 0; - if (n1 != n2) { - return n1 - n2; - } + // Helper to parse major and minor version from a string (e.g., "1.16.5" -> [1, 16]) + private int[] parseVersion(String versionString) { + Matcher matcher = Pattern.compile("^(\\d+)\\.(\\d+).*").matcher(versionString); + if (matcher.find()) { + return new int[]{Integer.parseInt(matcher.group(1)), Integer.parseInt(matcher.group(2))}; } - return 0; - } - - private int parseInt(String s) { - try { - return Integer.parseInt(s); - } catch (NumberFormatException e) { - return 0; - } - } - - private static boolean safeMatches(String expression, String against) { - String cleanPattern = expression.trim(); - Pattern pattern = Pattern.compile(cleanPattern, Pattern.CASE_INSENSITIVE); - return pattern.matcher(against).matches(); + return new int[]{0, 0}; // Default for unknown format } } \ No newline at end of file diff --git a/src/main/java/org/adrianvictor/lib/text/TextColor.java b/src/main/java/org/adrianvictor/lib/text/TextColor.java index 9252de4..26bb87a 100644 --- a/src/main/java/org/adrianvictor/lib/text/TextColor.java +++ b/src/main/java/org/adrianvictor/lib/text/TextColor.java @@ -1,10 +1,10 @@ package org.adrianvictor.lib.text; -import org.adrianvictor.lib.reflection.ImplementationRegistry; +import org.adrianvictor.lib.VersionedServiceFactory; import org.adrianvictor.lib.text.provider.TextColorProvider; public class TextColor { - public static TextColorProvider create(ImplementationRegistry registry) { - return registry.getInstance(TextColorProvider.class); + public static TextColorProvider create(VersionedServiceFactory factory) { + return factory.getService(TextColorProvider.class); } } diff --git a/src/main/java/org/adrianvictor/lib/text/TextColorUtils.java b/src/main/java/org/adrianvictor/lib/text/TextColorUtils.java index 1e1183e..b2d109e 100644 --- a/src/main/java/org/adrianvictor/lib/text/TextColorUtils.java +++ b/src/main/java/org/adrianvictor/lib/text/TextColorUtils.java @@ -1,13 +1,13 @@ package org.adrianvictor.lib.text; -import org.adrianvictor.lib.reflection.ImplementationRegistry; +import org.adrianvictor.lib.VersionedServiceFactory; import org.adrianvictor.lib.text.provider.TextColorProvider; public class TextColorUtils { private final TextColorProvider provider; - public TextColorUtils(ImplementationRegistry registry) { - provider = TextColor.create(registry); + public TextColorUtils(VersionedServiceFactory factory) { + provider = TextColor.create(factory); } public String formatColors(String message) { diff --git a/src/r1_21/java/org/adrianvictor/lib/impl/r1_21/R1_21Registrar.java b/src/r1_21/java/org/adrianvictor/lib/impl/r1_21/R1_21Registrar.java new file mode 100644 index 0000000..d289886 --- /dev/null +++ b/src/r1_21/java/org/adrianvictor/lib/impl/r1_21/R1_21Registrar.java @@ -0,0 +1,16 @@ +package org.adrianvictor.lib.impl.r1_21; + +import org.adrianvictor.lib.VersionedServiceFactory; +import org.adrianvictor.lib.VersionedServiceRegistrar; +import org.adrianvictor.lib.configuration.provider.ConfigurationProvider; +import org.adrianvictor.lib.impl.r1_21.configuration.Configuration; +import org.adrianvictor.lib.text.provider.TextColorProvider; +import org.adrianvictor.lib.impl.r1_21.text.TextColor; + +public class R1_21Registrar implements VersionedServiceRegistrar { + @Override + public void register(VersionedServiceFactory factory) { + factory.register(ConfigurationProvider.class, "r1_21", Configuration::new); + factory.register(TextColorProvider.class, "r1_21", TextColor::new); + } +} diff --git a/src/r1_21/resources/META-INF/services/org.adrianvictor.lib.VersionedServiceRegistrar b/src/r1_21/resources/META-INF/services/org.adrianvictor.lib.VersionedServiceRegistrar new file mode 100644 index 0000000..8f5e531 --- /dev/null +++ b/src/r1_21/resources/META-INF/services/org.adrianvictor.lib.VersionedServiceRegistrar @@ -0,0 +1 @@ +org.adrianvictor.lib.impl.r1_21.R1_21Registrar \ No newline at end of file From 0b753d6a4ed911c497722a9b2297c3990b8b0b42 Mon Sep 17 00:00:00 2001 From: Adrian Victor Date: Sat, 23 May 2026 21:41:17 -0300 Subject: [PATCH 2/2] Finish factory implementation --- .gitignore | 2 + .../DefaultVersionedServiceFactoryTest.java | 65 ++++++++++++------- build.gradle.kts | 13 +++- .../lib/impl/b1_7_3/B1_7_3Registrar.java | 4 +- ....lib.versioning.VersionedServiceRegistrar} | 0 src/main/java/org/adrianvictor/lib/Main.java | 12 ++-- .../lib/configuration/Configuration.java | 2 +- .../org/adrianvictor/lib/text/TextColor.java | 2 +- .../adrianvictor/lib/text/TextColorUtils.java | 2 +- .../DefaultVersionedServiceFactory.java | 6 +- .../VersionMatcher.java | 15 ++--- .../VersionedServiceFactory.java | 2 +- .../VersionedServiceRegistrar.java | 2 +- .../lib/impl/r1_21/R1_21Registrar.java | 8 +-- ....lib.versioning.VersionedServiceRegistrar} | 0 15 files changed, 79 insertions(+), 56 deletions(-) rename src/b1_7_3/resources/META-INF/services/{org.adrianvictor.lib.VersionedServiceRegistrar => org.adrianvictor.lib.versioning.VersionedServiceRegistrar} (100%) rename src/main/java/org/adrianvictor/lib/{ => versioning}/DefaultVersionedServiceFactory.java (87%) rename src/main/java/org/adrianvictor/lib/{reflection => versioning}/VersionMatcher.java (82%) rename src/main/java/org/adrianvictor/lib/{ => versioning}/VersionedServiceFactory.java (84%) rename src/main/java/org/adrianvictor/lib/{ => versioning}/VersionedServiceRegistrar.java (70%) rename src/r1_21/resources/META-INF/services/{org.adrianvictor.lib.VersionedServiceRegistrar => org.adrianvictor.lib.versioning.VersionedServiceRegistrar} (100%) diff --git a/.gitignore b/.gitignore index 46bcab9..df892ec 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,5 @@ out/ # Ignore Gradle build output directory build + +run/ \ No newline at end of file diff --git a/app/src/test/java/org/adrianvictor/lib/DefaultVersionedServiceFactoryTest.java b/app/src/test/java/org/adrianvictor/lib/DefaultVersionedServiceFactoryTest.java index ca7b1b6..a624d68 100644 --- a/app/src/test/java/org/adrianvictor/lib/DefaultVersionedServiceFactoryTest.java +++ b/app/src/test/java/org/adrianvictor/lib/DefaultVersionedServiceFactoryTest.java @@ -1,11 +1,12 @@ package org.adrianvictor.lib; -import org.adrianvictor.lib.reflection.VersionMatcher; +import org.adrianvictor.lib.versioning.DefaultVersionedServiceFactory; +import org.adrianvictor.lib.versioning.VersionMatcher; +import org.adrianvictor.lib.versioning.VersionedServiceFactory; +import org.adrianvictor.lib.versioning.VersionedServiceRegistrar; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import java.util.function.Supplier; - import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; @@ -19,14 +20,15 @@ class DummyRegistrarB1_7_3 implements VersionedServiceRegistrar { @Override public void register(VersionedServiceFactory factory) { factory.register(TestService.class, "b1_7_3", TestServiceB1_7_3::new); - factory.register(TestService.class, "b1_8_compat", TestServiceB1_7_3::new); // Register for b1_8_compat } } class DummyRegistrarR1_21 implements VersionedServiceRegistrar { @Override public void register(VersionedServiceFactory factory) { - factory.register(TestService.class, "r1_21", TestServiceR1_21::new); + factory.register(TestService.class, "r1_1", TestServiceR1_21::new); // Registers for r1_1 compat + factory.register(TestService.class, "r1_16_5", TestServiceR1_21::new); // Registers for r1_16_5 compat + factory.register(TestService.class, "r1_21", TestServiceR1_21::new); // Registers for r1_21 } } @@ -59,6 +61,40 @@ public class DefaultVersionedServiceFactoryTest { assertTrue(service instanceof TestServiceB1_7_3); } + @Test + void testServiceRegistrationAndRetrievalForR1_1() { + // Mock VersionMatcher to return r1_1 suffix for a 1.10.2 server + when(mockVersionMatcher.getServerVersion()).thenReturn("1.10.2"); + when(mockVersionMatcher.getClassSuffix(eq("1.10.2"))).thenReturn("r1_1"); + + // Register the dummy service for R1_21 (which covers r1_1 compat) + new DummyRegistrarR1_21().register(factory); + + // Retrieve the service + TestService service = factory.getService(TestService.class); + + // Assert that the correct compatible version is returned + assertNotNull(service); + assertTrue(service instanceof TestServiceR1_21); + } + + @Test + void testServiceRegistrationAndRetrievalForR1_16_5() { + // Mock VersionMatcher to return r1_16_5 suffix for a 1.18.1 server + when(mockVersionMatcher.getServerVersion()).thenReturn("1.18.1"); + when(mockVersionMatcher.getClassSuffix(eq("1.18.1"))).thenReturn("r1_16_5"); + + // Register the dummy service for R1_21 (which covers r1_16_5 compat) + new DummyRegistrarR1_21().register(factory); + + // Retrieve the service + TestService service = factory.getService(TestService.class); + + // Assert that the correct compatible version is returned + assertNotNull(service); + assertTrue(service instanceof TestServiceR1_21); + } + @Test void testServiceRegistrationAndRetrievalForR1_21() { // Mock VersionMatcher to return r1_21 suffix @@ -76,23 +112,6 @@ public class DefaultVersionedServiceFactoryTest { assertTrue(service instanceof TestServiceR1_21); } - @Test - void testServiceRegistrationAndRetrievalForB1_8_Compat() { - // Mock VersionMatcher to return b1_8_compat suffix for a 1.16.5 server - when(mockVersionMatcher.getServerVersion()).thenReturn("1.16.5"); - when(mockVersionMatcher.getClassSuffix(eq("1.16.5"))).thenReturn("b1_8_compat"); - - // Register the dummy service for b1_7_3 (which also covers b1_8_compat) - new DummyRegistrarB1_7_3().register(factory); - - // Retrieve the service - TestService service = factory.getService(TestService.class); - - // Assert that the correct compatible version is returned - assertNotNull(service); - assertTrue(service instanceof TestServiceB1_7_3); - } - @Test void testNoServiceRegisteredThrowsException() { // Mock VersionMatcher to return an unknown suffix @@ -114,7 +133,7 @@ public class DefaultVersionedServiceFactoryTest { when(mockVersionMatcher.getClassSuffix(eq("1.7.3"))).thenReturn("b1_7_3"); // Register R1_21 service, but not B1_7_3 - new DummyRegistrarR1_21().register(factory); + new DummyRegistrarR1_21().register(factory); // R1_21 registrar doesn't register b1_7_3 // Attempt to retrieve b1_7_3 service IllegalStateException exception = assertThrows(IllegalStateException.class, () -> diff --git a/build.gradle.kts b/build.gradle.kts index ecd5724..3e973c0 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,6 +1,6 @@ plugins { java - id("xyz.jpenilla.run-paper") version "2.3.1" + id("xyz.jpenilla.run-paper") version "3.0.1" } group = "org.adrianvictor" @@ -70,7 +70,7 @@ dependencies { /* ----------------------------------------- */ mcVersions.forEach { ver -> - tasks.register("jar${ver.replace(".", "_").replace("-", "_").replace("/", "_").capitalize()}") { + tasks.register("jar${ver.replace(".", "_").replace("-", "_").replace("/", "_").replaceFirstChar { it.uppercase() }}") { duplicatesStrategy = DuplicatesStrategy.EXCLUDE from(sourceSets["main"].output) from(sourceSets[ver].output) @@ -126,4 +126,13 @@ java { tasks.withType { options.encoding = "UTF-8" +} + +/* ----------------------------------------- */ +/* RUN SETTINGS */ +/* ----------------------------------------- */ + +tasks.runServer { + minecraftVersion("1.21.1") + pluginJars.from(tasks.named("jarR1_21")) } \ No newline at end of file diff --git a/src/b1_7_3/java/org/adrianvictor/lib/impl/b1_7_3/B1_7_3Registrar.java b/src/b1_7_3/java/org/adrianvictor/lib/impl/b1_7_3/B1_7_3Registrar.java index 197a704..2475ca3 100644 --- a/src/b1_7_3/java/org/adrianvictor/lib/impl/b1_7_3/B1_7_3Registrar.java +++ b/src/b1_7_3/java/org/adrianvictor/lib/impl/b1_7_3/B1_7_3Registrar.java @@ -1,7 +1,7 @@ package org.adrianvictor.lib.impl.b1_7_3; -import org.adrianvictor.lib.VersionedServiceFactory; -import org.adrianvictor.lib.VersionedServiceRegistrar; +import org.adrianvictor.lib.versioning.VersionedServiceFactory; +import org.adrianvictor.lib.versioning.VersionedServiceRegistrar; import org.adrianvictor.lib.configuration.provider.ConfigurationProvider; import org.adrianvictor.lib.impl.b1_7_3.configuration.Configuration; import org.adrianvictor.lib.text.provider.TextColorProvider; diff --git a/src/b1_7_3/resources/META-INF/services/org.adrianvictor.lib.VersionedServiceRegistrar b/src/b1_7_3/resources/META-INF/services/org.adrianvictor.lib.versioning.VersionedServiceRegistrar similarity index 100% rename from src/b1_7_3/resources/META-INF/services/org.adrianvictor.lib.VersionedServiceRegistrar rename to src/b1_7_3/resources/META-INF/services/org.adrianvictor.lib.versioning.VersionedServiceRegistrar diff --git a/src/main/java/org/adrianvictor/lib/Main.java b/src/main/java/org/adrianvictor/lib/Main.java index 2371249..a16c99d 100644 --- a/src/main/java/org/adrianvictor/lib/Main.java +++ b/src/main/java/org/adrianvictor/lib/Main.java @@ -1,6 +1,9 @@ package org.adrianvictor.lib; -import org.adrianvictor.lib.reflection.VersionMatcher; +import org.adrianvictor.lib.versioning.DefaultVersionedServiceFactory; +import org.adrianvictor.lib.versioning.VersionMatcher; +import org.adrianvictor.lib.versioning.VersionedServiceFactory; +import org.adrianvictor.lib.versioning.VersionedServiceRegistrar; import org.bukkit.plugin.java.JavaPlugin; import java.util.ServiceLoader; @@ -12,22 +15,15 @@ public class Main extends JavaPlugin { @Override public void onEnable() { - // Initialize VersionMatcher versionMatcher = new VersionMatcher(); - // Initialize DefaultVersionedServiceFactory versionedServiceFactory = new DefaultVersionedServiceFactory(versionMatcher); - // Discover and register version-specific implementations using ServiceLoader ServiceLoader registrars = ServiceLoader.load(VersionedServiceRegistrar.class); for (VersionedServiceRegistrar registrar : registrars) { registrar.register(versionedServiceFactory); } - // Example usage (for demonstration, can be removed later) - // ConfigurationProvider configProvider = Configuration.create(versionedServiceFactory); - // TextColorProvider textColorProvider = TextColor.create(versionedServiceFactory); - getLogger().info("tenkumaLib has been enabled!"); } diff --git a/src/main/java/org/adrianvictor/lib/configuration/Configuration.java b/src/main/java/org/adrianvictor/lib/configuration/Configuration.java index fa8999b..8cee615 100644 --- a/src/main/java/org/adrianvictor/lib/configuration/Configuration.java +++ b/src/main/java/org/adrianvictor/lib/configuration/Configuration.java @@ -1,6 +1,6 @@ package org.adrianvictor.lib.configuration; -import org.adrianvictor.lib.VersionedServiceFactory; +import org.adrianvictor.lib.versioning.VersionedServiceFactory; import org.adrianvictor.lib.configuration.provider.ConfigurationProvider; public class Configuration { diff --git a/src/main/java/org/adrianvictor/lib/text/TextColor.java b/src/main/java/org/adrianvictor/lib/text/TextColor.java index 26bb87a..c07ebdf 100644 --- a/src/main/java/org/adrianvictor/lib/text/TextColor.java +++ b/src/main/java/org/adrianvictor/lib/text/TextColor.java @@ -1,6 +1,6 @@ package org.adrianvictor.lib.text; -import org.adrianvictor.lib.VersionedServiceFactory; +import org.adrianvictor.lib.versioning.VersionedServiceFactory; import org.adrianvictor.lib.text.provider.TextColorProvider; public class TextColor { diff --git a/src/main/java/org/adrianvictor/lib/text/TextColorUtils.java b/src/main/java/org/adrianvictor/lib/text/TextColorUtils.java index b2d109e..81ba3cf 100644 --- a/src/main/java/org/adrianvictor/lib/text/TextColorUtils.java +++ b/src/main/java/org/adrianvictor/lib/text/TextColorUtils.java @@ -1,6 +1,6 @@ package org.adrianvictor.lib.text; -import org.adrianvictor.lib.VersionedServiceFactory; +import org.adrianvictor.lib.versioning.VersionedServiceFactory; import org.adrianvictor.lib.text.provider.TextColorProvider; public class TextColorUtils { diff --git a/src/main/java/org/adrianvictor/lib/DefaultVersionedServiceFactory.java b/src/main/java/org/adrianvictor/lib/versioning/DefaultVersionedServiceFactory.java similarity index 87% rename from src/main/java/org/adrianvictor/lib/DefaultVersionedServiceFactory.java rename to src/main/java/org/adrianvictor/lib/versioning/DefaultVersionedServiceFactory.java index 6be8582..9f528cf 100644 --- a/src/main/java/org/adrianvictor/lib/DefaultVersionedServiceFactory.java +++ b/src/main/java/org/adrianvictor/lib/versioning/DefaultVersionedServiceFactory.java @@ -1,6 +1,5 @@ -package org.adrianvictor.lib; +package org.adrianvictor.lib.versioning; -import org.adrianvictor.lib.reflection.VersionMatcher; import java.util.HashMap; import java.util.Map; import java.util.function.Supplier; @@ -24,8 +23,7 @@ public class DefaultVersionedServiceFactory implements VersionedServiceFactory { @SuppressWarnings("unchecked") public T getService(Class serviceType) { String serverVersion = versionMatcher.getServerVersion(); - // Determine the correct suffix using VersionMatcher (adapted) - String versionSuffix = versionMatcher.getClassSuffix(serverVersion); // Removed "release" parameter + String versionSuffix = versionMatcher.getClassSuffix(serverVersion); Map> versionSuppliers = serviceRegistrations.get(serviceType); if (versionSuppliers == null || !versionSuppliers.containsKey(versionSuffix)) { diff --git a/src/main/java/org/adrianvictor/lib/reflection/VersionMatcher.java b/src/main/java/org/adrianvictor/lib/versioning/VersionMatcher.java similarity index 82% rename from src/main/java/org/adrianvictor/lib/reflection/VersionMatcher.java rename to src/main/java/org/adrianvictor/lib/versioning/VersionMatcher.java index 1a77a2b..91fee05 100644 --- a/src/main/java/org/adrianvictor/lib/reflection/VersionMatcher.java +++ b/src/main/java/org/adrianvictor/lib/versioning/VersionMatcher.java @@ -1,15 +1,13 @@ -package org.adrianvictor.lib.reflection; +package org.adrianvictor.lib.versioning; import org.bukkit.Bukkit; import java.util.Comparator; import java.util.List; import java.util.ArrayList; -import java.util.Map; import java.util.Optional; import java.util.regex.Pattern; import java.util.regex.Matcher; -import java.util.Collections; public class VersionMatcher { @@ -39,7 +37,6 @@ public class VersionMatcher { } } - // Sort by version (highest minor first for best match within range) applicableEntries.sort(Comparator .comparing(Entry::maxMajor).reversed() .thenComparing(Entry::maxMinor).reversed() @@ -73,13 +70,15 @@ public class VersionMatcher { private List populateEntries() { return List.of( new Entry("^1\\.7\\.3$", "b1_7_3", 1, 7, 1, 7), - // Covers 1.8 up to 1.16 for compatibility (example for user request) - new Entry("^1\\.(8|9|10|11|12|13|14|15|16)\\..*$", "b1_8_compat", 1, 8, 1, 16), - new Entry("^1\\.21\\..*$", "r1_21", 1, 21, Integer.MAX_VALUE, Integer.MAX_VALUE) // Open-ended for future 1.21.x + // r1_1 covers versions from 1.1.x up to 1.16.4 + new Entry("^1\\.(1[0-5]|[1-9])(\\.\\d+)*$", "r1_1", 1, 1, 1, 16), + // r1_16_5 covers versions from 1.16.5 up to 1.20.x + new Entry("^1\\.(16\\.[5-9]|1[7-9]|20)(\\.\\d+)*$", "r1_16_5", 1, 16, 1, 20), + // r1_21 covers 1.21.x and above + new Entry("^1\\.21(\\.\\d+)*$", "r1_21", 1, 21, Integer.MAX_VALUE, Integer.MAX_VALUE) ); } - // Helper to parse major and minor version from a string (e.g., "1.16.5" -> [1, 16]) private int[] parseVersion(String versionString) { Matcher matcher = Pattern.compile("^(\\d+)\\.(\\d+).*").matcher(versionString); if (matcher.find()) { diff --git a/src/main/java/org/adrianvictor/lib/VersionedServiceFactory.java b/src/main/java/org/adrianvictor/lib/versioning/VersionedServiceFactory.java similarity index 84% rename from src/main/java/org/adrianvictor/lib/VersionedServiceFactory.java rename to src/main/java/org/adrianvictor/lib/versioning/VersionedServiceFactory.java index 749689d..850faea 100644 --- a/src/main/java/org/adrianvictor/lib/VersionedServiceFactory.java +++ b/src/main/java/org/adrianvictor/lib/versioning/VersionedServiceFactory.java @@ -1,4 +1,4 @@ -package org.adrianvictor.lib; +package org.adrianvictor.lib.versioning; import java.util.function.Supplier; diff --git a/src/main/java/org/adrianvictor/lib/VersionedServiceRegistrar.java b/src/main/java/org/adrianvictor/lib/versioning/VersionedServiceRegistrar.java similarity index 70% rename from src/main/java/org/adrianvictor/lib/VersionedServiceRegistrar.java rename to src/main/java/org/adrianvictor/lib/versioning/VersionedServiceRegistrar.java index ed78bc4..ee3fe52 100644 --- a/src/main/java/org/adrianvictor/lib/VersionedServiceRegistrar.java +++ b/src/main/java/org/adrianvictor/lib/versioning/VersionedServiceRegistrar.java @@ -1,4 +1,4 @@ -package org.adrianvictor.lib; +package org.adrianvictor.lib.versioning; public interface VersionedServiceRegistrar { void register(VersionedServiceFactory factory); diff --git a/src/r1_21/java/org/adrianvictor/lib/impl/r1_21/R1_21Registrar.java b/src/r1_21/java/org/adrianvictor/lib/impl/r1_21/R1_21Registrar.java index d289886..d4b10b4 100644 --- a/src/r1_21/java/org/adrianvictor/lib/impl/r1_21/R1_21Registrar.java +++ b/src/r1_21/java/org/adrianvictor/lib/impl/r1_21/R1_21Registrar.java @@ -1,7 +1,7 @@ package org.adrianvictor.lib.impl.r1_21; -import org.adrianvictor.lib.VersionedServiceFactory; -import org.adrianvictor.lib.VersionedServiceRegistrar; +import org.adrianvictor.lib.versioning.VersionedServiceFactory; +import org.adrianvictor.lib.versioning.VersionedServiceRegistrar; import org.adrianvictor.lib.configuration.provider.ConfigurationProvider; import org.adrianvictor.lib.impl.r1_21.configuration.Configuration; import org.adrianvictor.lib.text.provider.TextColorProvider; @@ -10,7 +10,7 @@ import org.adrianvictor.lib.impl.r1_21.text.TextColor; public class R1_21Registrar implements VersionedServiceRegistrar { @Override public void register(VersionedServiceFactory factory) { - factory.register(ConfigurationProvider.class, "r1_21", Configuration::new); - factory.register(TextColorProvider.class, "r1_21", TextColor::new); + factory.register(ConfigurationProvider.class, "r1_1", Configuration::new); + factory.register(TextColorProvider.class, "r1_16_5", TextColor::new); } } diff --git a/src/r1_21/resources/META-INF/services/org.adrianvictor.lib.VersionedServiceRegistrar b/src/r1_21/resources/META-INF/services/org.adrianvictor.lib.versioning.VersionedServiceRegistrar similarity index 100% rename from src/r1_21/resources/META-INF/services/org.adrianvictor.lib.VersionedServiceRegistrar rename to src/r1_21/resources/META-INF/services/org.adrianvictor.lib.versioning.VersionedServiceRegistrar