Skip to content

Commit 51fe320

Browse files
committed
Use Reflections library rather than Jar class scanning
1 parent d2c9293 commit 51fe320

File tree

3 files changed

+89
-39
lines changed

3 files changed

+89
-39
lines changed

build.gradle

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
plugins {
2-
id "java"
3-
id "application"
2+
id 'com.gradleup.shadow' version '9.0.0-beta12'
3+
id 'application'
4+
id 'java'
45
}
56

6-
mainClassName = "io.github.syst3ms.skriptparser.Parser"
7+
compileTestJava.options.encoding = 'UTF-8'
8+
compileJava.options.encoding = 'UTF-8'
79

8-
sourceCompatibility = 1.11
10+
mainClassName = "io.github.syst3ms.skriptparser.Parser"
911

1012
repositories {
1113
mavenCentral()
@@ -16,12 +18,25 @@ test {
1618
}
1719

1820
dependencies {
19-
implementation "org.jetbrains:annotations:15.0"
20-
implementation group: "com.google.code.findbugs", name: "jsr305", version: "3.0.2"
21-
testRuntimeOnly "org.junit.vintage:junit-vintage-engine:5.4.1"
22-
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.4.1"
23-
testImplementation "junit:junit:4.12"
24-
testImplementation "org.junit.jupiter:junit-jupiter-api:5.4.1"
21+
implementation (group: 'com.google.code.findbugs', name: 'jsr305', version: '3.0.2')
22+
implementation (group: 'org.jetbrains', name: 'annotations', version: '26.0.2')
23+
24+
shadow (group: 'org.reflections', name: 'reflections', version: '0.10.2')
25+
shadow (group: 'org.javassist', name: 'javassist', version: '3.30.2-GA')
26+
shadow (group: 'com.google.code.gson', name: 'gson', version: '2.13.0')
27+
28+
testRuntimeOnly (group: 'org.junit.vintage', name: 'junit-vintage-engine', version: '5.11.4')
29+
testRuntimeOnly (group: 'org.junit.jupiter', name:'junit-jupiter-engine', version: '5.11.4')
30+
31+
testImplementation (group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.11.4')
32+
testImplementation (group: 'com.google.code.gson', name: 'gson', version: '2.13.0')
33+
testImplementation (group: 'junit', name: 'junit', version: '4.13.2')
34+
}
35+
36+
java {
37+
withSourcesJar()
38+
sourceCompatibility = JavaVersion.VERSION_17
39+
targetCompatibility = JavaVersion.VERSION_17
2540
}
2641

2742
jar {
@@ -30,4 +45,4 @@ jar {
3045
"Implementation-Title": "skript-parser",
3146
"Implementation-Version": "alpha")
3247
}
33-
}
48+
}

src/main/java/io/github/syst3ms/skriptparser/Parser.java

Lines changed: 55 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
import io.github.syst3ms.skriptparser.registration.SkriptAddon;
88
import io.github.syst3ms.skriptparser.registration.SkriptRegistration;
99
import io.github.syst3ms.skriptparser.util.ConsoleColors;
10-
import io.github.syst3ms.skriptparser.util.FileUtils;
10+
import org.jetbrains.annotations.Nullable;
11+
import org.reflections.Reflections;
12+
import org.reflections.scanners.Scanners;
1113

1214
import java.io.IOException;
1315
import java.lang.reflect.InvocationTargetException;
@@ -23,12 +25,12 @@
2325
import java.util.Calendar;
2426
import java.util.List;
2527
import java.util.jar.JarFile;
26-
import java.util.jar.Manifest;
2728

