Reputation: 15316
I want to compile the ANTLR4 Java distribution using Maven. But it won't work.
I am probably going about this problem wrongly. There may be something very simple I am missing. Probably the way I'm calling Maven in the first place. The fact that absolutely no-one on the Internet seems to have this problem indicates as much.
First, my Java version:
$ java -version
openjdk version "17.0.3" 2022-04-19
OpenJDK Runtime Environment Temurin-17.0.3+7 (build 17.0.3+7)
OpenJDK 64-Bit Server VM Temurin-17.0.3+7 (build 17.0.3+7, mixed mode, sharing)
(But note that ANLTR4 is compiled to Java 11, except for the plugin which is compiled to Java 8, according to the POM)
So. Get the distribution from github:
$ git clone https://github.com/antlr/antlr4.git antlr4_30`
$ cd antlr4_30
$ git status
On branch master
Your branch is up to date with 'origin/master'.
Compile the projects (Maven modules)
runtime/Java
(the ANTLR4 core classes)tool
(the ANTLR4 compiler)antlr4-maven-plugin
(the maven plugin that runs ANTLR4 tasks)PROJECTS="runtime/Java,tool,antlr4-maven-plugin"
mvn --projects "$PROJECTS" clean
mvn --projects "$PROJECTS" verify
Compilation works, then the tests for the maven plugin kick off.
These tests are run using another maven plugin by "Takari" for plugin unit testing: Plugin Unit Testing.
The ANTLR4 Maven plugin tests fail:
java.lang.NullPointerException: Cannot invoke
"org.apache.maven.model.Plugin.getGroupId()"
because the return value of
"org.apache.maven.plugin.MojoExecution.getPlugin()"
is null
with the interesting part of the stack trace:
org.apache.maven.lifecycle.internal.
DefaultMojoExecutionConfigurator.configure(DefaultMojoExecutionConfigurator.java:44)
(called by) io.takari.maven.testing.
Maven331Runtime.lookupConfiguredMojo(Maven331Runtime.java:37)
(called by) io.takari.maven.testing.
Maven325Runtime.executeMojo(Maven325Runtime.java:34)
(called by) io.takari.maven.testing.
TestMavenRuntime.executeMojo(TestMavenRuntime.java:269)
(called by) org.antlr.mojo.antlr4.
Antlr4MojoTest.processWhenDependencyRemoved(Antlr4MojoTest.java:326)
After a lengthy trawl through the source code (code which is not straightforward to read but unfortunately lacks comments, logging or assertions, these would be useful), we find:
In class org.antlr.mojo.antlr4.Antlr4MojoTest
(file antlr4-maven-plugin/src/test/java/org/antlr/mojo/antlr4/Antlr4MojoTest.java
), the failing test cases perform the following (example of test case processWhenDependencyRemoved()
, slightly modified & commented):
// Junit4 rule
@Rule
public final TestMavenRuntime maven = new TestMavenRuntime();
@Test
public void processWhenDependencyRemoved() throws Exception {
Path baseDir = resources.getBasedir("dependencyRemoved").toPath();
Path antlrDir = baseDir.resolve("src/main/antlr4");
Path baseGrammar = antlrDir.resolve("imports/HelloBase.g4");
MavenProject project = maven.readMavenProject(baseDir.toFile());
MavenSession session = maven.newMavenSession(project);
String goal = "antlr4";
// Get a "org.apache.maven.plugin.MojoExecution" from the
// "io.takari.maven.testing.TestMavenRuntime" instance.
assertTrue(maven instanceof io.takari.maven.testing.TestMavenRuntime);
MojoExecution exec = maven.newMojoExecution(goal);
maven.executeMojo(session, project, exec);
...
Now, org.apache.maven.plugin.MojoExecution
(the exec
instance) provides a .getPlugin()
method which returns null
instead of a valid instance of org.apache.maven.model.Plugin
(a class generated by Modello
when Maven itself is compiled).
After two stack frames, org.apache.maven.lifecycle.internal.DefaultMojoExecutionConfigurator.configure()
is called, but then fails immediately in a chained call:
public void configure( MavenProject project, MojoExecution mojoExecution, boolean allowPluginLevelConfig )
{
String g = mojoExecution.getPlugin().getGroupId();
String a = mojoExecution.getPlugin().getArtifactId();
Plugin plugin = findPlugin( g, a, project.getBuildPlugins() );
...
Why does getPlugin()
return null
? From maven's org.apache.maven.plugin.MojoExecution
, file core/maven-3/maven-core/src/main/java/org/apache/maven/plugin/MojoExecution.java
:
public Plugin getPlugin()
{
if ( mojoDescriptor != null )
{
return mojoDescriptor.getPluginDescriptor().getPlugin();
}
return plugin;
}
I our case, mojoDescriptor
is not null, but mojoDescriptor.getPluginDescriptor().getPlugin()
is, which is bad.
I have no idea why the Plugin
instance is not set, or even where it is supposed to be set.
At some point, Maven's org.apache.maven.plugin.descriptor.PluginDescriptorBuilder
is called from Takari's io.takari.maven.testing.Maven30xRuntime
(source) to build org.apache.maven.plugin.descriptor.PluginDescriptor
from the plugin.xml
resource and that works nicely but the plugin
member is not set at that time. The data structures are not straightforward. Below, for what it's worth, the relationship between a few of the classes.
Upvotes: 2
Views: 476
Reputation: 6785
It looks like the "correct" way to build ANTLR4 from the repo is:
$ export MAVEN_OPTS="-Xmx1G" # don't forget this on linux
cd /tmp/antlr4 # or wherever you have the software
rm -rf ~/.m2/repository/org/antlr*
mvn clean
mvn -DskipTests install
see here for explanation.
This worked for me.
Upvotes: 2