Skip to content

Commit eea741b

Browse files
CesarCoelhoclaude
andcommitted
Find the generators without scanning the classpath for them
The plugin used org.reflections to walk every jar on its classpath looking for subtypes of Generator. That cost about 300 ms of every module's build to discover five classes, roughly ten times what generating the code itself takes. Each module that supplies a generator now names it in a service file, in the form the JDK's own service loading uses, and the plugin reads those. The constructor still takes the Log, so the file is read directly rather than through ServiceLoader. org.reflections is no longer a dependency. Measured on api-area002-v001-com, as the goal's cost above a bare clean: 450 ms before, 151 ms after. Over a whole reactor build of apis/*, 3811 ms to 2525 ms. Also restores src/main/resources in the three generator modules. They override <resources> to pick up LICENCE.md, which silently dropped the directory the parent declares, so nothing under src/main/resources had ever been packaged there - which is why the service files did not appear until it was fixed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent b933fd7 commit eea741b

6 files changed

Lines changed: 92 additions & 23 deletions

File tree

api-generator/api-generator-maven-plugin/pom.xml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,6 @@
8080
<groupId>com.sun.xml.bind</groupId>
8181
<artifactId>jaxb-core</artifactId>
8282
</dependency>
83-
<dependency>
84-
<groupId>org.reflections</groupId>
85-
<artifactId>reflections</artifactId>
86-
<version>0.9.10</version>
87-
</dependency>
8883
<dependency>
8984
<groupId>xml-apis</groupId>
9085
<artifactId>xml-apis</artifactId>
@@ -107,6 +102,11 @@
107102

108103
<build>
109104
<resources>
105+
<!-- Restored: the parent declares it, and overriding <resources> here dropped
106+
it, so nothing under src/main/resources was ever packaged. -->
107+
<resource>
108+
<directory>${basedir}/src/main/resources</directory>
109+
</resource>
110110
<resource>
111111
<directory>${basedir}/..</directory>
112112
<includes>

api-generator/api-generator-maven-plugin/src/main/java/esa/mo/tools/stubgen/StubGenerator.java

Lines changed: 69 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,19 @@
2424
import esa.mo.xsd.util.XmlSpecification;
2525
import esa.mo.xsd.util.XsdSpecification;
2626
import java.io.File;
27+
import java.io.BufferedReader;
2728
import java.io.IOException;
29+
import java.io.InputStreamReader;
2830
import java.lang.reflect.Modifier;
31+
import java.net.URL;
2932
import java.util.AbstractMap;
3033
import java.util.ArrayList;
3134
import java.util.HashMap;
3235
import java.util.LinkedList;
3336
import java.util.List;
3437
import java.util.Map;
38+
import java.util.Enumeration;
39+
import java.util.LinkedHashSet;
3540
import java.util.Set;
3641
import javax.xml.bind.JAXBContext;
3742
import javax.xml.bind.JAXBException;
@@ -42,10 +47,6 @@
4247
import org.apache.maven.plugins.annotations.LifecyclePhase;
4348
import org.apache.maven.plugins.annotations.Mojo;
4449
import org.apache.maven.plugins.annotations.Parameter;
45-
import org.reflections.Reflections;
46-
import org.reflections.scanners.SubTypesScanner;
47-
import org.reflections.util.ClasspathHelper;
48-
import org.reflections.util.ConfigurationBuilder;
4950
import w3c.xsd.Schema;
5051

5152
/**
@@ -427,33 +428,83 @@ private static XsdSpecification loadXsdSpecification(final File file) throws IOE
427428
return new XsdSpecification(file, schema);
428429
}
429430

431+
/**
432+
* The resource each module supplying generators declares them in, one class name per
433+
* line, in the form the JDK's own service loading uses.
434+
*/
435+
private static final String SERVICES = "META-INF/services/" + Generator.class.getName();
436+
437+
/**
438+
* Finds the generators on the classpath.
439+
* <p>
440+
* Each module that supplies one names it in a service file, and this reads those files.
441+
* It used to be found by scanning: every jar on the plugin's classpath was walked for
442+
* subtypes of {@link Generator}, which cost around 300 ms of every build to discover
443+
* five classes - close to ten times what generating the code itself takes. A module
444+
* that supplies a generator already knows it does, so it says so.
445+
*/
430446
private void loadGenerators(final org.apache.maven.plugin.logging.Log logger) {
431447
if (generatorsLoaded) {
432448
return;
433449
}
434450

435451
generatorsLoaded = true;
436452

437-
final Reflections reflections = new Reflections(new ConfigurationBuilder()
438-
.setUrls(ClasspathHelper.forClassLoader())
439-
.setScanners(new SubTypesScanner()));
453+
for (String name : declaredGenerators(logger)) {
454+
try {
455+
final Class<?> cls = Class.forName(name, true, loader());
456+
if (Modifier.isAbstract(cls.getModifiers())) {
457+
continue;
458+
}
459+
final Generator g = (Generator) cls.getConstructor(new Class[]{
460+
org.apache.maven.plugin.logging.Log.class
461+
}).newInstance(new Object[]{logger});
440462

441-
final Set<Class<? extends Generator>> classes = reflections.getSubTypesOf(Generator.class);
463+
GENERATOR_MAP.put(g.getShortName().toLowerCase(), g);
464+
} catch (Exception ex) {
465+
logger.warn("Could not construct generator : " + name);
466+
}
467+
}
468+
}
442469

