Skip to content

Commit 8dd88b0

Browse files
Updated ClassFinder
ClassFinders: Added an option to set the JarFile Added an option to set the ClassLoader This is useful when working with jar files loaded as modules. For example, Spigot plugins. Fixed an issue where the IdeClassFinder wouldn't correctly find classes if the base package is empty. Fixed UpToDate check, this will no longer say an update is available when the current version matches upstream.
1 parent fa5a114 commit 8dd88b0

File tree

9 files changed

+150
-62
lines changed

9 files changed

+150
-62
lines changed

pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929

3030
<groupId>top.wavelength</groupId>
3131
<artifactId>Java-BetterReflection</artifactId>
32-
<version>1.2</version>
32+
<version>1.3</version>
3333

3434
<properties>
3535
<maven.compiler.source>1.8</maven.compiler.source>

src/main/java/top/wavelength/betterreflection/BetterReflection.java

+17-6
Original file line numberDiff line numberDiff line change
@@ -140,12 +140,23 @@ public static FutureTask<Boolean> isUpToDate() {
140140
latestVersionFuture.run();
141141
int[] latestVersion = versionToInts(latestVersionFuture.get());
142142
int minLength = Math.min(version.length, latestVersion.length);
143-
for (int i = 0; i < Math.max(version.length, latestVersion.length); i++)
144-
if (minLength > i && version[i] > latestVersion[i])
145-
return true;
146-
return false;
147-
});
148143

144+
// Compare each segment up to the common length
145+
for (int i = 0; i < minLength; i++)
146+
if (version[i] > latestVersion[i])
147+
return true; // Current version is newer
148+
else if (version[i] < latestVersion[i])
149+
return false; // Current version is older
150+
151+
// If versions are equal up to the common length, check if current version has extra segments
152+
if (version.length > latestVersion.length)
153+
for (int i = latestVersion.length; i < version.length; i++)
154+
if (version[i] > 0)
155+
return true; // Current version is newer due to additional non-zero segments
156+
157+
// If we reach here, the versions are either equal or the current version has extra zeros
158+
return true; // Current version is up to date or equal
159+
});
149160
}
150161

151162
/**
@@ -155,7 +166,7 @@ public static FutureTask<Boolean> isUpToDate() {
155166
* @since 0.4
156167
*/
157168
public static String getVersion() {
158-
return "1.2";
169+
return "1.3";
159170
}
160171