2829
public class Parser {
30+
2931
public static final String CONSOLE_FORMAT = "[%tT] %s: %s%n";
30-
private static SkriptRegistration registration;
3132

33+
private static SkriptRegistration registration;
3234
private static List<LogEntry> logs;
3335

3436
public static void main(String[] args) {
@@ -69,49 +71,72 @@ public static void main(String[] args) {
6971
* @param standalone whether the parser tries to load addons (standalone) or not (library)
7072
*/
7173
public static void init(String[] mainPackages, String[] subPackages, String[] programArgs, boolean standalone) {
74+
init(mainPackages, subPackages, programArgs, standalone, null);
75+
}
76+
77+
/**
78+
* Starts the parser.
79+
* @param mainPackages packages inside which all subpackages containing classes to load may be present. Doesn't need
80+
* to contain Skript's own main packages.
81+
* @param subPackages the subpackages inside which classes to load may be present. Doesn't need to contain Skript's
82+
* own subpackages.
83+
* @param programArgs any other program arguments (typically from the command line)
84+
* @param standalone whether the parser tries to load addons (standalone) or not (library)
85+
* @param parserPath the main path to the parser, will be used to get the addons folder. If null, the path will be inferred from the parser's location.
86+
*/
87+
public static void init(String[] mainPackages, String[] subPackages, String[] programArgs, boolean standalone, @Nullable Path parserPath) {
7288
Skript skript = new Skript(programArgs);
7389
registration = new SkriptRegistration(skript);
7490
DefaultRegistration.register();
75-
// Make sure Skript loads properly no matter what
91+
92+
// Ensure Skript loads first
7693
mainPackages = Arrays.copyOf(mainPackages, mainPackages.length + 1);
7794
mainPackages[mainPackages.length - 1] = "io.github.syst3ms.skriptparser";
95+
96+
// Combine main and sub-packages
7897
List<String> sub = new ArrayList<>();
7998
sub.addAll(Arrays.asList(subPackages));
8099
sub.addAll(Arrays.asList("expressions", "effects", "event", "lang", "sections", "tags"));
81100
subPackages = sub.toArray(new String[0]);
82-
try {
83-
for (String mainPackage : mainPackages) {
84-
FileUtils.loadClasses(FileUtils.getJarFile(Parser.class), mainPackage, subPackages);
101+
List<String> allPackages = new ArrayList<>(List.of(mainPackages));
102+
for (String subPackage : subPackages) {
103+
for (String main : mainPackages) {
104+
allPackages.add(main + "." + subPackage);
85105
}
106+
}
107+
108+
try {
109+
// Load all classes in the specified packages
110+
new Reflections(allPackages.toArray(new String[0]), Scanners.SubTypes.filterResultsBy(s -> true))
111+
.getSubTypesOf(Object.class)
112+
.forEach(clazz -> {
113+
try {
114+
Class.forName(clazz.getName(), true, Parser.class.getClassLoader());
115+
} catch (ClassNotFoundException e) {
116+
e.printStackTrace();
117+
}
118+
});
119+
120+
// Load addons if standalone mode is enabled
86121
if (standalone) {
87-
Path parserPath = Paths.get(Parser.class
88-
.getProtectionDomain()
89-
.getCodeSource()
90-
.getLocation()
91-
.toURI()
92-
);
93-
Path addonFolderPath = Paths.get(parserPath.getParent().toString(), "addons");
122+
if (parserPath == null) {
123+
parserPath = Paths.get(Parser.class.getProtectionDomain().getCodeSource().getLocation().toURI()).getParent();
124+
}
125+
Path addonFolderPath = parserPath.getParent().resolve("addons");
94126
if (Files.isDirectory(addonFolderPath)) {
95127
Files.walk(addonFolderPath)
96128
.filter(Files::isRegularFile)
97-
.filter((filePath) -> filePath.toString().endsWith(".jar"))
98-
.forEach((Path addonPath) -> {
99-
try {
100-
URLClassLoader child = new URLClassLoader(
101-
new URL[]{addonPath.toUri().toURL()},
102-
Parser.class.getClassLoader()
103-
);
104-
JarFile jar = new JarFile(addonPath.toString());
105-
Manifest manifest = jar.getManifest();
106-
String main = manifest.getMainAttributes().getValue("Main-Class");
107-
if (main != null) {
108-
Class<?> mainClass = Class.forName(main, true, child);
129+
.filter(filePath -> filePath.toString().endsWith(".jar"))
130+
.forEach(addonPath -> {
131+
try (JarFile jar = new JarFile(addonPath.toString())) {
132+
URLClassLoader child = new URLClassLoader(new URL[]{addonPath.toUri().toURL()}, Parser.class.getClassLoader());
133+
String mainClassName = jar.getManifest().getMainAttributes().getValue("Main-Class");
134+
if (mainClassName != null) {
109135
try {
136+
Class<?> mainClass = Class.forName(mainClassName, true, child);
110137
Method init = mainClass.getDeclaredMethod("initAddon");
111138
init.invoke(null);
112139
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored) {
113-
} finally {
114-
jar.close();
115140
}
116141
}
117142
} catch (IOException | ClassNotFoundException e) {
@@ -125,6 +150,8 @@ public static void init(String[] mainPackages, String[] subPackages, String[] pr
125150
System.err.println("Error while loading classes:");
126151
e.printStackTrace();
127152
}
153+
154+
// Log registration results
128155
Calendar time = Calendar.getInstance();
129156
logs = registration.register();
130157
if (!logs.isEmpty()) {

src/main/java/io/github/syst3ms/skriptparser/util/FileUtils.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
* Utility functions for file parsing
1818
*/
1919
public class FileUtils {
20+
2021
public static final Pattern LEADING_WHITESPACE_PATTERN = Pattern.compile("(\\s+)\\S.*");
2122
public static final String MULTILINE_SYNTAX_TOKEN = "\\";
2223
private static final String OS_SEPARATOR = FileSystems.getDefault().getSeparator();
@@ -134,7 +135,9 @@ public static String removeExtension(String s) {
134135
* @param rootPackage a root package
135136
* @param subPackages a list of all subpackages of the root package, in which classes will be loaded
136137
* @throws IOException if an I/O error has occurred
138+
* @deprecated use the Reflections library for classpath scanning and loading instead
137139
*/
140+
@Deprecated
138141
public static void loadClasses(File jarFile, String rootPackage, String... subPackages) throws IOException {
139142
if (jarFile.isDirectory())
140143
throw new IllegalArgumentException("The provided file is actually a directory!");
@@ -174,7 +177,9 @@ public static void loadClasses(File jarFile, String rootPackage, String... subPa
174177
* @param rootPackage a root package
175178
* @param subPackages a list of all subpackages of the root package, in which classes will be leadied
176179
* @throws IOException if an I/O error has occurred
180+
* @deprecated use the Reflections library for classpath scanning and loading instead
177181
*/
182+
@Deprecated
178183
public static void loadClasses(Path directory, String rootPackage, String... subPackages) throws IOException {
179184
if (!directory.toFile().isDirectory())
180185
throw new IllegalArgumentException("The provided file isn't a directory!");
@@ -209,8 +214,11 @@ public static void loadClasses(Path directory, String rootPackage, String... sub
209214
*
210215
* @param cla the class
211216
* @return the JAR file containing the class
217+
* @deprecated not all projects that uses skript-parser are JAR files, so this method may not work as expected
212218
*/
219+
@Deprecated
213220
public static File getJarFile(Class<?> cla) throws URISyntaxException {
214221
return new File(cla.getProtectionDomain().getCodeSource().getLocation().toURI());
215222
}
223+
216224
}

0 commit comments

Comments
 (0)