443-
for (Class<? extends Generator> cls : classes) {
444-
final int mods = cls.getModifiers();
445-
if (!Modifier.isAbstract(mods)) {
446-
try {
447-
final Generator g = (Generator) cls.getConstructor(new Class[]{
448-
org.apache.maven.plugin.logging.Log.class
449-
}).newInstance(new Object[]{logger});
470+
/**
471+
* The plugin's own class loader, which is the realm holding both the plugin and
472+
* whatever generators the build supplied to it. The thread's context loader is not it:
473+
* inside a Mojo that is Maven's own, and it can see neither.
474+
*/
475+
private static ClassLoader loader() {
476+
return StubGenerator.class.getClassLoader();
477+
}
450478

451-
GENERATOR_MAP.put(g.getShortName().toLowerCase(), g);
452-
} catch (Exception ex) {
453-
logger.warn("Could not construct generator : " + cls.getName());
479+
/**
480+
* @return the class name of every generator declared on the classpath, in the order the
481+
* class loader offers them.
482+
*/
483+
private static Set<String> declaredGenerators(
484+
final org.apache.maven.plugin.logging.Log logger) {
485+
final Set<String> names = new LinkedHashSet<String>();
486+
try {
487+
final Enumeration<URL> found = loader().getResources(SERVICES);
488+
while (found.hasMoreElements()) {
489+
final BufferedReader in = new BufferedReader(new InputStreamReader(
490+
found.nextElement().openStream(), "UTF-8"));
491+
try {
492+
String line;
493+
while ((line = in.readLine()) != null) {
494+
final int comment = line.indexOf('#');
495+
final String name = (comment < 0 ? line : line.substring(0, comment)).trim();
496+
if (!name.isEmpty()) {
497+
names.add(name);
498+
}
499+
}
500+
} finally {
501+
in.close();
454502
}
455503
}
504+
} catch (IOException ex) {
505+
logger.warn("Could not read the declared generators: " + ex.getMessage());
456506
}
507+
return names;
457508
}
458509

459510
private void processWithGenerator(final Generator generator,

api-generator/generator-docs/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,11 @@
145145

146146
<build>
147147
<resources>
148+
<!-- Restored: the parent declares it, and overriding <resources> here dropped
149+
it, so nothing under src/main/resources was ever packaged. -->
150+
<resource>
151+
<directory>${basedir}/src/main/resources</directory>
152+
</resource>
148153
<resource>
149154
<directory>${basedir}/..</directory>
150155
<includes>
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# The generators this module supplies, found by the plugin without scanning the
2+
# classpath for them. See StubGenerator.loadGenerators.
3+
esa.mo.tools.stubgen.GeneratorDocx
4+
esa.mo.tools.stubgen.GeneratorSvg

api-generator/generator-java/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,11 @@
8989

9090
<build>
9191
<resources>
92+
<!-- Restored: the parent declares it, and overriding <resources> here dropped
93+
it, so nothing under src/main/resources was ever packaged. -->
94+
<resource>
95+
<directory>${basedir}/src/main/resources</directory>
96+
</resource>
9297
<resource>
9398
<directory>${basedir}/..</directory>
9499
<includes>
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# The generators this module supplies, found by the plugin without scanning the
2+
# classpath for them. See StubGenerator.loadGenerators.
3+
esa.mo.tools.stubgen.GeneratorJava
4+
esa.mo.tools.stubgen.GeneratorGwt

0 commit comments

Comments
 (0)