You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@maven.apache.org by Michel Pawlak <mi...@gmail.com> on 2017/01/28 14:51:10 UTC

What's the correct way to use InputLocationTracker?

Hi all,

I need some help with issues I’m facing when using org.apache.maven.model.InputLocationTracker.

Let’s first have a look at this sample class file (I tried to only keep what is relevant to the issue.)

-[snip]—
import java.util.ArrayList;
import java.util.List;
import org.apache.maven.model.Build;
import org.apache.maven.model.InputLocation;
import org.apache.maven.model.InputLocationTracker;
import org.apache.maven.model.Model;
import org.apache.maven.model.Plugin;
import org.codehaus.plexus.util.FileUtils;
import org.codehaus.plexus.util.xml.Xpp3Dom;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Sample check that verifies if Java source version is the ones that is expected.
 */
public class JavaSourceVersionCheck {

    private static final Logger LOGGER = LoggerFactory.getLogger(JavaSourceVersionCheck.class);

    private static final String MAVEN_COMPILER_PLUGIN_GROUPID = "org.apache.maven.plugins";

    private static final String MAVEN_COMPILER_PLUGIN_ARTIFACTID = "maven-compiler-plugin";

    /**
     * Default Java source version.
     */
    public static final String EXPECTED_JAVA_SOURCE_VERSION = "1.7";

    /**
     * Default Java target version.
     */
    public static final String EXPECTED_JAVA_TARGET_VERSION = "1.7";

    /**
     * Executes the check on a Maven Model instance.
     *
     * @param model Maven raw Model (i.e. with unresolved pom inheritance)
     */
    public void execute(final Model model) {
        LOGGER.debug("checking Model");
        final Build build = model.getBuild();
        if (build != null) {
            for (final Plugin plugin : build.getPlugins()) {
                if (isMavenCompilerPlugin(plugin)) {
                    LOGGER.debug("Maven compiler plugin found!");
                    checkJavaSourceVersion(plugin);
                }
            }
        }
        LOGGER.debug("done");
    }

    private boolean isMavenCompilerPlugin(final Plugin plugin) {
        return MAVEN_COMPILER_PLUGIN_GROUPID.equals(plugin.getGroupId()) && MAVEN_COMPILER_PLUGIN_ARTIFACTID.equals(plugin.getArtifactId());
    }

