gnodet-bot commented on code in PR #13490:
URL: https://github.com/apache/maven/pull/13490#discussion_r4284082696
##########
apache-maven/src/assembly/component.xml:
##########
@@ -23,14 +23,16 @@ under the License.
<useProjectArtifact>false</useProjectArtifact>
<outputDirectory>boot</outputDirectory>
<includes>
- <include>org.codehaus.plexus:plexus-classworlds</include>
+ <include>org.apache.maven:maven-classworlds</include>
+ <include>org.apache.maven:maven-api-classworlds</include>
</includes>
</dependencySet>
<dependencySet>
<useProjectArtifact>false</useProjectArtifact>
<outputDirectory>lib</outputDirectory>
<excludes>
- <exclude>org.codehaus.plexus:plexus-classworlds</exclude>
+ <exclude>org.apache.maven:maven-classworlds</exclude>
+ <exclude>org.apache.maven:maven-api-classworlds</exclude>
Review Comment:
⚠️ **Boot launcher glob mismatch — Maven won't start**
`component.xml` places `maven-classworlds-<version>.jar` and
`maven-api-classworlds-<version>.jar` in `boot/`, but `mvn` still uses `echo
"$MAVEN_HOME"/boot/plexus-classworlds-*.jar` (unchanged from master) and
`mvn.cmd` uses `for %%i in ("%MAVEN_HOME%"\boot\plexus-classworlds-*) do set
LAUNCHER_JAR=...`. Neither glob matches any file in the assembled distribution
— Maven cannot start at all.
Both launchers must be updated to match the new artifact names:
`mvn`:
```
LAUNCHER_JAR=`echo "$MAVEN_HOME"/boot/maven-classworlds-*.jar`:`echo
"$MAVEN_HOME"/boot/maven-api-classworlds-*.jar`
```
`mvn.cmd`:
```
for %%i in ("%MAVEN_HOME%"oot\maven-classworlds-*) do set LAUNCHER_JAR="%%i"
for %%i in ("%MAVEN_HOME%"oot\maven-api-classworlds-*) do set
LAUNCHER_JAR=%LAUNCHER_JAR%;"%%i"
```
(And the test scripts `test-mvn-fast-version.sh` and
`test-mvn-path-conversion.sh` need matching stubs.)
##########
impl/maven-cli/src/main/java/org/apache/maven/cling/MavenCling.java:
##########
@@ -64,18 +64,19 @@ public static void main(String[] args) throws IOException {
* This makes {@code MavenCling} the default entry point that external
tools (such as the Maven Wrapper
* or IDEs) can rely on without needing to set the {@code maven.mainClass}
property.
*/
- public static int main(String[] args, ClassWorld world) throws IOException
{
+ public static int main(String[] args,
org.codehaus.plexus.classworlds.ClassWorld world) throws IOException {
String mainClass = System.getProperty(MAVEN_MAIN_CLASS_PROPERTY);
if (mainClass != null &&
!MavenCling.class.getName().equals(mainClass)) {
return delegateMain(mainClass, args, world);
}
return new MavenCling(world).run(args, null, null, null, false);
}
- private static int delegateMain(String mainClass, String[] args,
ClassWorld world) throws IOException {
+ private static int delegateMain(String mainClass, String[] args,
org.codehaus.plexus.classworlds.ClassWorld world)
+ throws IOException {
try {
Class<?> clazz =
Thread.currentThread().getContextClassLoader().loadClass(mainClass);
- Method method = clazz.getMethod("main", String[].class,
ClassWorld.class);
+ Method method = clazz.getMethod("main", String[].class,
org.codehaus.plexus.classworlds.ClassWorld.class);
Review Comment:
⚠️ **`delegateMain()` also reverted — `mvnval` broken here too**
Same issue as `Launcher.getEnhancedMainMethod()`: the single-type lookup
`clazz.getMethod("main", String[].class,
org.codehaus.plexus.classworlds.ClassWorld.class)` throws
`NoSuchMethodException` for `MavenValCling` (its `main` takes
`org.apache.maven.api.classworlds.ClassWorld`). The dual-candidate loop that
was approved in the last review must be restored here as well:
```suggestion
String[] cwClassNames = {
org.codehaus.plexus.classworlds.ClassWorld.class.getName(),
org.apache.maven.api.classworlds.ClassWorld.class.getName()
};
Method method = null;
for (String cwClassName : cwClassNames) {
try {
Class<?> cwClass =
Thread.currentThread().getContextClassLoader().loadClass(cwClassName);
Method m = clazz.getMethod("main", String[].class,
cwClass);
if (Modifier.isStatic(m.getModifiers()) &&
Modifier.isPublic(m.getModifiers())) {
method = m;
break;
}
} catch (NoSuchMethodException ignored) {
// try next candidate
}
}
if (method == null) {
throw new NoSuchMethodException(mainClass + ".main(String[],
ClassWorld)");
}
```
##########
impl/maven-classworlds/src/main/java/org/codehaus/plexus/classworlds/launcher/Launcher.java:
##########
@@ -0,0 +1,365 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.codehaus.plexus.classworlds.launcher;
+
+/*
+ * Copyright 2001-2006 Codehaus Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+import org.codehaus.plexus.classworlds.ClassWorld;
+import org.codehaus.plexus.classworlds.realm.ClassRealm;
+import org.codehaus.plexus.classworlds.realm.DuplicateRealmException;
+import org.codehaus.plexus.classworlds.realm.NoSuchRealmException;
+
+/**
+ * <p>Command-line invokable application launcher.</p>
+ *
+ * <p>This launcher class assists in the creation of classloaders and
<code>ClassRealm</code>s
+ * from a configuration file and the launching of the application's
<code>main</code>
+ * method from the correct class loaded through the correct classloader.</p>
+ *
+ * <p> The path to the configuration file is specified using the
<code>classworlds.conf</code>
+ * system property, typically specified using the <code>-D</code> switch to
+ * <code>java</code>.</p>
+ *
+ * @author <a href="mailto:[email protected]">bob mcwhirter</a>
+ */
+public class Launcher {
+ protected static final String CLASSWORLDS_CONF = "classworlds.conf";
+
+ protected static final String UBERJAR_CONF_DIR = "WORLDS-INF/conf/";
+
+ protected ClassLoader systemClassLoader;
+
+ protected String mainClassName;
+
+ protected String mainRealmName;
+
+ protected ClassWorld world;
+
+ private int exitCode = 0;
+
+ public Launcher() {
+ this.systemClassLoader =
Thread.currentThread().getContextClassLoader();
+ }
+
+ public void setSystemClassLoader(ClassLoader loader) {
+ this.systemClassLoader = loader;
+ }
+
+ public ClassLoader getSystemClassLoader() {
+ return this.systemClassLoader;
+ }
+
+ public int getExitCode() {
+ return exitCode;
+ }
+
+ public void setAppMain(String mainClassName, String mainRealmName) {
+ this.mainClassName = mainClassName;
+ this.mainRealmName = mainRealmName;
+ }
+
+ public String getMainRealmName() {
+ return this.mainRealmName;
+ }
+
+ public String getMainClassName() {
+ return this.mainClassName;
+ }
+
+ public void setWorld(ClassWorld world) {
+ this.world = world;
+ }
+
+ public ClassWorld getWorld() {
+ return this.world;
+ }
+
+ /**
+ * Configure from a file.
+ *
+ * @param is The config input stream.
+ * @throws IOException If an error occurs reading the config
file.
+ * @throws MalformedURLException If the config file contains invalid
URLs.
+ * @throws ConfigurationException If the config file is corrupt.
+ * @throws org.codehaus.plexus.classworlds.realm.DuplicateRealmException
If the config file defines two realms
+ * with the same id.
+ * @throws org.codehaus.plexus.classworlds.realm.NoSuchRealmException
If the config file defines a main entry
+ * point in a non-existent realm.
+ */
+ public void configure(InputStream is)
+ throws IOException, ConfigurationException,
DuplicateRealmException, NoSuchRealmException {
+ Configurator configurator = new Configurator(this);
+ configurator.configure(is);
+ }
+
+ /**
+ * Retrieve the main entry class.
+ *
+ * @return The main entry class.
+ * @throws ClassNotFoundException If the class cannot be found.
+ * @throws NoSuchRealmException If the specified main entry realm does
not exist.
+ */
+ public Class<?> getMainClass() throws ClassNotFoundException,
NoSuchRealmException {
+ return getMainRealm().loadClass(getMainClassName());
+ }
+
+ /**
+ * Retrieve the main entry realm.
+ *
+ * @return The main entry realm.
+ * @throws NoSuchRealmException If the specified main entry realm does not
exist.
+ */
+ public ClassRealm getMainRealm() throws NoSuchRealmException {
+ return getWorld().getRealm(getMainRealmName());
+ }
+
+ /**
+ * Retrieve the enhanced main entry method.
+ *
+ * @return The enhanced main entry method.
+ * @throws ClassNotFoundException If the main entry class cannot be found.
+ * @throws NoSuchMethodException If the main entry method cannot be found.
+ * @throws NoSuchRealmException If the main entry realm cannot be found.
+ */
+ protected Method getEnhancedMainMethod()
+ throws ClassNotFoundException, NoSuchMethodException,
NoSuchRealmException {
+ Class<?> cwClass =
getMainRealm().loadClass(ClassWorld.class.getName());
Review Comment:
⚠️ **`MavenValCling` broken — single-type lookup misses the API
`ClassWorld`**
`getEnhancedMainMethod()` now only loads
`org.codehaus.plexus.classworlds.ClassWorld` (the impl type).
`MavenValCling.main(String[], ClassWorld)` declares
`org.apache.maven.api.classworlds.ClassWorld` as its second parameter —
`getMainClass().getMethod("main", String[].class, cwClass)` will throw
`NoSuchMethodException` whenever the configured main class is `MavenValCling`.
The dual-candidate loop from the previous commit was the correct fix.
Restore it:
```suggestion
// Try both the impl ClassWorld and the stable API ClassWorld
interface.
// Entry points using impl ClassWorld (MavenCling, MavenEncCling,
MavenShellCling, MavenUpCling)
// are found by the first candidate; MavenValCling (which uses the
API type) by the second.
String[] cwClassNames = {ClassWorld.class.getName(),
"org.apache.maven.api.classworlds.ClassWorld"};
for (String cwClassName : cwClassNames) {
try {
Class<?> cwClass = getMainRealm().loadClass(cwClassName);
Method m = getMainClass().getMethod("main", String[].class,
cwClass);
int modifiers = m.getModifiers();
if (Modifier.isStatic(modifiers) &&
Modifier.isPublic(modifiers)) {
if (m.getReturnType() == Integer.TYPE ||
m.getReturnType() == Void.TYPE) {
return m;
}
}
} catch (NoSuchMethodException | ClassNotFoundException ignored)
{
// try next candidate
}
}
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]