161172
/**

src/main/java/top/wavelength/betterreflection/BetterReflectionUtils.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ public static List<File> getDirectoriesFromPackageName(String packageName) throw
246246
* @deprecated This method is deprecated in favour of ClassFinder
247247
*/
248248
@Deprecated
249-
public static List<BetterReflectionClass<Object>> getClassesInPackage(String packageName) throws IOException, URISyntaxException, CannotReadJarException {
249+
public static List<BetterReflectionClass<Object>> getClassesInPackage(String packageName) throws IOException, URISyntaxException, CannotReadJarException, ClassNotFoundException {
250250
return ClassFinderFactory.create(packageName, CLASS).findClasses();
251251
}
252252

@@ -267,7 +267,7 @@ public static List<BetterReflectionClass<Object>> getClassesInPackage(String pac
267267
* Jar and the Jar file cannot be found or it
268268
* cannot be read.
269269
*/
270-
public static List<BetterReflectionClass<?>> getClassesFromNameBeginning(String packageName, String beginning) throws IOException, URISyntaxException, CannotReadJarException {
270+
public static List<BetterReflectionClass<?>> getClassesFromNameBeginning(String packageName, String beginning) throws IOException, URISyntaxException, CannotReadJarException, ClassNotFoundException {
271271
List<BetterReflectionClass<?>> classes = new ArrayList<>();
272272
for (BetterReflectionClass<?> clasz : getClassesInPackage(packageName))
273273
if (clasz.getSimpleName().startsWith(beginning))

src/main/java/top/wavelength/betterreflection/lookup/ClassFinder.java

+69-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package top.wavelength.betterreflection.lookup;
22

33
import top.wavelength.betterreflection.BetterReflectionClass;
4+
import top.wavelength.betterreflection.BetterReflectionUtils;
45

6+
import java.io.File;
57
import java.io.IOException;
68
import java.net.URISyntaxException;
79
import java.util.Iterator;
@@ -15,10 +17,28 @@
1517
*/
1618
public abstract class ClassFinder<T> implements Iterable<BetterReflectionClass<T>> {
1719

20+
/**
21+
* @since 1.1
22+
*/
1823
protected final String basePackage;
24+
/**
25+
* @since 1.1
26+
*/
1927
private boolean recursive;
28+
/**
29+
* @since 1.1
30+
*/
2031
private BetterReflectionClass<T> type;
2132

33+
/**
34+
* @since 1.3
35+
*/
36+
private ClassLoader classLoader = getClass().getClassLoader();
37+
/**
38+
* @since 1.3
39+
*/
40+
private File jarFile = BetterReflectionUtils.LAUNCH_JAR_FILE;
41+
2242
/**
2343
* Constructs a ClassFinder object with the given base package parameter.
2444
*
@@ -52,6 +72,16 @@ public ClassFinder<T> ofType(BetterReflectionClass<T> type) {
5272
return this;
5373
}
5474

75+
/**
76+
* Retrieves the type of the ClassFinder instance.
77+
*
78+
* @return the BetterReflectionClass representing the type.
79+
* @since 1.1
80+
*/
81+
public BetterReflectionClass<?> getType() {
82+
return type;
83+
}
84+
5585
/**
5686
* Sets the recursive flag of the ClassFinder instance.
5787
*
@@ -75,13 +105,47 @@ public boolean isRecursive() {
75105
}
76106

77107
/**
78-
* Retrieves the type of the ClassFinder instance.
108+
* Sets the class loader that will be used to load the classes for this ClassFinder instance.
79109
*
80-
* @return the BetterReflectionClass representing the type.
81-
* @since 1.1
110+
* @param classLoader the {@link ClassLoader} instance to be used for loading classes
111+
* @return the updated {@link ClassFinder} instance
112+
* @since 1.3
82113
*/
83-
public BetterReflectionClass<?> getType() {
84-
return type;
114+
public ClassFinder<T> classLoader(ClassLoader classLoader) {
115+
this.classLoader = classLoader;
116+
return this;
117+
}
118+
119+
/**
120+
* Retrieves the class loader currently set for this ClassFinder instance.
121+
*
122+
* @return the {@link ClassLoader} instance being used to load classes
123+
* @since 1.3
124+
*/
125+
public ClassLoader getClassLoader() {
126+
return classLoader;
127+
}
128+
129+
/**
130+
* Sets the jar file that this ClassFinder will search for classes.
131+
*
132+
* @param jarFile the {@link File} representing the jar file to search for classes
133+
* @return the updated {@link File} instance
134+
* @since 1.3
135+
*/
136+
public ClassFinder<T> jarFile(File jarFile) {
137+
this.jarFile = jarFile;
138+
return this;
139+
}
140+
141+
/**
142+
* Retrieves the jar file currently set for this ClassFinder instance.
143+
*
144+
* @return the {@link File} representing the jar file being searched for classes
145+
* @since 1.3
146+
*/
147+
public File getJarFile() {
148+
return jarFile;
85149
}
86150

87151
/**

src/main/java/top/wavelength/betterreflection/lookup/IdeClassFinder.java

+15-3
Original file line numberDiff line numberDiff line change
@@ -56,17 +56,29 @@ public List<BetterReflectionClass<T>> findClasses() throws IOException, URISynta
5656
@SuppressWarnings("unchecked")
5757
public List<BetterReflectionClass<T>> scanDirectory(List<File> directories, String packageName) {
5858
List<BetterReflectionClass<T>> classes = new ArrayList<>();
59+
60+
String base = packageName == null || packageName.trim().isEmpty() ? "" : packageName + '.';
61+
5962
for (File directory : directories) {
6063
File[] files = directory.listFiles();
6164
assert files != null;
62-
for (File file : files)
65+
for (File file : files) {
6366
if (file.isDirectory() && isRecursive())
64-
classes.addAll(scanDirectory(Collections.singletonList(file), packageName + "." + file.getName()));
67+
classes.addAll(scanDirectory(Collections.singletonList(file), base + file.getName()));
6568
else if (file.getName().endsWith(".class")) {
66-
BetterReflectionClass<?> clasz = BetterReflectionClass.forName(packageName + '.' + file.getName().substring(0, file.getName().lastIndexOf('.')));
69+
String className = base + file.getName().substring(0, file.getName().lastIndexOf('.'));
70+
71+
BetterReflectionClass<?> clasz;
72+
try {
73+
clasz = new BetterReflectionClass<>(Class.forName(className, true, getClassLoader()));
74+
} catch (ClassNotFoundException | NoClassDefFoundError e) {
75+
continue;
76+
}
77+
6778
if (getType() == null || getType().isAssignableFrom(Objects.requireNonNull(clasz)))
6879
classes.add((BetterReflectionClass<T>) clasz);
6980
}
81+
}
7082
}
7183
return classes;
7284
}

src/main/java/top/wavelength/betterreflection/lookup/JarClassFinder.java

+22-16
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@
33
import top.wavelength.betterreflection.BetterReflectionClass;
44
import top.wavelength.betterreflection.exceptions.CannotReadJarException;
55

6+
import java.io.File;
67
import java.io.IOException;
7-
import java.util.*;
8+
import java.util.ArrayList;
9+
import java.util.Enumeration;
10+
import java.util.List;
11+
import java.util.Objects;
812
import java.util.jar.JarEntry;
913
import java.util.jar.JarFile;
1014

11-
import static top.wavelength.betterreflection.BetterReflectionUtils.LAUNCH_JAR_FILE;
12-
1315
/**
1416
* JarClassFinder is a concrete implementation of the ClassFinder abstract class that is used to
1517
* find classes in a package from a JAR file based on certain criteria.
@@ -40,14 +42,13 @@ public JarClassFinder(String packageName) {
4042
@SuppressWarnings("unchecked")
4143
@Override
4244
public List<BetterReflectionClass<T>> findClasses() throws IOException {
43-
if (basePackage == null || basePackage.trim().isEmpty())
44-
return Collections.emptyList();
4545
List<BetterReflectionClass<T>> classes = new ArrayList<>();
46-
String basePackage = this.basePackage.replace('.', '/');
47-
if (LAUNCH_JAR_FILE == null || !LAUNCH_JAR_FILE.exists() || !LAUNCH_JAR_FILE.canRead())
48-
throw new CannotReadJarException(LAUNCH_JAR_FILE == null ? "[NO NAME]" : LAUNCH_JAR_FILE.getName());
46+
String basePackage = this.basePackage == null ? "" : this.basePackage.replace('.', '/');
47+
File jarFile = getJarFile();
48+
if (jarFile == null || !jarFile.exists() || !jarFile.canRead())
49+
throw new CannotReadJarException(jarFile == null ? "[NO NAME]" : jarFile.getName());
4950

50-
try (JarFile jar = new JarFile(LAUNCH_JAR_FILE)) {
51+
try (JarFile jar = new JarFile(jarFile)) {
5152
Enumeration<JarEntry> entries = jar.entries();
5253
while (entries.hasMoreElements()) {
5354
JarEntry entry = entries.nextElement();
@@ -60,14 +61,19 @@ public List<BetterReflectionClass<T>> findClasses() throws IOException {
6061
String packageName = entry.getName().substring(0, name.lastIndexOf('/')).replace('/', '.');
6162
String className = entry.getName().substring(packageName.length() + 1, entry.getName().lastIndexOf('.'));
6263
String fullName = packageName + '.' + className;
63-
BetterReflectionClass<?> clasz = BetterReflectionClass.forName(fullName);
64-
if (getType() == null || getType().isAssignableFrom(Objects.requireNonNull(clasz)))
65-
classes.add((BetterReflectionClass<T>) clasz);
6664

67-
if (isRecursive()) {
68-
if (packageName.startsWith(basePackage))
69-
classes.add((BetterReflectionClass<T>) clasz);
70-
} else if (packageName.equals(basePackage))
65+
if ((isRecursive() && !packageName.startsWith(basePackage))
66+
|| (!isRecursive() && !packageName.equalsIgnoreCase(basePackage)))
67+
continue;
68+
69+
BetterReflectionClass<?> clasz;
70+
try {
71+
clasz = new BetterReflectionClass<>(Class.forName(fullName, true, getClassLoader()));
72+
} catch (ClassNotFoundException | NoClassDefFoundError e) {
73+
continue;
74+
}
75+
76+
if (getType() == null || getType().isAssignableFrom(Objects.requireNonNull(clasz)))
7177
classes.add((BetterReflectionClass<T>) clasz);
7278
}
7379
}

src/test/java/top/wavelength/betterreflection/lookup/ClassFinderTest.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
public class ClassFinderTest {
1515

1616
@Test
17-
public void testNonRecursive() throws IOException, URISyntaxException {
17+
public void testNonRecursive() throws IOException, URISyntaxException, ClassNotFoundException {
1818
BetterReflectionClass<ClassFinderTest> thisClass = new BetterReflectionClass<>(ClassFinderTest.class);
1919

2020
// Create a ClassFinder instance
@@ -38,7 +38,7 @@ public void testNonRecursive() throws IOException, URISyntaxException {
3838
}
3939

4040
@Test
41-
public void testRecursive() throws IOException, URISyntaxException {
41+
public void testRecursive() throws IOException, URISyntaxException, ClassNotFoundException {
4242
BetterReflectionClass<ClassFinderTest> thisClass = new BetterReflectionClass<>(ClassFinderTest.class);
4343

4444
// Create a ClassFinder instance
@@ -58,7 +58,7 @@ public void testRecursive() throws IOException, URISyntaxException {
5858
}
5959

6060
@Test
61-
public void testWithType() throws IOException, URISyntaxException {
61+
public void testWithType() throws IOException, URISyntaxException, ClassNotFoundException {
6262
// Create a mock for BetterReflectionClass
6363
BetterReflectionClass<TestLookupClass> testLookupClass = new BetterReflectionClass<>(TestLookupClass.class);
6464
BetterReflectionClass<ClassFinderTest> thisClass = new BetterReflectionClass<>(ClassFinderTest.class);
@@ -84,7 +84,7 @@ public void testWithType() throws IOException, URISyntaxException {
8484
}
8585

8686
@Test
87-
public void testWithTypeRecursive() throws IOException, URISyntaxException {
87+
public void testWithTypeRecursive() throws IOException, URISyntaxException, ClassNotFoundException {
8888
// Create a mock for BetterReflectionClass
8989
BetterReflectionClass<TestLookupClass> testLookupClass = new BetterReflectionClass<>(TestLookupClass.class);
9090
BetterReflectionClass<ClassFinderTest> thisClass = new BetterReflectionClass<>(ClassFinderTest.class);

src/test/java/top/wavelength/betterreflection/test/ClassFinderTest.java

-25
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package top.wavelength.betterreflection.test;
2+
3+
import org.junit.jupiter.api.Test;
4+
import top.wavelength.betterreflection.BetterReflection;
5+
6+
import java.util.concurrent.ExecutionException;
7+
import java.util.concurrent.FutureTask;
8+
9+
import static org.junit.jupiter.api.Assertions.assertTrue;
10+
11+
public class UpToDateTest {
12+
13+
@Test
14+
public void upToDateTest() throws ExecutionException, InterruptedException {
15+
FutureTask<Boolean> upToDateTask = BetterReflection.isUpToDate();
16+
upToDateTask.run();
17+
assertTrue(upToDateTask.get(), "Not up to date.");
18+
}
19+
20+
}

0 commit comments

Comments
 (0)