    private void checkJavaSourceVersion(final Plugin plugin) {
        final Xpp3Dom configuration = (Xpp3Dom) plugin.getConfiguration();
        final Xpp3Dom sourceDom = configuration.getChild("source");
        LOGGER.debug("Configuration DOM: {}", configuration.toString());
        if (sourceDom != null) {
            LOGGER.debug("Found <source> tag, checking its value");
            final String sourceValue = sourceDom.getValue();
            if (!sourceValue.equals(EXPECTED_JAVA_SOURCE_VERSION)) {
                final InputLocation location = locate(plugin, “configuration", "source");
                // here I should do something else with the location instance, but as I want to keep the sample as simple as possible, let’s just log a message
                LOGGER.warn(“non compliant value: is {} but should be {} (issue was found at {} column {})", sourceValue, EXPECTED_JAVA_SOURCE_VERSION, location.getLineNumber(),
                    location.getColumnNumber());
            }
        }
    }

    /**
     * Locates the line in the {@link Model} POM where XML tags below an {@link InputLocationTracker} is located.
     *
     * @param locationTracker Maven {@link Model} {@link InputLocationTracker} for which the line has to be retrieved.
     * @param tags list of tags to drill down, the last one representing the tag for which the line has to be retrieved.
     * @return an IssueLocation representing the line and column in the {@link Model} where the last tag of the {@code tags} list below {@link InputLocationTracker} is located.
     */
    public final InputLocation locate(final InputLocationTracker locationTracker, final String... tags) {
        final List<String> tagsList = new ArrayList<>();
        if (tags.length == 0) {
            tagsList.add("");
        } else {
            for (final String tag : tags) {
                tagsList.add(tag);
            }
        }
        final InputLocation inputLocation = locate(locationTracker, tagsList);
        LOGGER.debug("\t<{}> tag located at line {}, column {})", tagsList.get(tagsList.size() - 1), inputLocation.getLineNumber(), inputLocation.getColumnNumber());
        return inputLocation;

    }

    private final InputLocation locate(final InputLocationTracker locationTracker, final List<String> tags) {
        InputLocation inputLocation = null;
        for (final String tag : tags) {
            if (inputLocation == null) {
                inputLocation = locationTracker.getLocation(tag);
            } else {
                // InputLocation is an InputLocationTracker
                final InputLocation tempInputLocation = inputLocation.getLocation(tag); // (1) 
                if (tempInputLocation == null) {
                    LOGGER.error("InputLocation for tag <{}> is null, returning position of last tag that has been found", tag);
                    break;
                } else {
                    inputLocation = tempInputLocation;
                }
            }
        }
        return inputLocation;
    }

    public static void main(final String[] args) throws Exception {
        final Model model = RawMavenModelFactory.instance()
            .buildWith(FileUtils.toFile(JavaSourceVersionCheck.class.getClassLoader()
                .getResource("pom.xml")));
        final JavaSourceVersionCheck check = new JavaSourceVersionCheck();
        check.execute(model);
    }

}
-[snip]—

Here is the code of the buildWith() method:

-[snip]—
    public Model buildWith(final File pomFile) throws MavenModelBuildingException {
        final MavenXpp3ReaderEx reader = new MavenXpp3ReaderEx();
        reader.setAddDefaultEntities(false);
        try {
            return reader.read(new FileInputStream(pomFile), true, new InputSource());
        } catch (IOException | XmlPullParserException e) {
            throw new MavenModelBuildingException("Could not build Maven model.", e);
        }
    }
-[snip]—

The dependencies I’m using here are the following:

-[snip]—
<lib.maven.version>3.3.3</lib.maven.version>
<lib.aether.version>1.0.2.v20150114</lib.aether.version>
-[snip]—

And here is the sample pom.xml file that is used by the main method:

-[snip]—
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>test</groupId>
  <artifactId>test</artifactId>
  <version>1.0.0-SNAPSHOT</version>
  <properties>
    <plugin.maven-compiler-plugin.version>3.3</plugin.maven-compiler-plugin.version>
  </properties>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>${plugin.maven-compiler-plugin.version}</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>
-[snip]—

When run the code, I get the following output:

-[snip]—
15:21:35.822 [main] DEBUG JavaSourceVersionCheck - checking Model
15:21:35.826 [main] DEBUG JavaSourceVersionCheck - Maven compiler plugin found!
15:21:35.830 [main] DEBUG JavaSourceVersionCheck - Configuration DOM: <?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <source>1.8</source>
  <target>1.8</target>
</configuration>
15:21:35.831 [main] DEBUG JavaSourceVersionCheck - Found <source> tag, checking its value
15:21:35.831 [main] ERROR JavaSourceVersionCheck - InputLocation for tag <source> is null, returning position of last tag that has been found
15:21:35.831 [main] DEBUG JavaSourceVersionCheck - 	<source> tag located at line 15, column 24)
15:21:35.831 [main] WARN  JavaSourceVersionCheck - non compliant value: is 1.8 but should be 1.7 (issue was found at 15 column 24)
15:21:35.832 [main] DEBUG JavaSourceVersionCheck - done
-[snip]—

So I have two problems here:

I cannot retrieve the line and column number for the <source> tag, as calling inputLocation.getLocation(tag); is null (see (1) in above source code)
getColumnNumber() returns “line 15 column 24” which is the last column of the line of the pom.xml where <configuration> is located.

My questions are the following:
Is it a bug or am I doing something wrong? (source is reachable from the DOM, but when calling getLocation())
How can I retrieve the line and column of the opening <source> tag?
How can I retrieve the line and column of the closing <source> tag?
Why does getColumnNumber() always return the last column of the line?

Thanks a lot in advance for your help and best regards!

Michel