diff --git a/pom.xml b/pom.xml index 93920c2751..d4d6036034 100644 --- a/pom.xml +++ b/pom.xml @@ -123,6 +123,8 @@ 1.12.0 1.11.1 4.11.0 + 7.1.0 + 4.2.2 ${project.version} @@ -186,6 +188,16 @@ maven-compat ${mavenVersion} + + com.fasterxml.woodstox + woodstox-core + ${woodstoxVersion} + + + org.codehaus.woodstox + stax2-api + ${stax2ApiVersion} + org.apache.maven.resolver @@ -274,11 +286,6 @@ plexus-interactivity-api 1.3 - - com.fasterxml.woodstox - woodstox-core - 7.1.0 - org.apache.commons commons-lang3 diff --git a/versions-common/src/main/java/org/codehaus/mojo/versions/api/PomHelper.java b/versions-common/src/main/java/org/codehaus/mojo/versions/api/PomHelper.java index 723fbd2655..052dfe05e2 100644 --- a/versions-common/src/main/java/org/codehaus/mojo/versions/api/PomHelper.java +++ b/versions-common/src/main/java/org/codehaus/mojo/versions/api/PomHelper.java @@ -19,17 +19,20 @@ * under the License. */ -import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamException; -import javax.xml.stream.events.XMLEvent; +import javax.xml.stream.XMLStreamReader; +import javax.xml.transform.TransformerException; +import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.io.StringReader; import java.io.UncheckedIOException; +import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; @@ -53,6 +56,7 @@ import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.Pair; import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException; import org.apache.maven.artifact.versioning.VersionRange; import org.apache.maven.execution.MavenSession; @@ -71,18 +75,20 @@ import org.apache.maven.project.ProjectBuildingException; import org.apache.maven.project.ProjectBuildingRequest; import org.apache.maven.project.ProjectBuildingResult; -import org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader; +import org.apache.maven.shared.utils.io.IOUtil; +import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader; import org.codehaus.mojo.versions.utils.ModelNode; import org.codehaus.mojo.versions.utils.RegexUtils; import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException; import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator; -import org.codehaus.plexus.util.IOUtil; -import org.codehaus.plexus.util.xml.XmlStreamReader; import org.codehaus.plexus.util.xml.pull.XmlPullParserException; import org.codehaus.stax2.XMLInputFactory2; import static java.util.Collections.singletonMap; -import static java.util.stream.IntStream.range; +import static java.util.Optional.ofNullable; +import static org.codehaus.mojo.versions.api.PomHelper.Marks.CHILD_START; +import static org.codehaus.mojo.versions.api.PomHelper.Marks.END_ELEMENT; +import static org.codehaus.mojo.versions.api.PomHelper.Marks.PARENT_START; /** * Helper class for modifying pom files. @@ -153,15 +159,15 @@ public static Model getRawModel(File moduleProjectFile) throws IOException { /** * Gets the current raw model before any interpolation what-so-ever. * - * @param modifiedPomXMLEventReader The {@link ModifiedPomXMLEventReader} to getModel the raw model for. + * @param modelString a string containing the raw model + * @param modelPath the File containing the model * @return The raw model. * @throws IOException if the file is not found or if the file does not parse. */ - public static Model getRawModel(ModifiedPomXMLEventReader modifiedPomXMLEventReader) throws IOException { - try (Reader reader = - new StringReader(modifiedPomXMLEventReader.asStringBuilder().toString())) { + public static Model getRawModel(String modelString, File modelPath) throws IOException { + try (Reader reader = new StringReader(modelString)) { Model result = getRawModel(reader); - result.setPomFile(new File(modifiedPomXMLEventReader.getPath())); + result.setPomFile(modelPath); return result; } } @@ -192,7 +198,7 @@ public static Model getRawModel(Reader reader) throws IOException { * @throws XMLStreamException if somethinh went wrong. */ public static boolean setPropertyVersion( - final ModifiedPomXMLEventReader pom, final String profileId, final String property, final String value) + final MutableXMLStreamReader pom, final String profileId, final String property, final String value) throws XMLStreamException { Stack stack = new Stack<>(); String path = ""; @@ -212,12 +218,11 @@ public static boolean setPropertyVersion( } pom.rewind(); - while (pom.hasNext()) { - XMLEvent event = pom.nextEvent(); - if (event.isStartElement()) { + pom.next(); + if (pom.isStartElement()) { stack.push(path); - path = path + "/" + event.asStartElement().getName().getLocalPart(); + path = path + "/" + pom.getLocalName(); if (propertyRegex.matcher(path).matches()) { pom.mark(0); @@ -229,12 +234,12 @@ public static boolean setPropertyVersion( pom.clearMark(1); } else if (profileId != null && projectProfileId.matcher(path).matches()) { String candidateId = pom.getElementText(); - path = stack.pop(); // since getElementText will be after the end element inMatchScope = profileId.trim().equals(candidateId.trim()); } } - if (event.isEndElement()) { + // for empty elements, pom can be both start- and end element + if (pom.isEndElement()) { if (propertyRegex.matcher(path).matches()) { pom.mark(1); } else if (matchScopeRegex.matcher(path).matches()) { @@ -260,7 +265,7 @@ public static boolean setPropertyVersion( * @return true if a replacement was made. * @throws XMLStreamException if somethinh went wrong. */ - public static boolean setProjectVersion(final ModifiedPomXMLEventReader pom, final String value) + public static boolean setProjectVersion(final MutableXMLStreamReader pom, final String value) throws XMLStreamException { return setElementValue(pom, "/project", "version", value, false); } @@ -270,46 +275,47 @@ public static boolean setProjectVersion(final ModifiedPomXMLEventReader pom, fin * Will only consider the first found occurrence of the parent element. * If the element is not found in the parent element, the method will create the element. * - * @param pom pom to modify - * @param parentPath path of the parent element - * @param elementName name of the element to set or create - * @param value the new value of the element - * @return {@code true} if the element was created or replaced + * @param pom pom to modify + * @param parentPath path of the parent element + * @param elementName name of the element to set or create + * @param value the new value of the element + * @return {@code true} if the element was created or replaced * @throws XMLStreamException if something went wrong */ public static boolean setElementValue( - ModifiedPomXMLEventReader pom, String parentPath, String elementName, String value) - throws XMLStreamException { + MutableXMLStreamReader pom, String parentPath, String elementName, String value) throws XMLStreamException { pom.rewind(); return setElementValue(pom, parentPath, elementName, value, true); } + enum Marks { + CHILD_START, + PARENT_START, + END_ELEMENT + } + /** * Sets the value of the given element given its parent element path. * Will only consider the first found occurrence of the parent element. * If the element is not found in the parent element, the method will create the element * if {@code shouldCreate} is {@code true}. * - * @param pom pom to modify - * @param parentPath path of the parent element - * @param elementName name of the element to set or create - * @param value the new value of the element - * @param shouldCreate should the element be created if it's not found in the first encountered parent element - * matching the parentPath - * @return {@code true} if the element was created or replaced + * @param pom pom to modify + * @param parentPath path of the parent element + * @param elementName name of the element to set or create + * @param value the new value of the element + * @param shouldCreate should the element be created if it's not found in the first encountered parent element + * matching the parentPath + * @return {@code true} if the element was created or replaced * @throws XMLStreamException if something went wrong */ public static boolean setElementValue( - ModifiedPomXMLEventReader pom, String parentPath, String elementName, String value, boolean shouldCreate) + MutableXMLStreamReader pom, String parentPath, String elementName, String value, boolean shouldCreate) throws XMLStreamException { class ElementValueInternal { private final String parentName; private final String superParentPath; - private static final int MARK_CHILD_BEGIN = 0; - private static final int MARK_OPTION = 1; - private static final int PARENT_BEGIN = 2; - ElementValueInternal() { int lastDelimeterIndex = parentPath.lastIndexOf('/'); parentName = parentPath.substring(lastDelimeterIndex + 1); @@ -319,20 +325,18 @@ class ElementValueInternal { boolean process(String currentPath) throws XMLStreamException { boolean replacementMade = false; while (!replacementMade && pom.hasNext()) { - XMLEvent event = pom.nextEvent(); - if (event.isStartElement()) { - String currentElementName = - event.asStartElement().getName().getLocalPart(); - + pom.next(); + if (pom.isStartElement()) { // here, we will only mark the beginning of the child or the parent element - if (currentPath.equals(parentPath) && elementName.equals(currentElementName)) { - pom.mark(MARK_CHILD_BEGIN); - } else if (currentPath.equals(superParentPath) && currentElementName.equals(parentName)) { - pom.mark(PARENT_BEGIN); + if (currentPath.equals(parentPath) && elementName.equals(pom.getLocalName())) { + pom.mark(CHILD_START); + } else if (currentPath.equals(superParentPath) + && pom.getLocalName().equals(parentName)) { + pom.mark(PARENT_START); } // process child element - replacementMade = process(currentPath + "/" + currentElementName); - } else if (event.isEndElement()) { + replacementMade = process(currentPath + "/" + pom.getLocalName()); + } else if (pom.isEndElement()) { // here we're doing the replacement if (currentPath.equals(parentPath + "/" + elementName)) { // end of the child @@ -351,18 +355,18 @@ boolean process(String currentPath) throws XMLStreamException { } private void replaceValueInChild() { - pom.mark(MARK_OPTION); - if (pom.getBetween(MARK_CHILD_BEGIN, MARK_OPTION).length() > 0) { - pom.replaceBetween(0, 1, value); + pom.mark(END_ELEMENT); + if (!pom.getBetween(CHILD_START, END_ELEMENT).isEmpty()) { + pom.replaceBetween(CHILD_START, END_ELEMENT, value); } else { pom.replace(String.format("<%1$s>%2$s", elementName, value)); } } private void replaceValueInParent() { - pom.mark(MARK_OPTION); - if (pom.hasMark(PARENT_BEGIN)) { - if (pom.getBetween(PARENT_BEGIN, MARK_OPTION).length() > 0) { + pom.mark(END_ELEMENT); + if (pom.hasMark(PARENT_START)) { + if (!pom.getBetween(PARENT_START, END_ELEMENT).isEmpty()) { pom.replace(String.format("<%2$s>%3$s", parentName, elementName, value)); } else { pom.replace(String.format("<%1$s><%2$s>%3$s", parentName, elementName, value)); @@ -373,12 +377,8 @@ private void replaceValueInParent() { } } - try { - pom.rewind(); - return new ElementValueInternal().process(""); - } finally { - range(0, 3).forEach(pom::clearMark); - } + pom.rewind(); + return new ElementValueInternal().process(""); } /** @@ -389,23 +389,23 @@ private void replaceValueInParent() { * parent version). * @throws XMLStreamException if something went wrong. */ - public static String getProjectVersion(final ModifiedPomXMLEventReader pom) throws XMLStreamException { + public static String getProjectVersion(final MutableXMLStreamReader pom) throws XMLStreamException { Stack stack = new Stack<>(); String path = ""; pom.rewind(); - while (pom.hasNext()) { - XMLEvent event = pom.nextEvent(); - if (event.isStartElement()) { + pom.next(); + if (pom.isStartElement()) { stack.push(path); - path = path + "/" + event.asStartElement().getName().getLocalPart(); + path = path + "/" + pom.getLocalName(); if (PATTERN_PROJECT_VERSION.matcher(path).matches()) { pom.mark(0); } } - if (event.isEndElement()) { + // for empty elements, pom can be both start- and end element + if (pom.isEndElement()) { if (PATTERN_PROJECT_VERSION.matcher(path).matches()) { pom.mark(1); if (pom.hasMark(0) && pom.hasMark(1)) { @@ -428,25 +428,25 @@ public static String getProjectVersion(final ModifiedPomXMLEventReader pom) thro * @return true if a replacement was made. * @throws XMLStreamException if somethinh went wrong. */ - public static boolean setProjectParentVersion(final ModifiedPomXMLEventReader pom, final String value) + public static boolean setProjectParentVersion(final MutableXMLStreamReader pom, final String value) throws XMLStreamException { Stack stack = new Stack<>(); String path = ""; boolean madeReplacement = false; pom.rewind(); - while (pom.hasNext()) { - XMLEvent event = pom.nextEvent(); - if (event.isStartElement()) { + pom.next(); + if (pom.isStartElement()) { stack.push(path); - path = path + "/" + event.asStartElement().getName().getLocalPart(); + path = path + "/" + pom.getLocalName(); if (PATTERN_PROJECT_PARENT_VERSION.matcher(path).matches()) { pom.mark(0); } } - if (event.isEndElement()) { + // for empty elements, pom can be both start- and end element + if (pom.isEndElement()) { if (PATTERN_PROJECT_PARENT_VERSION.matcher(path).matches()) { pom.mark(1); if (pom.hasMark(0) && pom.hasMark(1)) { @@ -477,7 +477,7 @@ public static boolean setProjectParentVersion(final ModifiedPomXMLEventReader po */ @SuppressWarnings("checkstyle:MethodLength") public static boolean setDependencyVersion( - final ModifiedPomXMLEventReader pom, + final MutableXMLStreamReader pom, final String groupId, final String artifactId, final String oldVersion, @@ -499,29 +499,23 @@ public static boolean setDependencyVersion( } pom.rewind(); - while (pom.hasNext()) { - while (pom.hasNext()) { - XMLEvent event = pom.nextEvent(); - if (event.isStartElement()) { - stack.push(path); - final String elementName = event.asStartElement().getName().getLocalPart(); - path = path + "/" + elementName; - - if (implicitPaths.contains(path)) { - final String elementText = pom.getElementText().trim(); - implicitProperties.put(path.substring(1).replace('/', '.'), elementText); - path = stack.pop(); - } - } - if (event.isEndElement()) { - path = stack.pop(); + pom.next(); + if (pom.isStartElement()) { + stack.push(path); + path = path + "/" + pom.getLocalName(); + + if (implicitPaths.contains(path)) { + final String elementText = pom.getElementText().trim(); + implicitProperties.put(path.substring(1).replace('/', '.'), elementText); } } + if (pom.isEndElement()) { + path = stack.pop(); + } } - boolean modified = true; - while (modified) { + for (boolean modified = true; modified; ) { modified = false; for (Map.Entry entry : implicitProperties.entrySet()) { if (entry.getKey().contains(".parent")) { @@ -544,13 +538,11 @@ public static boolean setDependencyVersion( boolean haveOldVersion = false; pom.rewind(); - while (pom.hasNext()) { - XMLEvent event = pom.nextEvent(); - if (event.isStartElement()) { + pom.next(); + if (pom.isStartElement()) { stack.push(path); - final String elementName = event.asStartElement().getName().getLocalPart(); - path = path + "/" + elementName; + path = path + "/" + pom.getLocalName(); if (PATTERN_PROJECT_DEPENDENCY.matcher(path).matches()) { // we're in a new match scope @@ -564,22 +556,21 @@ public static boolean setDependencyVersion( haveOldVersion = false; } else if (inMatchScope && PATTERN_PROJECT_DEPENDENCY_VERSION.matcher(path).matches()) { - if ("groupId".equals(elementName)) { + if ("groupId".equals(pom.getLocalName())) { haveGroupId = groupId.equals(evaluate(pom.getElementText().trim(), implicitProperties, logger)); - path = stack.pop(); - } else if ("artifactId".equals(elementName)) { + } else if ("artifactId".equals(pom.getLocalName())) { haveArtifactId = artifactId.equals(evaluate(pom.getElementText().trim(), implicitProperties, logger)); - path = stack.pop(); - } else if ("version".equals(elementName)) { + } else if ("version".equals(pom.getLocalName())) { pom.mark(0); } } } - if (event.isEndElement()) { + // for empty elements, pom can be both start- and end element + if (pom.isEndElement()) { if (PATTERN_PROJECT_DEPENDENCY_VERSION.matcher(path).matches() - && "version".equals(event.asEndElement().getName().getLocalPart())) { + && "version".equals(pom.getLocalName())) { pom.mark(1); String compressedPomVersion = StringUtils.deleteWhitespace(pom.getBetween(0, 1).trim()); @@ -619,7 +610,7 @@ public static boolean setDependencyVersion( * * @param expr The expression to evaluate. * @param properties The properties to substitute. - * @param logger The logger to use. + * @param logger The logger to use. * @return The evaluated expression. */ public static String evaluate(String expr, Map properties, Log logger) { @@ -684,7 +675,7 @@ public static String evaluate(String expr, Map properties, Log l * otherwise */ public static Optional extractExpression(String expr) { - return Optional.ofNullable(expr) + return ofNullable(expr) .map(String::trim) .filter(e -> e.startsWith("${") && e.indexOf("}") == e.length() - 1) .map(e -> e.substring(2, e.length() - 1)); @@ -734,7 +725,7 @@ private static VersionRange createVersionRange(String versionOrRange) throws Inv * @throws XMLStreamException if somethinh went wrong. */ public static boolean setPluginVersion( - final ModifiedPomXMLEventReader pom, + final MutableXMLStreamReader pom, final String groupId, final String artifactId, final String oldVersion, @@ -750,12 +741,11 @@ public static boolean setPluginVersion( boolean haveOldVersion = false; pom.rewind(); - while (pom.hasNext()) { - XMLEvent event = pom.nextEvent(); - if (event.isStartElement()) { + pom.next(); + if (pom.isStartElement()) { stack.push(path); - final String elementName = event.asStartElement().getName().getLocalPart(); + final String elementName = pom.getLocalName(); path = path + "/" + elementName; if (PATTERN_PROJECT_PLUGIN.matcher(path).matches()) { @@ -772,18 +762,16 @@ public static boolean setPluginVersion( && PATTERN_PROJECT_PLUGIN_VERSION.matcher(path).matches()) { if ("groupId".equals(elementName)) { haveGroupId = pom.getElementText().trim().equals(groupId); - path = stack.pop(); } else if ("artifactId".equals(elementName)) { haveArtifactId = artifactId.equals(pom.getElementText().trim()); - path = stack.pop(); } else if ("version".equals(elementName)) { pom.mark(0); } } } - if (event.isEndElement()) { - if (PATTERN_PROJECT_PLUGIN_VERSION.matcher(path).matches() - && "version".equals(event.asEndElement().getName().getLocalPart())) { + // for empty elements, pom can be both start- and end element + if (pom.isEndElement()) { + if (PATTERN_PROJECT_PLUGIN_VERSION.matcher(path).matches() && "version".equals(pom.getLocalName())) { pom.mark(1); try { @@ -842,8 +830,8 @@ private static Map getRawModelWithParents(MavenProject proj /** * Examines the project to find any properties which are associated with versions of artifacts in the project. * - * @param helper Our versions helper. - * @param project The project to examine. + * @param helper Our versions helper. + * @param project The project to examine. * @param includeParent whether parent POMs should be included * @return An array of properties that are associated within the project. * @throws ExpressionEvaluationException if an expression cannot be evaluated. @@ -1020,14 +1008,14 @@ private static void addPluginAssociations( final String propertyRef = "${" + property.getName() + "}"; if (version.contains(propertyRef)) { String groupId = plugin.getGroupId(); - if (groupId == null || groupId.trim().length() == 0) { - // group Id has a special default + if (StringUtils.isBlank(groupId)) { + // groupId has a special default groupId = APACHE_MAVEN_PLUGINS_GROUPID; } else { groupId = (String) expressionEvaluator.evaluate(groupId); } String artifactId = plugin.getArtifactId(); - if (artifactId == null || artifactId.trim().length() == 0) { + if (StringUtils.isBlank(artifactId)) { // malformed pom continue; } else { @@ -1065,14 +1053,14 @@ private static void addReportPluginAssociations( if (version.contains(propertyRef)) { // any of these could be defined by a property String groupId = plugin.getGroupId(); - if (groupId == null || groupId.trim().length() == 0) { - // group Id has a special default + if (StringUtils.isBlank(groupId)) { + // groupId has a special default groupId = APACHE_MAVEN_PLUGINS_GROUPID; } else { groupId = (String) expressionEvaluator.evaluate(groupId); } String artifactId = plugin.getArtifactId(); - if (artifactId == null || artifactId.trim().length() == 0) { + if (StringUtils.isBlank(artifactId)) { // malformed pom continue; } else { @@ -1110,14 +1098,14 @@ private static void addDependencyAssocations( if (version.contains(propertyRef)) { // Any of these could be defined by a property String groupId = dependency.getGroupId(); - if (groupId == null || groupId.trim().length() == 0) { + if (StringUtils.isBlank(groupId)) { // malformed pom continue; } else { groupId = (String) expressionEvaluator.evaluate(groupId); } String artifactId = dependency.getArtifactId(); - if (artifactId == null || artifactId.trim().length() == 0) { + if (StringUtils.isBlank(artifactId)) { // malformed pom continue; } else { @@ -1285,9 +1273,9 @@ public static String getGroupId(Model model) { /** * Finds the local root of the current project of the {@link MavenSession} instance. * - * @param projectBuilder {@link ProjectBuilder} instance - * @param mavenSession {@link MavenSession} instance - * @param logger The logger to log tog + * @param projectBuilder {@link ProjectBuilder} instance + * @param mavenSession {@link MavenSession} instance + * @param logger The logger to log tog * @return The local root (note this may be the project passed as an argument). */ public static MavenProject getLocalRoot(ProjectBuilder projectBuilder, MavenSession mavenSession, Log logger) { @@ -1328,6 +1316,7 @@ public static MavenProject getLocalRoot(ProjectBuilder projectBuilder, MavenSess *

Convenience method for creating a {@link ProjectBuildingRequest} instance based on maven session.

*

Note: The method initializes the remote repositories with the remote artifact repositories. * Please use the initializers if you need to override this.

+ * * @param mavenSession {@link MavenSession} instance * @param initializers optional additional initializers, which will be executed after the object is initialized * @return constructed builder request @@ -1357,18 +1346,10 @@ public static ProjectBuildingRequest createProjectBuilderRequest( * ordered depth-first visiting order. The root node is always the first node of the list. * * @param rootNode The root node of the reactor - * @param logger logger to log parsing errors to + * @param logger logger to log parsing errors to * @return the root node of the {@link ModelNode} of raw models relative to the project's basedir. - * @throws UncheckedIOException thrown if reading one of the models down the tree fails */ public static List getRawModelTree(ModelNode rootNode, Log logger) throws UncheckedIOException { - XMLInputFactory inputFactory = XMLInputFactory2.newInstance(); - inputFactory.setProperty(XMLInputFactory2.P_PRESERVE_LOCATION, Boolean.TRUE); - return getRawModelTree(rootNode, logger, inputFactory); - } - - private static List getRawModelTree(ModelNode rootNode, Log logger, XMLInputFactory inputFactory) - throws UncheckedIOException { Path baseDir = rootNode.getModel().getPomFile().getParentFile().toPath(); List result = new ArrayList<>(); result.add(rootNode); @@ -1377,16 +1358,15 @@ private static List getRawModelTree(ModelNode rootNode, Log logger, X .map(path -> Files.isDirectory(path) ? path.resolve("pom.xml") : path) .map(pomFile -> { try { - ModifiedPomXMLEventReader pom = new ModifiedPomXMLEventReader( - readXmlFile(pomFile.toFile()), inputFactory, pomFile.toString()); - return new ModelNode(rootNode, getRawModel(pom), pom); + MutableXMLStreamReader pom = new MutableXMLStreamReader(pomFile); + return new ModelNode(rootNode, getRawModel(pom.getSource(), pomFile.toFile()), pom); } catch (IOException e) { throw new UncheckedIOException("Could not open " + pomFile, e); - } catch (XMLStreamException e) { + } catch (XMLStreamException | TransformerException e) { throw new RuntimeException("Could not parse " + pomFile, e); } }) - .flatMap(node -> getRawModelTree(node, logger, inputFactory).stream()) + .flatMap(node -> getRawModelTree(node, logger).stream()) .collect(Collectors.toList())); return result; } @@ -1395,12 +1375,12 @@ private static List getRawModelTree(ModelNode rootNode, Log logger, X * Traverses the module tree upwards searching for the closest definition of a property with the given name. * * @param propertyName name of the property to be found - * @param node model tree node at which the search should be started + * @param node model tree node at which the search should be started * @return {@link Optional} object containing the model tree node containing the closest * property definition, or {@link Optional#empty()} if none has been found */ public static Optional findProperty(String propertyName, ModelNode node) { - if (Optional.ofNullable(node.getModel().getProperties()) + if (ofNullable(node.getModel().getProperties()) .map(properties -> properties.getProperty(propertyName)) .isPresent()) { return Optional.of(node); @@ -1427,8 +1407,8 @@ public static Map getChildModels(MavenProject project, Log logger) /** * Builds a sub-map of raw models keyed by module path. * - * @param model The root model - * @param logger The logger for logging. + * @param model The root model + * @param logger The logger for logging. * @return A map of raw models keyed by path relative to the project's basedir. */ private static Map getChildModels(Model model, Log logger) { @@ -1531,15 +1511,43 @@ public static int getReactorParentCount(Map reactor, Model model) { } /** - * Reads a file into a String. + * Reads an XML from the given InputStream. + * + * @param inputStream The input stream to read. + * @return Pair<String, Charset> The (mutable) content of the file with the charset of the file + * @throws java.io.IOException when things go wrong. + */ + public static Pair readXml(InputStream inputStream) throws IOException, XMLStreamException { + try (BufferedInputStream buffer = new BufferedInputStream(inputStream)) { + // XMLStreamReader is only used to discover the encoding + // NB. We can't use a Transformer because XMLStreamReader will override + // the preamble with its own detected encoding, which is not always what the original file has + + buffer.mark(0x4000); + XMLInputFactory2 factory = (XMLInputFactory2) XMLInputFactory2.newInstance(); + factory.configureForLowMemUsage(); + XMLStreamReader xmlStreamReader = factory.createXMLStreamReader(buffer); + xmlStreamReader.close(); + Charset encoding = ofNullable(xmlStreamReader.getEncoding()) + .map(Charset::forName) + .orElse(Charset.defaultCharset()); + + buffer.reset(); + return Pair.of(IOUtil.toString(buffer, encoding.toString()), encoding); + } + } + + /** + * Reads an XML from a file. * - * @param outFile The file to read. - * @return String The content of the file. + * @param file The file to read. + * @return Pair<String, Charset> The contents of the file with the charset of the file * @throws java.io.IOException when things go wrong. */ - public static StringBuilder readXmlFile(File outFile) throws IOException { - try (Reader reader = new XmlStreamReader(outFile)) { - return new StringBuilder(IOUtil.toString(reader)); + public static Pair readXml(File file) + throws IOException, XMLStreamException, TransformerException { + try (InputStream is = Files.newInputStream(file.toPath())) { + return readXml(is); } } diff --git a/versions-common/src/main/java/org/codehaus/mojo/versions/api/PropertyVersionsBuilder.java b/versions-common/src/main/java/org/codehaus/mojo/versions/api/PropertyVersionsBuilder.java index ab00675e05..d591128ca2 100644 --- a/versions-common/src/main/java/org/codehaus/mojo/versions/api/PropertyVersionsBuilder.java +++ b/versions-common/src/main/java/org/codehaus/mojo/versions/api/PropertyVersionsBuilder.java @@ -36,7 +36,7 @@ * @author Stephen Connolly * @since 1.0-beta-1 */ -class PropertyVersionsBuilder { +public class PropertyVersionsBuilder { private final String name; private final String profileId; diff --git a/versions-common/src/main/java/org/codehaus/mojo/versions/change/AbstractVersionChanger.java b/versions-common/src/main/java/org/codehaus/mojo/versions/change/AbstractVersionChanger.java index 1a357e39d8..30b995e051 100644 --- a/versions-common/src/main/java/org/codehaus/mojo/versions/change/AbstractVersionChanger.java +++ b/versions-common/src/main/java/org/codehaus/mojo/versions/change/AbstractVersionChanger.java @@ -21,7 +21,7 @@ import org.apache.maven.model.Model; import org.apache.maven.plugin.logging.Log; -import org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader; +import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader; /** * Created by IntelliJ IDEA. @@ -32,11 +32,11 @@ public abstract class AbstractVersionChanger implements VersionChanger { private final Model model; - private final ModifiedPomXMLEventReader pom; + private final MutableXMLStreamReader pom; protected final Log log; - public AbstractVersionChanger(Model model, ModifiedPomXMLEventReader pom, Log log) { + public AbstractVersionChanger(Model model, MutableXMLStreamReader pom, Log log) { this.model = model; this.pom = pom; this.log = log; @@ -46,7 +46,7 @@ public Model getModel() { return model; } - public ModifiedPomXMLEventReader getPom() { + public MutableXMLStreamReader getPom() { return pom; } diff --git a/versions-common/src/main/java/org/codehaus/mojo/versions/change/DependencyVersionChanger.java b/versions-common/src/main/java/org/codehaus/mojo/versions/change/DependencyVersionChanger.java index 03fd65810d..6a7062ad2c 100644 --- a/versions-common/src/main/java/org/codehaus/mojo/versions/change/DependencyVersionChanger.java +++ b/versions-common/src/main/java/org/codehaus/mojo/versions/change/DependencyVersionChanger.java @@ -21,7 +21,7 @@ import org.apache.maven.plugin.logging.Log; import org.codehaus.mojo.versions.api.PomHelper; import org.codehaus.mojo.versions.api.change.DependencyVersionChange; -import org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader; +import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader; /** * Created by IntelliJ IDEA. @@ -31,7 +31,7 @@ */ public class DependencyVersionChanger extends AbstractVersionChanger { - public DependencyVersionChanger(Model model, ModifiedPomXMLEventReader pom, Log reporter) { + public DependencyVersionChanger(Model model, MutableXMLStreamReader pom, Log reporter) { super(model, pom, reporter); } diff --git a/versions-common/src/main/java/org/codehaus/mojo/versions/change/ParentVersionChanger.java b/versions-common/src/main/java/org/codehaus/mojo/versions/change/ParentVersionChanger.java index a723ae62cd..08f1c1b0bf 100644 --- a/versions-common/src/main/java/org/codehaus/mojo/versions/change/ParentVersionChanger.java +++ b/versions-common/src/main/java/org/codehaus/mojo/versions/change/ParentVersionChanger.java @@ -21,14 +21,14 @@ import org.apache.maven.plugin.logging.Log; import org.codehaus.mojo.versions.api.PomHelper; import org.codehaus.mojo.versions.api.change.DependencyVersionChange; -import org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader; +import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader; /** * */ public class ParentVersionChanger extends AbstractVersionChanger { - public ParentVersionChanger(Model model, ModifiedPomXMLEventReader pom, Log reporter) { + public ParentVersionChanger(Model model, MutableXMLStreamReader pom, Log reporter) { super(model, pom, reporter); } diff --git a/versions-common/src/main/java/org/codehaus/mojo/versions/change/PluginVersionChanger.java b/versions-common/src/main/java/org/codehaus/mojo/versions/change/PluginVersionChanger.java index ac3f1b60d0..feed1486bd 100644 --- a/versions-common/src/main/java/org/codehaus/mojo/versions/change/PluginVersionChanger.java +++ b/versions-common/src/main/java/org/codehaus/mojo/versions/change/PluginVersionChanger.java @@ -21,7 +21,7 @@ import org.apache.maven.plugin.logging.Log; import org.codehaus.mojo.versions.api.PomHelper; import org.codehaus.mojo.versions.api.change.DependencyVersionChange; -import org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader; +import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader; /** * Created by IntelliJ IDEA. @@ -31,7 +31,7 @@ */ public class PluginVersionChanger extends AbstractVersionChanger { - public PluginVersionChanger(Model model, ModifiedPomXMLEventReader pom, Log reporter) { + public PluginVersionChanger(Model model, MutableXMLStreamReader pom, Log reporter) { super(model, pom, reporter); } diff --git a/versions-common/src/main/java/org/codehaus/mojo/versions/change/ProjectVersionChanger.java b/versions-common/src/main/java/org/codehaus/mojo/versions/change/ProjectVersionChanger.java index e9e21b16a1..20f4e258ea 100644 --- a/versions-common/src/main/java/org/codehaus/mojo/versions/change/ProjectVersionChanger.java +++ b/versions-common/src/main/java/org/codehaus/mojo/versions/change/ProjectVersionChanger.java @@ -21,7 +21,7 @@ import org.apache.maven.plugin.logging.Log; import org.codehaus.mojo.versions.api.PomHelper; import org.codehaus.mojo.versions.api.change.DependencyVersionChange; -import org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader; +import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader; /** * Created by IntelliJ IDEA. @@ -31,7 +31,7 @@ */ public class ProjectVersionChanger extends AbstractVersionChanger { - public ProjectVersionChanger(Model model, ModifiedPomXMLEventReader pom, Log reporter) { + public ProjectVersionChanger(Model model, MutableXMLStreamReader pom, Log reporter) { super(model, pom, reporter); } diff --git a/versions-common/src/main/java/org/codehaus/mojo/versions/change/VersionChangerFactory.java b/versions-common/src/main/java/org/codehaus/mojo/versions/change/VersionChangerFactory.java index 8e91d8fb64..739fccc827 100644 --- a/versions-common/src/main/java/org/codehaus/mojo/versions/change/VersionChangerFactory.java +++ b/versions-common/src/main/java/org/codehaus/mojo/versions/change/VersionChangerFactory.java @@ -24,7 +24,7 @@ import org.apache.maven.model.Model; import org.apache.maven.plugin.logging.Log; -import org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader; +import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader; /** * Created by IntelliJ IDEA. @@ -35,7 +35,7 @@ public class VersionChangerFactory { private Model model = null; - private ModifiedPomXMLEventReader pom = null; + private MutableXMLStreamReader pom = null; private Log log = null; @@ -47,11 +47,11 @@ public synchronized void setModel(Model model) { this.model = model; } - public synchronized ModifiedPomXMLEventReader getPom() { + public synchronized MutableXMLStreamReader getPom() { return pom; } - public synchronized void setPom(ModifiedPomXMLEventReader pom) { + public synchronized void setPom(MutableXMLStreamReader pom) { this.pom = pom; } diff --git a/versions-common/src/main/java/org/codehaus/mojo/versions/rewriting/ModifiedPomXMLEventReader.java b/versions-common/src/main/java/org/codehaus/mojo/versions/rewriting/ModifiedPomXMLEventReader.java deleted file mode 100644 index 4798700c3d..0000000000 --- a/versions-common/src/main/java/org/codehaus/mojo/versions/rewriting/ModifiedPomXMLEventReader.java +++ /dev/null @@ -1,521 +0,0 @@ -package org.codehaus.mojo.versions.rewriting; - -/* - * 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. - */ - -import javax.xml.stream.XMLEventReader; -import javax.xml.stream.XMLInputFactory; -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.events.Characters; -import javax.xml.stream.events.XMLEvent; - -import java.io.IOException; -import java.io.StringReader; - -import org.apache.maven.model.Model; -import org.apache.maven.model.io.xpp3.MavenXpp3Reader; -import org.codehaus.plexus.util.xml.pull.XmlPullParserException; - -/** - * Represents the modified pom file. Note: implementations of the StAX API (JSR-173) are not good round-trip rewriting - * while keeping all unchanged bytes in the file as is. For example, the StAX API specifies that CR - * characters will be stripped. Current implementations do not keep " and ' characters consistent. - * - * @author Stephen Connolly - */ -public class ModifiedPomXMLEventReader implements XMLEventReader { - - // ------------------------------ FIELDS ------------------------------ - - /** - * Field MAX_MARKS - */ - private static final int MAX_MARKS = 3; - - /** - * Field pom - */ - private final StringBuilder pom; - - /** - * Field modified - */ - private boolean modified = false; - - /** - * Field factory - */ - private final XMLInputFactory factory; - - /** - * Field nextStart - */ - private int nextStart = 0; - - /** - * Field nextEnd - */ - private int nextEnd = 0; - - /** - * Field markStart - */ - private int[] markStart = new int[MAX_MARKS]; - - /** - * Field markEnd - */ - private int[] markEnd = new int[MAX_MARKS]; - - /** - * Field markDelta - */ - private int[] markDelta = new int[MAX_MARKS]; - - /** - * Field lastStart - */ - private int lastStart = -1; - - /** - * Field lastEnd - */ - private int lastEnd; - - /** - * Field lastDelta - */ - private int lastDelta = 0; - - /** - * Field next - */ - private XMLEvent next = null; - - /** - * Field nextDelta - */ - private int nextDelta = 0; - - /** - * Field backing - */ - private XMLEventReader backing; - - /** - * Field path - */ - private final String path; - - // --------------------------- CONSTRUCTORS --------------------------- - - /** - * Constructor ModifiedPomXMLEventReader creates a new ModifiedPomXMLEventReader instance. - * - * @param pom of type StringBuilder - * @param factory of type XMLInputFactory - * @param path Path pointing to source of XML - * @throws XMLStreamException when - */ - public ModifiedPomXMLEventReader(StringBuilder pom, XMLInputFactory factory, String path) - throws XMLStreamException { - this.pom = pom; - this.factory = factory; - this.path = path; - rewind(); - } - - /** - * Rewind to the start so we can run through again. - * - * @throws XMLStreamException when things go wrong. - */ - public void rewind() throws XMLStreamException { - backing = factory.createXMLEventReader(new StringReader(pom.toString())); - nextEnd = 0; - nextDelta = 0; - for (int i = 0; i < MAX_MARKS; i++) { - markStart[i] = -1; - markEnd[i] = -1; - markDelta[i] = 0; - } - lastStart = -1; - lastEnd = -1; - lastDelta = 0; - next = null; - } - - // --------------------- GETTER / SETTER METHODS --------------------- - - /** - * Getter for property 'modified'. - * - * @return Value for property 'modified'. - */ - public boolean isModified() { - return modified; - } - - // ------------------------ INTERFACE METHODS ------------------------ - - // --------------------- Interface Iterator --------------------- - - /** - * {@inheritDoc} - */ - public Object next() { - try { - return nextEvent(); - } catch (XMLStreamException e) { - return null; - } - } - - /** - * {@inheritDoc} - */ - public void remove() { - throw new UnsupportedOperationException(); - } - - // --------------------- Interface XMLEventReader --------------------- - - /** - * {@inheritDoc} - */ - public XMLEvent nextEvent() throws XMLStreamException { - try { - return next; - } finally { - next = null; - lastStart = nextStart; - lastEnd = nextEnd; - lastDelta = nextDelta; - } - } - - /** - * {@inheritDoc} - */ - public XMLEvent peek() throws XMLStreamException { - return backing.peek(); - } - - /** - * {@inheritDoc} - */ - public String getElementText() throws XMLStreamException { - return backing.getElementText(); - } - - /** - * {@inheritDoc} - */ - public XMLEvent nextTag() throws XMLStreamException { - while (hasNext()) { - XMLEvent e = nextEvent(); - if (e.isCharacters() && !((Characters) e).isWhiteSpace()) { - throw new XMLStreamException("Unexpected text"); - } - if (e.isStartElement() || e.isEndElement()) { - return e; - } - } - throw new XMLStreamException("Unexpected end of Document"); - } - - /** - * {@inheritDoc} - */ - public Object getProperty(String name) { - return backing.getProperty(name); - } - - /** - * {@inheritDoc} - */ - public void close() throws XMLStreamException { - backing.close(); - next = null; - backing = null; - } - - // -------------------------- OTHER METHODS -------------------------- - - /** - * Returns a copy of the backing string buffer. - * - * @return a copy of the backing string buffer. - */ - public StringBuilder asStringBuilder() { - return new StringBuilder(pom.toString()); - } - - /** - * Clears the mark. - * - * @param index the mark to clear. - */ - public void clearMark(int index) { - markStart[index] = -1; - } - - /** - * the verbatim text of the current element when {@link #mark(int)} was called. - * - * @param index The mark index. - * @return the current element when {@link #mark(int)} was called. - */ - public String getMarkVerbatim(int index) { - if (hasMark(index)) { - return pom.substring(markDelta[index] + markStart[index], markDelta[index] + markEnd[index]); - } - return ""; - } - - /** - * Returns the verbatim text of the element returned by {@link #peek()}. - * - * @return the verbatim text of the element returned by {@link #peek()}. - */ - public String getPeekVerbatim() { - if (hasNext()) { - return pom.substring(nextDelta + nextStart, nextDelta + nextEnd); - } - return ""; - } - - /** - * {@inheritDoc} - */ - public boolean hasNext() { - if (next != null) { - // fast path - return true; - } - if (!backing.hasNext()) { - // fast path - return false; - } - try { - next = backing.nextEvent(); - nextStart = nextEnd; - if (backing.hasNext()) { - nextEnd = backing.peek().getLocation().getCharacterOffset(); - } - - if (nextEnd != -1) { - if (!next.isCharacters()) { - while (nextStart < nextEnd - && nextStart < pom.length() - && (c(nextStart) == '\n' || c(nextStart) == '\r')) { - nextStart++; - } - } else { - while (nextEndIncludesNextEvent() || nextEndIncludesNextEndElement()) { - nextEnd--; - } - } - } - return nextStart < pom.length(); - } catch (XMLStreamException e) { - throw new RuntimeException("Error parsing " + path + ": " + e.getMessage(), e); - } - } - - /** - * Getter for property 'verbatim'. - * - * @return Value for property 'verbatim'. - */ - public String getVerbatim() { - if (lastStart >= 0 && lastEnd >= lastStart) { - return pom.substring(lastDelta + lastStart, lastDelta + lastEnd); - } - return ""; - } - - /** - * Sets a mark to the current event. - * - * @param index the mark to set. - */ - public void mark(int index) { - markStart[index] = lastStart; - markEnd[index] = lastEnd; - markDelta[index] = lastDelta; - } - - /** - * Returns true if nextEnd is including the start of and end element. - * - * @return true if nextEnd is including the start of and end element. - */ - private boolean nextEndIncludesNextEndElement() { - return (nextEnd > nextStart + 2 && nextEnd - 2 < pom.length() && c(nextEnd - 2) == '<'); - } - - /** - * Returns true if nextEnd is including the start of the next event. - * - * @return true if nextEnd is including the start of the next event. - */ - private boolean nextEndIncludesNextEvent() { - return nextEnd > nextStart + 1 - && nextEnd - 2 < pom.length() - && (c(nextEnd - 1) == '<' || c(nextEnd - 1) == '&'); - } - - /** - * Gets the character at the index provided by the StAX parser. - * - * @param index the index. - * @return char The character. - */ - private char c(int index) { - return pom.charAt(nextDelta + index); - } - - /** - * Replaces the current element with the replacement text. - * - * @param replacement The replacement. - */ - public void replace(String replacement) { - if (lastStart < 0 || lastEnd < lastStart) { - throw new IllegalStateException(); - } - int start = lastDelta + lastStart; - int end = lastDelta + lastEnd; - if (replacement.equals(pom.substring(start, end))) { - return; - } - pom.replace(start, end, replacement); - int delta = replacement.length() - (lastEnd - lastStart); - nextDelta += delta; - for (int i = 0; i < MAX_MARKS; i++) { - if (hasMark(i) && lastStart == markStart[i] && markEnd[i] == lastEnd) { - markEnd[i] += delta; - } - } - lastEnd += delta; - modified = true; - } - - /** - * Returns true if the specified mark is defined. - * - * @param index The mark. - * @return true if the specified mark is defined. - */ - public boolean hasMark(int index) { - return markStart[index] != -1; - } - - public String getBetween(int index1, int index2) { - if (!hasMark(index1) || !hasMark(index2) || markStart[index1] > markStart[index2]) { - throw new IllegalStateException(); - } - int start = markDelta[index1] + markEnd[index1]; - int end = markDelta[index2] + markStart[index2]; - return pom.substring(start, end); - } - - /** - * Replaces all content between marks index1 and index2 with the replacement text. - * - * @param index1 The event mark to replace after. - * @param index2 The event mark to replace before. - * @param replacement The replacement. - */ - public void replaceBetween(int index1, int index2, String replacement) { - if (!hasMark(index1) || !hasMark(index2) || markStart[index1] > markStart[index2]) { - throw new IllegalStateException(); - } - int start = markDelta[index1] + markEnd[index1]; - int end = markDelta[index2] + markStart[index2]; - if (replacement.equals(pom.substring(start, end))) { - return; - } - pom.replace(start, end, replacement); - int delta = replacement.length() - (end - start); - nextDelta += delta; - - for (int i = 0; i < MAX_MARKS; i++) { - if (i == index1 || i == index2 || markStart[i] == -1) { - continue; - } - if (markStart[i] > markStart[index2]) { - markDelta[i] += delta; - } else if (markStart[i] == markEnd[index1] && markEnd[i] == markStart[index1]) { - markDelta[i] += delta; - } else if (markStart[i] > markEnd[index1] || markEnd[i] < markStart[index2]) { - markStart[i] = -1; - } - } - - modified = true; - } - - /** - * Replaces the specified marked element with the replacement text. - * - * @param index The mark. - * @param replacement The replacement. - */ - public void replaceMark(int index, String replacement) { - if (!hasMark(index)) { - throw new IllegalStateException(); - } - int start = markDelta[index] + markStart[index]; - int end = markDelta[index] + markEnd[index]; - if (replacement.equals(pom.substring(start, end))) { - return; - } - pom.replace(start, end, replacement); - int delta = replacement.length() - (markEnd[index] - markStart[index]); - nextDelta += delta; - if (lastStart == markStart[index] && lastEnd == markEnd[index]) { - lastEnd += delta; - } else if (lastStart > markStart[index]) { - lastDelta += delta; - } - for (int i = 0; i < MAX_MARKS; i++) { - if (i == index || markStart[i] == -1) { - continue; - } - if (markStart[i] > markStart[index]) { - markDelta[i] += delta; - } else if (markStart[i] == markStart[index] && markEnd[i] == markEnd[index]) { - markDelta[i] += delta; - } - } - markEnd[index] += delta; - modified = true; - } - - public Model parse() throws IOException, XmlPullParserException { - MavenXpp3Reader reader = new MavenXpp3Reader(); - return reader.read(new StringReader(pom.toString())); - } - - public String getPath() { - return path; - } -} diff --git a/versions-common/src/main/java/org/codehaus/mojo/versions/rewriting/MutableXMLStreamReader.java b/versions-common/src/main/java/org/codehaus/mojo/versions/rewriting/MutableXMLStreamReader.java new file mode 100644 index 0000000000..c964b6b460 --- /dev/null +++ b/versions-common/src/main/java/org/codehaus/mojo/versions/rewriting/MutableXMLStreamReader.java @@ -0,0 +1,377 @@ +package org.codehaus.mojo.versions.rewriting; + +/* + * Copyright MojoHaus and Contributors + * 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 javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import javax.xml.transform.TransformerException; + +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +import org.apache.maven.shared.utils.io.IOUtil; +import org.codehaus.stax2.LocationInfo; +import org.codehaus.stax2.XMLInputFactory2; +import org.codehaus.stax2.XMLStreamReader2; +import org.codehaus.stax2.util.StreamReader2Delegate; + +import static java.util.Optional.ofNullable; + +/** + * A mutable {@link XMLStreamReader2}, allowing simple string manipulation (replacement) of the underlying document + */ +public class MutableXMLStreamReader extends StreamReader2Delegate implements AutoCloseable { + private static final XMLInputFactory FACTORY = XMLInputFactory2.newInstance(); + + private StringBuilder source; + + private final Path fileName; + + private boolean modified; + + private final Map marks = new HashMap<>(); + + /** + * Current (start and end) offset (caused by mutations) against the {@link #getLocationInfo()} as reported by + * the delegate + */ + private final int[] delta = new int[2]; + + static { + FACTORY.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, false); + } + + private Charset sourceEncoding; + + /** + * Constructs a new object using the contents of the given file as the initial contents of the document. + * + * @param path file containing the initial document contents + * @throws IOException thrown in case of an I/O problems + * @throws XMLStreamException thrown if the file cannot be parsed + */ + public MutableXMLStreamReader(Path path) throws IOException, XMLStreamException, TransformerException { + this(Files.newInputStream(path), path); + } + + /** + * Constructs a new object using the contents of the given input stream as the initial contents of the document. + * + * @param inputStream stream containing the initial document contents + * @param fileName name of the file + * @throws IOException thrown in case of an I/O problems + * @throws XMLStreamException thrown if the file cannot be parsed + */ + public MutableXMLStreamReader(InputStream inputStream, Path fileName) + throws IOException, XMLStreamException, TransformerException { + super(null); + this.fileName = fileName; + init(inputStream); + rewind(); + } + + /** + * Returns the name of the file associated with the document + * + * @return name of the file associated with the document + */ + public Path getFileName() { + return fileName; + } + + /** + * Returns the current state of the document, in string format + * + * @return current state of the document, in string format + */ + public String getSource() { + return source.toString(); + } + + /** + * Whether the document has been modified + * + * @return {@code true} if the document has been modified + */ + public boolean isModified() { + return modified; + } + + /** + * Returns current (adjusted by {@link #delta} starting char offset + * + * @return current (adjusted by {@link #delta} starting char offset + */ + public int getCurrentStartingCharOffset() { + return delta[0] + (int) getLocationInfo().getStartingCharOffset(); + } + + /** + * Returns current (adjusted by {@link #delta} ending char offset + * + * @return current (adjusted by {@link #delta} ending char offset + */ + public int getCurrentEndingCharOffset() { + try { + return delta[1] + (int) getLocationInfo().getEndingCharOffset(); + } catch (XMLStreamException e) { + throw new IllegalStateException(e); + } + } + + /** + * Replaces the current element with the replacement text + * + * @param replacement string replacing the current element + */ + public void replace(String replacement) { + if (getEventType() == START_DOCUMENT || getEventType() == END_DOCUMENT) { + throw new IllegalStateException("Attempt at replacement outside of any element"); + } + + int start = getCurrentStartingCharOffset(), end = getCurrentEndingCharOffset(); + if (source.substring(start, end).equals(replacement)) { + return; + } + + source.replace(start, end, replacement); + int delta = replacement.length() - (end - start); + + // marks can only be added as the cursor traverses the document onwards, + // so the only marks affected by the replacement are marks set on the current element + marks.values().stream().filter(mi -> mi.getEnd() == end).forEach(mi -> mi.setEnd(mi.getEnd() + delta)); + + this.delta[1] += delta; + modified = true; + } + + private void validateMarks(Object... marks) { + for (Object mark : marks) { + if (!hasMark(mark)) { + throw new IllegalStateException("Mark " + mark + " does not exist"); + } + } + } + + private void validateMarkOffsets(Object mark1, Object mark2) { + if (marks.get(mark1).getStart() > marks.get(mark2).getStart()) { + throw new IllegalStateException("Start offset of " + mark1 + "(" + + marks.get(mark1).getEnd() + ") > start offset of " + mark2 + + "(" + marks.get(mark2).getStart() + ")"); + } + } + + /** + * Returns the substring of the document between the end of the first mark and the start of the second marked element + * + * @param mark1 starting mark of the substring + * @param mark2 ending mark of the substring + * @return substring of the document between two marks + */ + public String getBetween(Object mark1, Object mark2) { + validateMarks(mark1, mark2); + validateMarkOffsets(mark1, mark2); + + return Objects.equals(marks.get(mark1), marks.get(mark2)) + ? "" + : source.substring(marks.get(mark1).getEnd(), marks.get(mark2).getStart()); + } + + /** + * Replaces the document between two marks with the given replacement. + * + * @param mark1 starting mark of the string to be replaced + * @param mark2 ending mark of the string to be replaced + * @param replacement replacement string + */ + public void replaceBetween(Object mark1, Object mark2, String replacement) { + validateMarks(mark1, mark2); + validateMarkOffsets(mark1, mark2); + + int start = marks.get(mark1).getEnd(), end = marks.get(mark2).getStart(); + if (source.substring(start, end).equals(replacement)) { + return; + } + + source.replace(start, end, replacement); + int delta = replacement.length() - (end - start); + + marks.values().stream().filter(mi -> mi.getStart() >= end).forEach(mi -> mi.setStart(mi.getStart() + delta)); + marks.values().stream().filter(mi -> mi.getEnd() >= end).forEach(mi -> mi.setEnd(mi.getEnd() + delta)); + + this.delta[1] += delta; + modified = true; + } + + /** + * Replaces the document between the starting and ending character offset of the given mark + * + * @param mark mark to be replaced between its starting and ending character offset + * @param replacement replacement string + */ + public void replaceMark(Object mark, String replacement) { + validateMarks(mark); + + int start = marks.get(mark).getStart(), end = marks.get(mark).getEnd(); + if (source.substring(start, end).equals(replacement)) { + return; + } + + source.replace(start, end, replacement); + int delta = replacement.length() - (end - start); + + marks.values().stream().filter(mi -> mi.getStart() >= end).forEach(mi -> mi.setStart(mi.getStart() + delta)); + marks.values().stream().filter(mi -> mi.getEnd() >= end).forEach(mi -> mi.setEnd(mi.getEnd() + delta)); + + if (start < getCurrentStartingCharOffset()) { + this.delta[0] += delta; + } + this.delta[1] += delta; + modified = true; + } + + /** + * Recreates the underlying delegate {@link XMLStreamReader2} based on the current state of the document + * + * @throws XMLStreamException thrown if the document cannot be parsed + */ + public void rewind() throws XMLStreamException { + if (getParent() != null) { + getParent().close(); + } + + marks.clear(); + delta[0] = 0; + delta[1] = 0; + + XMLStreamReader2 reader = (XMLStreamReader2) FACTORY.createXMLStreamReader( + new ByteArrayInputStream(source.toString().getBytes(sourceEncoding)), sourceEncoding.toString()); + setParent(reader); + } + + @Override + public int next() throws XMLStreamException { + delta[0] = delta[1]; + return super.next(); + } + + /** + * If the mark with the given {@code markNr} has been recorded + * + * @param markNr number of the mark to check + * @return {@code true} if the given mark exists + */ + public boolean hasMark(Object markNr) { + return marks.containsKey(markNr); + } + + /** + * Records the current {@link LocationInfo} and delta under the given {@code markNr} + * + * @param markNr number of the mark to record to + */ + public void mark(Object markNr) { + marks.put(markNr, new MarkInfo(getCurrentStartingCharOffset(), getCurrentEndingCharOffset())); + } + + /** + * Removes the mark under the given {@code markNr} + * + * @param markNr number of the mark to remove + */ + public void clearMark(Object markNr) { + marks.remove(markNr); + } + + private void init(InputStream inputStream) throws IOException, XMLStreamException, TransformerException { + try (BufferedInputStream buf = new BufferedInputStream(inputStream)) { + buf.mark(0x4000); + + // detect the encoding + XMLStreamReader reader = FACTORY.createXMLStreamReader(buf); + sourceEncoding = + ofNullable(reader.getEncoding()).map(Charset::forName).orElse(Charset.defaultCharset()); + reader.close(); + + // offload the entire contents to this.source + buf.reset(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + IOUtil.copy(buf, baos); + source = new StringBuilder(baos.toString(sourceEncoding.toString())); + } + } + + /** + * Contains startingCharOffset and endingCharOffset information for a mark + */ + private static class MarkInfo { + private int start; + private int end; + + MarkInfo(int start, int end) { + this.start = start; + this.end = end; + } + + int getStart() { + return start; + } + + void setStart(int value) { + start = value; + } + + int getEnd() { + return end; + } + + void setEnd(int value) { + end = value; + } + + @Override + public int hashCode() { + return Objects.hash(start, end); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof MarkInfo)) { + return false; + } + MarkInfo other = (MarkInfo) obj; + return start == other.start && end == other.end; + } + + @Override + public String toString() { + return "MarkInfo[" + getStart() + ":" + getEnd() + "]"; + } + } +} diff --git a/versions-common/src/main/java/org/codehaus/mojo/versions/utils/ModelNode.java b/versions-common/src/main/java/org/codehaus/mojo/versions/utils/ModelNode.java index e59eb4992e..875f9b9787 100644 --- a/versions-common/src/main/java/org/codehaus/mojo/versions/utils/ModelNode.java +++ b/versions-common/src/main/java/org/codehaus/mojo/versions/utils/ModelNode.java @@ -21,7 +21,7 @@ import java.util.Optional; import org.apache.maven.model.Model; -import org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader; +import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader; /** * Represents a navigable tree of {@link Model} instances. @@ -29,15 +29,15 @@ public class ModelNode { private ModelNode parent; private Model item; - private ModifiedPomXMLEventReader pom; + private MutableXMLStreamReader pom; /** * Creates a root node (without a parent). * * @param model {@link Model} instance - * @param pom {@link ModifiedPomXMLEventReader} instance + * @param pom {@link MutableXMLStreamReader} instance */ - public ModelNode(Model model, ModifiedPomXMLEventReader pom) { + public ModelNode(Model model, MutableXMLStreamReader pom) { this(null, model, pom); } @@ -46,9 +46,9 @@ public ModelNode(Model model, ModifiedPomXMLEventReader pom) { * * @param parent parent node * @param model {@link Model} instance - * @param pom {@link ModifiedPomXMLEventReader} instance + * @param pom {@link MutableXMLStreamReader} instance */ - public ModelNode(ModelNode parent, Model model, ModifiedPomXMLEventReader pom) { + public ModelNode(ModelNode parent, Model model, MutableXMLStreamReader pom) { this.parent = parent; this.item = model; this.pom = pom; @@ -73,11 +73,11 @@ public Optional getParent() { } /** - * Gets the {@link ModifiedPomXMLEventReader} instance + * Gets the {@link MutableXMLStreamReader} instance * - * @return the {@link ModifiedPomXMLEventReader} instance + * @return the {@link MutableXMLStreamReader} instance */ - public ModifiedPomXMLEventReader getModifiedPomXMLEventReader() { + public MutableXMLStreamReader getMutableXMLStreamReader() { return pom; } diff --git a/versions-common/src/test/java/org/codehaus/mojo/versions/api/PomHelperTest.java b/versions-common/src/test/java/org/codehaus/mojo/versions/api/PomHelperTest.java index 0c885c8f0f..9afce7c232 100644 --- a/versions-common/src/test/java/org/codehaus/mojo/versions/api/PomHelperTest.java +++ b/versions-common/src/test/java/org/codehaus/mojo/versions/api/PomHelperTest.java @@ -19,10 +19,11 @@ * under the License. */ -import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamException; +import javax.xml.transform.TransformerException; import java.io.File; +import java.io.IOException; import java.io.StringReader; import java.net.URL; import java.nio.file.Files; @@ -42,16 +43,16 @@ import org.apache.maven.plugin.logging.Log; import org.apache.maven.plugin.logging.SystemStreamLog; import org.apache.maven.project.MavenProject; -import org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader; +import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader; import org.codehaus.mojo.versions.utils.ModelNode; -import org.codehaus.stax2.XMLInputFactory2; import org.hamcrest.MatcherAssert; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import static org.codehaus.mojo.versions.utils.ModifiedPomXMLEventReaderUtils.matches; -import static org.codehaus.stax2.XMLInputFactory2.P_PRESERVE_LOCATION; +import static java.nio.charset.Charset.defaultCharset; +import static org.apache.commons.io.IOUtils.toInputStream; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.containsStringIgnoringCase; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.core.Is.is; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -66,12 +67,7 @@ class PomHelperTest { private static final int NUMBER_OF_CHILD_PROJECTS = 30; - private static final XMLInputFactory INPUT_FACTORY = XMLInputFactory2.newInstance(); - - @BeforeAll - static void setUpClass() { - INPUT_FACTORY.setProperty(P_PRESERVE_LOCATION, Boolean.TRUE); - } + private static final Path PATH = Paths.get("dummy-file"); /** * Tests what happens when changing a long property substitution pattern, e.g. @@ -84,12 +80,8 @@ void testLongProperties() throws Exception { URL url = getClass().getResource("PomHelperTest.testLongProperties.pom.xml"); assert url != null; File file = new File(url.getPath()); - StringBuilder input = PomHelper.readXmlFile(file); - - XMLInputFactory inputFactory = XMLInputFactory2.newInstance(); - inputFactory.setProperty(P_PRESERVE_LOCATION, Boolean.TRUE); - ModifiedPomXMLEventReader pom = new ModifiedPomXMLEventReader(input, inputFactory, file.getAbsolutePath()); + MutableXMLStreamReader pom = new MutableXMLStreamReader(file.toPath()); String oldVersion = PomHelper.getProjectVersion(pom); @@ -106,9 +98,9 @@ void testLongProperties() throws Exception { void testGroupIdNotOnChildPom() throws Exception { URL url = getClass().getResource("PomHelperTest.noGroupIdOnChild.pom.xml"); assert url != null; - StringBuilder input = PomHelper.readXmlFile(new File(url.getPath())); + String input = PomHelper.readXml(new File(url.getPath())).getLeft(); MavenXpp3Reader reader = new MavenXpp3Reader(); - Model model = reader.read(new StringReader(input.toString())); + Model model = reader.read(new StringReader(input)); assertEquals("org.myorg", PomHelper.getGroupId(model)); } @@ -174,57 +166,60 @@ void testRangeVersionIntersect() throws Exception { } @Test - void testSetElementValueExistingValue() throws XMLStreamException { - ModifiedPomXMLEventReader xmlEventReader = new ModifiedPomXMLEventReader( - new StringBuilder("test"), - INPUT_FACTORY, - null); + void testSetElementValueExistingValue() throws XMLStreamException, IOException, TransformerException { + MutableXMLStreamReader xmlEventReader = new MutableXMLStreamReader( + toInputStream("test", defaultCharset()), + PATH); assertThat(PomHelper.setElementValue(xmlEventReader, "/super-parent/parent", "child", "value"), is(true)); MatcherAssert.assertThat( - xmlEventReader, matches("value")); + xmlEventReader.getSource().replaceAll("\\s", ""), + is("value")); } @Test - void testSetElementValueEmptyChild() throws XMLStreamException { - ModifiedPomXMLEventReader xmlEventReader = new ModifiedPomXMLEventReader( - new StringBuilder(""), INPUT_FACTORY, null); + void testSetElementValueEmptyChild() throws XMLStreamException, IOException, TransformerException { + MutableXMLStreamReader xmlEventReader = new MutableXMLStreamReader( + toInputStream("", defaultCharset()), PATH); assertThat(PomHelper.setElementValue(xmlEventReader, "/super-parent/parent", "child", "value"), is(true)); MatcherAssert.assertThat( - xmlEventReader, matches("value")); + xmlEventReader.getSource().replaceAll("\\s", ""), + is("value")); } @Test - void testSetElementValueNewValueEmptyParent() throws XMLStreamException { - ModifiedPomXMLEventReader xmlEventReader = new ModifiedPomXMLEventReader( - new StringBuilder(""), INPUT_FACTORY, null); + void testSetElementValueNewValueEmptyParent() throws XMLStreamException, IOException, TransformerException { + MutableXMLStreamReader xmlEventReader = new MutableXMLStreamReader( + toInputStream("", defaultCharset()), PATH); assertThat(PomHelper.setElementValue(xmlEventReader, "/super-parent/parent", "child", "value"), is(true)); MatcherAssert.assertThat( - xmlEventReader, matches("value")); + xmlEventReader.getSource().replaceAll("\\s", ""), + is("value")); } @Test - void testSetElementValueNewValueNoChild() throws XMLStreamException { - ModifiedPomXMLEventReader xmlEventReader = new ModifiedPomXMLEventReader( - new StringBuilder(""), INPUT_FACTORY, null); + void testSetElementValueNewValueNoChild() throws XMLStreamException, IOException, TransformerException { + MutableXMLStreamReader xmlEventReader = new MutableXMLStreamReader( + toInputStream("", defaultCharset()), PATH); assertThat(PomHelper.setElementValue(xmlEventReader, "/super-parent/parent", "child", "value"), is(true)); MatcherAssert.assertThat( - xmlEventReader, matches("value")); + xmlEventReader.getSource().replaceAll("\\s", ""), + is("value")); } @Test - void testSetProjectValueNewValueNonEmptyParent() throws XMLStreamException { - ModifiedPomXMLEventReader xmlEventReader = new ModifiedPomXMLEventReader( - new StringBuilder("test"), - INPUT_FACTORY, - null); + void testSetProjectValueNewValueNonEmptyParent() throws XMLStreamException, IOException, TransformerException { + MutableXMLStreamReader xmlEventReader = new MutableXMLStreamReader( + toInputStream("test", defaultCharset()), + PATH); assertThat(PomHelper.setElementValue(xmlEventReader, "/super-parent/parent", "child", "value"), is(true)); MatcherAssert.assertThat( - xmlEventReader, matches("value")); + xmlEventReader.getSource().replaceAll("\\s", ""), + is("value")); } @Test @@ -284,13 +279,10 @@ private Model createSimpleModel(String artifactId) { @Test void testGetRawModelTree() throws Exception { Log log = mock(Log.class); - XMLInputFactory inputFactory = XMLInputFactory2.newInstance(); - inputFactory.setProperty(XMLInputFactory2.P_PRESERVE_LOCATION, Boolean.TRUE); Path path = Paths.get("src/test/resources/org/codehaus/mojo/versions/api/getRawModelTree/pom.xml"); - ModifiedPomXMLEventReader pomReader = new ModifiedPomXMLEventReader( - new StringBuilder(new String(Files.readAllBytes(path))), inputFactory, path.toString()); - List rawModelTree = - PomHelper.getRawModelTree(new ModelNode(PomHelper.getRawModel(pomReader), pomReader), log); + MutableXMLStreamReader pomReader = new MutableXMLStreamReader(path); + List rawModelTree = PomHelper.getRawModelTree( + new ModelNode(PomHelper.getRawModel(pomReader.getSource(), path.toFile()), pomReader), log); assertThat( rawModelTree.stream() .map(ModelNode::getModel) @@ -302,13 +294,10 @@ void testGetRawModelTree() throws Exception { @Test void testFindProperty() throws Exception { Log log = mock(Log.class); - XMLInputFactory inputFactory = XMLInputFactory2.newInstance(); - inputFactory.setProperty(XMLInputFactory2.P_PRESERVE_LOCATION, Boolean.TRUE); Path path = Paths.get("src/test/resources/org/codehaus/mojo/versions/api/findProperty/pom.xml"); - ModifiedPomXMLEventReader pomReader = new ModifiedPomXMLEventReader( - new StringBuilder(new String(Files.readAllBytes(path))), inputFactory, path.toString()); - List rawModelTree = - PomHelper.getRawModelTree(new ModelNode(PomHelper.getRawModel(pomReader), pomReader), log); + MutableXMLStreamReader pomReader = new MutableXMLStreamReader(path); + List rawModelTree = PomHelper.getRawModelTree( + new ModelNode(PomHelper.getRawModel(pomReader.getSource(), path.toFile()), pomReader), log); ModelNode grandparent = rawModelTree.get(0); assertThat(grandparent.getModel().getArtifactId(), is("grandparent")); @@ -324,4 +313,15 @@ void testFindProperty() throws Exception { assertThat(PomHelper.findProperty("a", childB).get(), is(grandparent)); assertThat(PomHelper.findProperty("b", childB).get(), is(childB)); } + + @Test + // The reason for this is that XMLStreamReader overrides the preamble with its own detected encoding, + // which is especially visible for files with a BOM + void testReadXmlFileUtf16() throws IOException, XMLStreamException, TransformerException { + String string = PomHelper.readXml( + new File("src/test/resources/org/codehaus/mojo/versions/api/PomHelperTest.utf16.xml")) + .toString(); + assertThat(string, containsStringIgnoringCase("\"utf-16\"")); + assertThat(string, containsString("ąęśćńźĄŚĘŻĆ")); + } } diff --git a/versions-common/src/test/java/org/codehaus/mojo/versions/rewriting/ModifiedPomXMLEventReaderTest.java b/versions-common/src/test/java/org/codehaus/mojo/versions/rewriting/ModifiedPomXMLEventReaderTest.java deleted file mode 100644 index 3d259c018c..0000000000 --- a/versions-common/src/test/java/org/codehaus/mojo/versions/rewriting/ModifiedPomXMLEventReaderTest.java +++ /dev/null @@ -1,130 +0,0 @@ -package org.codehaus.mojo.versions.rewriting; - -/* - * 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. - */ - -import javax.xml.stream.Location; -import javax.xml.stream.XMLEventReader; -import javax.xml.stream.XMLInputFactory; -import javax.xml.stream.events.XMLEvent; - -import java.io.StringReader; -import java.lang.reflect.Field; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.core.Is.is; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; - -/** - * Unit tests for {@link ModifiedPomXMLEventReaderTest} - * - * @author Andrzej Jarmoniuk - */ -@ExtendWith(MockitoExtension.class) -class ModifiedPomXMLEventReaderTest { - private static final String[] STR = {"xyz", "0123456789abcdef"}; - private static final String REPLACEMENT = "abcdef"; - - @Mock - private Location location; - - @Mock - private XMLEvent xmlEvent; - - @Mock - private XMLEventReader xmlEventReader; - - @Mock - private XMLInputFactory xmlInputFactory; - - private ModifiedPomXMLEventReader pomXMLEventReader; - - @BeforeEach - void setUp() throws Exception { - - when(location.getCharacterOffset()).thenReturn(STR[0].length()).thenReturn(STR[0].length() + STR[1].length()); - - when(xmlEvent.isCharacters()).thenReturn(true); - when(xmlEvent.getLocation()).thenReturn(location); - - when(xmlEventReader.hasNext()) - .thenReturn(true) - .thenReturn(true) // str[0] - .thenReturn(true) - .thenReturn(true) // str[1] - .thenReturn(false); // ∅ - when(xmlEventReader.nextEvent()).thenReturn(xmlEvent).thenReturn(xmlEvent); - when(xmlEventReader.peek()).thenReturn(xmlEvent); - - when(xmlInputFactory.createXMLEventReader(any(StringReader.class))).thenReturn(xmlEventReader); - - pomXMLEventReader = - new ModifiedPomXMLEventReader(new StringBuilder(STR[0]).append(STR[1]), xmlInputFactory, ""); - } - - @Test - void testReplace() throws Exception { - assertThat(pomXMLEventReader.hasNext(), is(true)); - assertThat(pomXMLEventReader.nextEvent(), is(xmlEvent)); - - assertThat(pomXMLEventReader.hasNext(), is(true)); - assertThat(pomXMLEventReader.nextEvent(), is(xmlEvent)); - - pomXMLEventReader.replace(REPLACEMENT); - assertThat(pomXMLEventReader.asStringBuilder().toString(), is(STR[0] + REPLACEMENT)); - - pomXMLEventReader.mark(0); - assertThat(pomXMLEventReader.getMarkVerbatim(0), is(REPLACEMENT)); - - // more dangerous test since this touches the implementation - Field field = pomXMLEventReader.getClass().getDeclaredField("lastEnd"); - field.setAccessible(true); - assertThat(field.getInt(pomXMLEventReader), is((STR[0] + REPLACEMENT).length())); - } - - @Test - void testReplaceMark() throws Exception { - assertThat(pomXMLEventReader.hasNext(), is(true)); - assertThat(pomXMLEventReader.nextEvent(), is(xmlEvent)); - - assertThat(pomXMLEventReader.hasNext(), is(true)); - assertThat(pomXMLEventReader.nextEvent(), is(xmlEvent)); - - pomXMLEventReader.mark(0); - - pomXMLEventReader.replaceMark(0, REPLACEMENT); - assertThat(pomXMLEventReader.asStringBuilder().toString(), is(STR[0] + REPLACEMENT)); - - pomXMLEventReader.mark(0); - assertThat(pomXMLEventReader.getMarkVerbatim(0), is(REPLACEMENT)); - - // more dangerous test since this touches the implementation - Field field = pomXMLEventReader.getClass().getDeclaredField("lastEnd"); - field.setAccessible(true); - - assertThat(field.getInt(pomXMLEventReader), is((STR[0] + REPLACEMENT).length())); - } -} diff --git a/versions-common/src/test/java/org/codehaus/mojo/versions/rewriting/MutableXMLStreamReaderTest.java b/versions-common/src/test/java/org/codehaus/mojo/versions/rewriting/MutableXMLStreamReaderTest.java new file mode 100644 index 0000000000..caa62133c7 --- /dev/null +++ b/versions-common/src/test/java/org/codehaus/mojo/versions/rewriting/MutableXMLStreamReaderTest.java @@ -0,0 +1,245 @@ +package org.codehaus.mojo.versions.rewriting; + +/* + * 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. + */ + +import javax.xml.stream.XMLStreamException; +import javax.xml.transform.TransformerException; + +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; + +import org.codehaus.stax2.XMLStreamReader2; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import static javax.xml.stream.XMLStreamConstants.END_DOCUMENT; +import static javax.xml.stream.XMLStreamConstants.END_ELEMENT; +import static javax.xml.stream.XMLStreamConstants.START_DOCUMENT; +import static javax.xml.stream.XMLStreamConstants.START_ELEMENT; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.containsStringIgnoringCase; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.core.Is.is; + +/** + * Unit tests for {@link MutableXMLStreamReaderTest} + */ +class MutableXMLStreamReaderTest { + private static final Path PATH = Paths.get("path"); + + @ParameterizedTest + @ValueSource(strings = {"iso-8859-2", "utf-8", "utf-16"}) + void testCreateReaderUsingFile(String value) throws XMLStreamException, IOException, TransformerException { + Path path = Paths.get("src/test/resources/org/codehaus/mojo/versions/rewriting/" + value + ".xml"); + try (MutableXMLStreamReader reader = new MutableXMLStreamReader(path)) { + assertThat(reader.getFileName(), is(path)); + assertThat(reader.getSource(), containsStringIgnoringCase("encoding=\"" + value + "\"")); + assertThat(reader.getSource(), containsString("ąęóśłźćńĄŻĘĆ")); + } + } + + @ParameterizedTest + @ValueSource(strings = {"iso-8859-2", "utf-8", "utf-16"}) + void testCreateReaderUsingInputStream(String value) throws XMLStreamException, IOException, TransformerException { + Path path = Paths.get("src/test/resources/org/codehaus/mojo/versions/rewriting/" + value + ".xml"); + try (MutableXMLStreamReader reader = + new MutableXMLStreamReader(getClass().getResourceAsStream(value + ".xml"), path)) { + assertThat(reader.getFileName(), is(path)); + assertThat(reader.getSource(), containsStringIgnoringCase("encoding=\"" + value + "\"")); + assertThat(reader.getSource(), containsString("ąęóśłźćńĄŻĘĆ")); + } + } + + private static boolean goToElement(XMLStreamReader2 reader, int eventType, String elementName) + throws XMLStreamException { + for (int event = reader.getEventType(); event != END_DOCUMENT && reader.hasNext(); event = reader.next()) { + if (event == eventType && elementName.equals(reader.getLocalName())) { + return true; + } + } + return false; + } + + private static boolean goToStartElement(XMLStreamReader2 reader, String elementName) throws XMLStreamException { + return goToElement(reader, START_ELEMENT, elementName); + } + + private static boolean goToEndElement(XMLStreamReader2 reader, String elementName) throws XMLStreamException { + return goToElement(reader, END_ELEMENT, elementName); + } + + @ParameterizedTest + @ValueSource(strings = {"iso-8859-2", "utf-8", "utf-16"}) + void testReplace(String value) throws XMLStreamException, IOException, TransformerException { + MutableXMLStreamReader reader = + new MutableXMLStreamReader(getClass().getResourceAsStream(value + ".xml"), PATH); + + assertThat(reader.getEventType(), is(START_DOCUMENT)); + assertThat(reader.hasNext(), is(true)); + + // move inside the element + assertThat(goToStartElement(reader, "modelVersion"), is(true)); + reader.next(); + assertThat(reader.isCharacters(), is(true)); + + assertThat( + reader.getSource().substring((int) reader.getCurrentStartingCharOffset(), (int) + reader.getCurrentEndingCharOffset()), + equalTo("4.0.0")); + + reader.replace("5"); + assertThat( + reader.getSource() + .substring(reader.getCurrentStartingCharOffset(), reader.getCurrentEndingCharOffset()), + equalTo("5")); + + // now move inside the element + assertThat(goToStartElement(reader, "groupId"), is(true)); + reader.next(); + assertThat(reader.isCharacters(), is(true)); + + assertThat( + reader.getSource() + .substring(reader.getCurrentStartingCharOffset(), reader.getCurrentEndingCharOffset()), + equalTo("localhost")); + } + + @ParameterizedTest + @ValueSource(strings = {"iso-8859-2", "utf-8", "utf-16"}) + void testBetween(String value) throws XMLStreamException, IOException, TransformerException { + MutableXMLStreamReader reader = + new MutableXMLStreamReader(getClass().getResourceAsStream(value + ".xml"), PATH); + + assertThat(reader.getEventType(), is(START_DOCUMENT)); + assertThat(reader.hasNext(), is(true)); + + // move the cursor to + assertThat(goToStartElement(reader, "modelVersion"), is(true)); + reader.mark(""); + + // move the cursor to + assertThat(goToEndElement(reader, "modelVersion"), is(true)); + reader.mark(""); + + assertThat(reader.getBetween("", ""), is("4.0.0")); + + // to check if the replacement has not shifted offsets, move inside the element + assertThat(goToStartElement(reader, "groupId"), is(true)); + reader.next(); + assertThat(reader.isCharacters(), is(true)); + + assertThat( + reader.getSource() + .substring(reader.getCurrentStartingCharOffset(), reader.getCurrentEndingCharOffset()), + equalTo("localhost")); + } + + @ParameterizedTest + @ValueSource(strings = {"iso-8859-2", "utf-8", "utf-16"}) + void testReplaceBetween(String value) throws XMLStreamException, IOException, TransformerException { + MutableXMLStreamReader reader = + new MutableXMLStreamReader(getClass().getResourceAsStream(value + ".xml"), PATH); + + assertThat(reader.getEventType(), is(START_DOCUMENT)); + assertThat(reader.hasNext(), is(true)); + + // move the cursor to + assertThat(goToStartElement(reader, "version"), is(true)); + reader.mark(""); + + // move the cursor to + assertThat(goToEndElement(reader, "version"), is(true)); + reader.mark(""); + assertThat(reader.getBetween("", ""), is("1.0")); + + // move the cursor to + assertThat(goToStartElement(reader, "properties"), is(true)); + reader.mark(""); + + // move the cursor to + assertThat(goToEndElement(reader, "properties"), is(true)); + reader.mark(""); + + assertThat( + reader.getBetween("", ""), + allOf(containsString("2.0"), containsString("1.0"))); + + reader.replaceBetween("", "", "1.1.0-SNAPSHOT"); + assertThat(reader.getSource(), containsString("1.1.0-SNAPSHOT")); + assertThat(reader.getBetween("", ""), is("1.1.0-SNAPSHOT")); + + // after the replacement, offsets between marks should have been adjusted + assertThat( + reader.getBetween("", ""), + allOf(containsString("2.0"), containsString("1.0"))); + + // offsets outside marks should also be correct + assertThat(goToStartElement(reader, "groupId"), is(true)); + reader.next(); + assertThat(reader.isCharacters(), is(true)); + + assertThat( + reader.getSource() + .substring(reader.getCurrentStartingCharOffset(), reader.getCurrentEndingCharOffset()), + equalTo("localhost")); + } + + @ParameterizedTest + @ValueSource(strings = {"iso-8859-2", "utf-8", "utf-16"}) + void testReplaceMark(String value) throws XMLStreamException, IOException, TransformerException { + MutableXMLStreamReader reader = + new MutableXMLStreamReader(getClass().getResourceAsStream(value + ".xml"), PATH); + + assertThat(reader.getEventType(), is(START_DOCUMENT)); + assertThat(reader.hasNext(), is(true)); + + // create a set of marks in and around + assertThat(goToStartElement(reader, "version"), is(true)); + reader.mark(""); + reader.next(); + assertThat(reader.isCharacters(), is(true)); + reader.mark("version"); + assertThat(goToEndElement(reader, "version"), is(true)); + reader.mark(""); + + // create another set of marks in and around + assertThat(goToStartElement(reader, "api"), is(true)); + reader.mark(""); + reader.next(); + assertThat(reader.isCharacters(), is(true)); + reader.mark("api"); + assertThat(goToEndElement(reader, "api"), is(true)); + reader.mark(""); + + assertThat(reader.getBetween("", ""), is("1.0")); + assertThat(reader.getBetween("", ""), is("2.0")); + + reader.replaceMark("version", "1.0.1-SNAPSHOT"); + assertThat(reader.getBetween("", ""), is("1.0.1-SNAPSHOT")); + assertThat(reader.getBetween("", ""), is("2.0")); + + reader.replaceMark("version", "2"); + assertThat(reader.getBetween("", ""), is("2")); + assertThat(reader.getBetween("", ""), is("2.0")); + } +} diff --git a/versions-common/src/test/java/org/codehaus/mojo/versions/utils/ModifiedPomXMLEventReaderUtils.java b/versions-common/src/test/java/org/codehaus/mojo/versions/utils/ModifiedPomXMLEventReaderUtils.java deleted file mode 100644 index 01143daa4f..0000000000 --- a/versions-common/src/test/java/org/codehaus/mojo/versions/utils/ModifiedPomXMLEventReaderUtils.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.codehaus.mojo.versions.utils; - -/* - * 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. - */ - -import org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader; -import org.hamcrest.Description; -import org.hamcrest.Matcher; -import org.hamcrest.TypeSafeMatcher; - -/** - *

Utilities for the {@link ModifiedPomXMLEventReader} class

- * - * @author Andrzej Jarmoniuk - */ -public class ModifiedPomXMLEventReaderUtils { - public static

Matcher

matches(String pattern) { - return new TypeSafeMatcher

() { - @Override - public void describeTo(Description description) { - description.appendText(pattern); - } - - @Override - protected void describeMismatchSafely(P pom, Description description) { - description.appendText(asString(pom)); - } - - @Override - protected boolean matchesSafely(P pom) { - return pattern.matches(asString(pom)); - } - - private String asString(P pom) { - return pom.asStringBuilder().toString().replaceAll("\\s", ""); - } - }; - } -} diff --git a/versions-common/src/test/resources/org/codehaus/mojo/versions/api/PomHelperTest.utf16.xml b/versions-common/src/test/resources/org/codehaus/mojo/versions/api/PomHelperTest.utf16.xml new file mode 100644 index 0000000000..e654cff84c Binary files /dev/null and b/versions-common/src/test/resources/org/codehaus/mojo/versions/api/PomHelperTest.utf16.xml differ diff --git a/versions-common/src/test/resources/org/codehaus/mojo/versions/rewriting/iso-8859-2.xml b/versions-common/src/test/resources/org/codehaus/mojo/versions/rewriting/iso-8859-2.xml new file mode 100644 index 0000000000..6393a480d6 --- /dev/null +++ b/versions-common/src/test/resources/org/codehaus/mojo/versions/rewriting/iso-8859-2.xml @@ -0,0 +1,47 @@ + + + + + 4.0.0 + + localhost + it-update-properties-016 + 1.0 + pom + + iso-8859-2 + a test file in iso-8859-2 with some special characters: ±ê󶳼æñ¡¯ÊÆ + + + 2.0 + 1.0 + + + + + localhost + dummy-api + ${api} + + + localhost + dummy-impl + ${impl} + + + + diff --git a/versions-common/src/test/resources/org/codehaus/mojo/versions/rewriting/utf-16.xml b/versions-common/src/test/resources/org/codehaus/mojo/versions/rewriting/utf-16.xml new file mode 100644 index 0000000000..f85f8a0014 Binary files /dev/null and b/versions-common/src/test/resources/org/codehaus/mojo/versions/rewriting/utf-16.xml differ diff --git a/versions-common/src/test/resources/org/codehaus/mojo/versions/rewriting/utf-8.xml b/versions-common/src/test/resources/org/codehaus/mojo/versions/rewriting/utf-8.xml new file mode 100644 index 0000000000..fdc34c6ec4 --- /dev/null +++ b/versions-common/src/test/resources/org/codehaus/mojo/versions/rewriting/utf-8.xml @@ -0,0 +1,47 @@ + + + + + 4.0.0 + + localhost + it-update-properties-016 + 1.0 + pom + + utf-8 + test file using the utf-8 encoding with some special characters: ąęóśłźćńĄŻĘĆ + + + 2.0 + 1.0 + + + + + localhost + dummy-api + ${api} + + + localhost + dummy-impl + ${impl} + + + + diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/AbstractVersionsDependencyUpdaterMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/AbstractVersionsDependencyUpdaterMojo.java index 0994cd94b8..a7d794b87d 100644 --- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/AbstractVersionsDependencyUpdaterMojo.java +++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/AbstractVersionsDependencyUpdaterMojo.java @@ -42,7 +42,7 @@ import org.codehaus.mojo.versions.api.recording.ChangeRecorder; import org.codehaus.mojo.versions.api.recording.DependencyChangeRecord; import org.codehaus.mojo.versions.recording.DefaultDependencyChangeRecord; -import org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader; +import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader; import org.codehaus.mojo.versions.utils.DependencyBuilder; import org.codehaus.mojo.versions.utils.DependencyComparator; import org.eclipse.aether.RepositorySystem; @@ -285,7 +285,7 @@ protected String toString(MavenProject project) { buf.append(':'); buf.append(project.getArtifactId()); - if (project.getVersion() != null && project.getVersion().length() > 0) { + if (project.getVersion() != null && !project.getVersion().isEmpty()) { buf.append(":"); buf.append(project.getVersion()); } @@ -298,17 +298,17 @@ protected String toString(Dependency d) { buf.append(d.getGroupId()); buf.append(':'); buf.append(d.getArtifactId()); - if (d.getType() != null && d.getType().length() > 0) { + if (d.getType() != null && !d.getType().isEmpty()) { buf.append(':'); buf.append(d.getType()); } else { buf.append(":jar"); } - if (d.getClassifier() != null && d.getClassifier().length() > 0) { + if (d.getClassifier() != null && !d.getClassifier().isEmpty()) { buf.append(':'); buf.append(d.getClassifier()); } - if (d.getVersion() != null && d.getVersion().length() > 0) { + if (d.getVersion() != null && !d.getVersion().isEmpty()) { buf.append(":"); buf.append(d.getVersion()); } @@ -405,7 +405,7 @@ private ArtifactFilter getIncludesArtifactFilter() { List patterns = new ArrayList<>(); if (this.includesList != null) { patterns.addAll(separatePatterns(includesList)); - } else if (includes != null) { + } else { patterns.addAll(Arrays.asList(includes)); } includesFilter = new PatternIncludesArtifactFilter(patterns); @@ -418,7 +418,7 @@ private ArtifactFilter getExcludesArtifactFilter() { List patterns = new ArrayList<>(); if (excludesList != null) { patterns.addAll(separatePatterns(excludesList)); - } else if (excludes != null) { + } else { patterns.addAll(Arrays.asList(excludes)); } excludesFilter = new PatternExcludesArtifactFilter(patterns); @@ -494,7 +494,7 @@ private int findFirstChar(final String includeString, final String chars) { * Attempts to update the dependency {@code dep} to the given {@code newVersion}. The dependency can either * be the parent project or any given dependency. * - * @param pom {@link ModifiedPomXMLEventReader} instance to update the POM XML document + * @param pom {@link MutableXMLStreamReader} instance to update the POM XML document * @param dep dependency to be updated (can also be a dependency made from the parent) * @param newVersion new version to update the dependency to * @param changeKind title for the {@link ChangeRecorder} log @@ -502,10 +502,7 @@ private int findFirstChar(final String includeString, final String chars) { * @throws XMLStreamException thrown if updating the XML doesn't succeed */ protected boolean updateDependencyVersion( - ModifiedPomXMLEventReader pom, - Dependency dep, - String newVersion, - DependencyChangeRecord.ChangeKind changeKind) + MutableXMLStreamReader pom, Dependency dep, String newVersion, DependencyChangeRecord.ChangeKind changeKind) throws XMLStreamException, MojoExecutionException { boolean updated = false; if (isProcessingParent() diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/AbstractVersionsUpdaterMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/AbstractVersionsUpdaterMojo.java index d0bbdb4c53..f394adcb01 100644 --- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/AbstractVersionsUpdaterMojo.java +++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/AbstractVersionsUpdaterMojo.java @@ -20,12 +20,13 @@ */ import javax.inject.Inject; -import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamException; +import javax.xml.transform.TransformerException; import java.io.File; import java.io.IOException; import java.io.Writer; +import java.nio.charset.Charset; import java.nio.file.Files; import java.util.List; import java.util.Map; @@ -57,13 +58,11 @@ import org.codehaus.mojo.versions.api.recording.ChangeRecorder; import org.codehaus.mojo.versions.model.RuleSet; import org.codehaus.mojo.versions.ordering.InvalidSegmentException; -import org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader; -import org.codehaus.plexus.util.IOUtil; -import org.codehaus.plexus.util.WriterFactory; -import org.codehaus.stax2.XMLInputFactory2; +import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader; import org.eclipse.aether.RepositorySystem; import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; +import static java.util.Optional.ofNullable; /** * Abstract base class for Versions Mojos. @@ -313,8 +312,7 @@ protected ArtifactVersion findLatestVersion( */ protected void process(File outFile) throws MojoExecutionException, MojoFailureException { try { - StringBuilder input = PomHelper.readXmlFile(outFile); - ModifiedPomXMLEventReader newPom = newModifiedPomXER(input, outFile.getAbsolutePath()); + MutableXMLStreamReader newPom = new MutableXMLStreamReader(outFile.toPath()); update(newPom); @@ -330,50 +328,20 @@ protected void process(File outFile) throws MojoExecutionException, MojoFailureE } else { getLog().debug("Skipping generation of backup file"); } - writeFile(outFile, input); + try (Writer writer = Files.newBufferedWriter( + outFile.toPath(), + ofNullable(newPom.getEncoding()).map(Charset::forName).orElse(Charset.defaultCharset()))) { + writer.write(newPom.getSource()); + } } - saveChangeRecorderResults(); - } catch (IOException | XMLStreamException e) { + } catch (IOException e) { getLog().error(e); - } catch (VersionRetrievalException e) { + } catch (VersionRetrievalException | XMLStreamException | TransformerException e) { throw new MojoExecutionException(e.getMessage(), e); } } - /** - * Creates a {@link org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader} from a StringBuilder. - * - * @param input The XML to read and modify. - * @param path Path pointing to the source of the XML - * @return The {@link org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader}. - */ - protected final ModifiedPomXMLEventReader newModifiedPomXER(StringBuilder input, String path) { - ModifiedPomXMLEventReader newPom = null; - try { - XMLInputFactory inputFactory = XMLInputFactory2.newInstance(); - inputFactory.setProperty(XMLInputFactory2.P_PRESERVE_LOCATION, Boolean.TRUE); - newPom = new ModifiedPomXMLEventReader(input, inputFactory, path); - } catch (XMLStreamException e) { - getLog().error(e); - } - return newPom; - } - - /** - * Writes a StringBuilder into a file. - * - * @param outFile The file to read. - * @param input The contents of the file. - * @throws IOException when things go wrong. - */ - protected final void writeFile(File outFile, StringBuilder input) throws IOException { - - try (Writer writer = WriterFactory.newXmlWriter(outFile)) { - IOUtil.copy(input.toString(), writer); - } - } - /** * Updates the pom. * @@ -384,7 +352,7 @@ protected final void writeFile(File outFile, StringBuilder input) throws IOExcep * @throws VersionRetrievalException if version retrieval goes wrong * @since 1.0-alpha-1 */ - protected abstract void update(ModifiedPomXMLEventReader pom) + protected abstract void update(MutableXMLStreamReader pom) throws MojoExecutionException, MojoFailureException, XMLStreamException, VersionRetrievalException; /** @@ -452,13 +420,13 @@ protected boolean shouldApplyUpdate( * @param allowDowngrade if downgrades should be allowed if snapshots are not allowed * @param unchangedSegment most major segment not to be changed * @return new version of the artifact, if the property was updated; {@code null} if there was no update - * @throws XMLStreamException thrown from {@link ModifiedPomXMLEventReader} if the update doesn't succeed + * @throws XMLStreamException thrown from {@link MutableXMLStreamReader} if the update doesn't succeed * @throws InvalidVersionSpecificationException thrown if {@code unchangedSegment} doesn't match the version * @throws InvalidSegmentException thrown if {@code unchangedSegment} is invalid * @throws MojoExecutionException thrown if any other error occurs */ protected ArtifactVersion updatePropertyToNewestVersion( - ModifiedPomXMLEventReader pom, + MutableXMLStreamReader pom, Property property, PropertyVersions version, String currentVersion, @@ -510,8 +478,7 @@ protected void saveChangeRecorderResults() throws IOException, MojoExecutionExce this.getLog().debug("writing change record to " + this.changeRecorderOutputFile); getChangeRecorder() - .writeReport(Optional.ofNullable(changeRecorderOutputFile) - .map(File::toPath) - .orElse(null)); + .writeReport( + ofNullable(changeRecorderOutputFile).map(File::toPath).orElse(null)); } } diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/CompareDependenciesMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/CompareDependenciesMojo.java index d0ed14303e..43b5c171c3 100644 --- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/CompareDependenciesMojo.java +++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/CompareDependenciesMojo.java @@ -47,7 +47,7 @@ import org.codehaus.mojo.versions.api.VersionsHelper; import org.codehaus.mojo.versions.api.recording.ChangeRecorder; import org.codehaus.mojo.versions.api.recording.DependencyChangeRecord; -import org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader; +import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader; import org.codehaus.mojo.versions.utils.DependencyBuilder; import org.eclipse.aether.RepositorySystem; @@ -139,9 +139,9 @@ public CompareDependenciesMojo( * @throws org.apache.maven.plugin.MojoExecutionException Something wrong with the plugin itself * @throws org.apache.maven.plugin.MojoFailureException The plugin detected an error in the build * @throws javax.xml.stream.XMLStreamException when things go wrong with XML streaming - * @see AbstractVersionsUpdaterMojo#update(org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader) + * @see AbstractVersionsUpdaterMojo#update(MutableXMLStreamReader) */ - protected void update(ModifiedPomXMLEventReader pom) + protected void update(MutableXMLStreamReader pom) throws MojoExecutionException, MojoFailureException, XMLStreamException { if (this.ignoreRemoteDependencies && this.ignoreRemoteDependencyManagement) { throw new MojoFailureException(" ignoreRemoteDependencies and ignoreRemoteDependencyManagement " @@ -219,7 +219,7 @@ protected void update(ModifiedPomXMLEventReader pom) if (reportMode) { getLog().info("The following differences were found:"); - if (totalDiffs.size() == 0) { + if (totalDiffs.isEmpty()) { getLog().info(" none"); } else { for (String totalDiff : totalDiffs) { @@ -227,7 +227,7 @@ protected void update(ModifiedPomXMLEventReader pom) } } getLog().info("The following property differences were found:"); - if (propertyDiffs.size() == 0) { + if (propertyDiffs.isEmpty()) { getLog().info(" none"); } else { for (String propertyDiff : propertyDiffs) { @@ -281,7 +281,7 @@ private MavenProject getRemoteMavenProject(String groupId, String artifactId, St * @throws MojoExecutionException */ private List compareVersions( - ModifiedPomXMLEventReader pom, + MutableXMLStreamReader pom, List dependencies, Map remoteDependencies, DependencyChangeRecord.ChangeKind changeKind) @@ -313,7 +313,7 @@ private List compareVersions( * Updates the properties holding a version if necessary. */ private List updatePropertyVersions( - ModifiedPomXMLEventReader pom, + MutableXMLStreamReader pom, Map versionProperties, Map remoteDependencies) throws XMLStreamException { @@ -383,7 +383,7 @@ private void writeReportFile(List dependenciesUpdate, List prope PrintWriter pw = new PrintWriter(fw)) { pw.println("The following differences were found:"); pw.println(); - if (dependenciesUpdate.size() == 0) { + if (dependenciesUpdate.isEmpty()) { pw.println(" none"); } else { for (String dependencyUpdate : dependenciesUpdate) { @@ -393,7 +393,7 @@ private void writeReportFile(List dependenciesUpdate, List prope pw.println(); pw.println("The following property differences were found:"); pw.println(); - if (propertiesUpdate.size() == 0) { + if (propertiesUpdate.isEmpty()) { pw.println(" none"); } else { for (String propertyUpdate : propertiesUpdate) { diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/DisplayDependencyUpdatesMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/DisplayDependencyUpdatesMojo.java index ab8deb889b..f256b28de5 100644 --- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/DisplayDependencyUpdatesMojo.java +++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/DisplayDependencyUpdatesMojo.java @@ -46,7 +46,7 @@ import org.codehaus.mojo.versions.api.recording.ChangeRecorder; import org.codehaus.mojo.versions.filtering.WildcardMatcher; import org.codehaus.mojo.versions.ordering.InvalidSegmentException; -import org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader; +import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader; import org.codehaus.mojo.versions.utils.DependencyComparator; import org.codehaus.mojo.versions.utils.SegmentUtils; import org.eclipse.aether.RepositorySystem; @@ -582,11 +582,11 @@ private void logUpdates(Map updates, String sectio /** * @param pom the pom to update. - * @see org.codehaus.mojo.versions.AbstractVersionsUpdaterMojo#update(org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader) + * @see org.codehaus.mojo.versions.AbstractVersionsUpdaterMojo#update(MutableXMLStreamReader) * @since 1.0-alpha-1 */ @Override - protected void update(ModifiedPomXMLEventReader pom) { + protected void update(MutableXMLStreamReader pom) { // do nothing } } diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/DisplayExtensionUpdatesMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/DisplayExtensionUpdatesMojo.java index bd3e057d14..efdfe89660 100644 --- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/DisplayExtensionUpdatesMojo.java +++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/DisplayExtensionUpdatesMojo.java @@ -16,9 +16,10 @@ */ import javax.inject.Inject; +import javax.xml.stream.XMLStreamException; +import javax.xml.transform.TransformerException; import java.io.IOException; -import java.nio.file.Files; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -50,7 +51,7 @@ import org.codehaus.mojo.versions.api.recording.ChangeRecorder; import org.codehaus.mojo.versions.filtering.DependencyFilter; import org.codehaus.mojo.versions.filtering.WildcardMatcher; -import org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader; +import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader; import org.codehaus.mojo.versions.utils.CoreExtensionUtils; import org.codehaus.mojo.versions.utils.DependencyBuilder; import org.codehaus.mojo.versions.utils.ExtensionBuilder; @@ -269,13 +270,12 @@ public void execute() throws MojoExecutionException, MojoFailureException { private List getRawModels() throws MojoFailureException { List rawModels; try { - ModifiedPomXMLEventReader pomReader = newModifiedPomXER( - new StringBuilder( - new String(Files.readAllBytes(getProject().getFile().toPath()))), - getProject().getFile().toPath().toString()); - ModelNode rootNode = new ModelNode(PomHelper.getRawModel(pomReader), pomReader); + MutableXMLStreamReader pomReader = + new MutableXMLStreamReader(getProject().getFile().toPath()); + ModelNode rootNode = new ModelNode( + PomHelper.getRawModel(pomReader.getSource(), getProject().getFile()), pomReader); rawModels = PomHelper.getRawModelTree(rootNode, getLog()); - } catch (IOException e) { + } catch (IOException | XMLStreamException | TransformerException e) { throw new MojoFailureException(e.getMessage(), e); } return rawModels; @@ -354,11 +354,11 @@ private void logUpdates(Map updates) { /** * @param pom the pom to update. - * @see AbstractVersionsUpdaterMojo#update(ModifiedPomXMLEventReader) + * @see AbstractVersionsUpdaterMojo#update(MutableXMLStreamReader) * @since 1.0-alpha-1 */ @Override - protected void update(ModifiedPomXMLEventReader pom) { + protected void update(MutableXMLStreamReader pom) { // do nothing } } diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/DisplayParentUpdatesMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/DisplayParentUpdatesMojo.java index b8ca91b1c0..fa7f1b9787 100644 --- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/DisplayParentUpdatesMojo.java +++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/DisplayParentUpdatesMojo.java @@ -42,7 +42,7 @@ import org.codehaus.mojo.versions.api.VersionRetrievalException; import org.codehaus.mojo.versions.api.recording.ChangeRecorder; import org.codehaus.mojo.versions.ordering.InvalidSegmentException; -import org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader; +import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader; import org.codehaus.mojo.versions.utils.DefaultArtifactVersionCache; import org.codehaus.mojo.versions.utils.DependencyBuilder; import org.codehaus.mojo.versions.utils.SegmentUtils; @@ -258,5 +258,5 @@ private static Iterable reverse(T[] array) { } @Override - protected void update(ModifiedPomXMLEventReader pom) {} + protected void update(MutableXMLStreamReader pom) {} } diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/DisplayPluginUpdatesMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/DisplayPluginUpdatesMojo.java index 1380747131..f48a72362e 100644 --- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/DisplayPluginUpdatesMojo.java +++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/DisplayPluginUpdatesMojo.java @@ -21,13 +21,14 @@ import javax.inject.Inject; import javax.xml.stream.XMLStreamException; -import javax.xml.stream.events.XMLEvent; +import javax.xml.transform.TransformerException; +import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; -import java.io.Reader; +import java.io.InputStream; import java.io.StringWriter; -import java.net.URL; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -81,17 +82,16 @@ import org.codehaus.mojo.versions.api.VersionRetrievalException; import org.codehaus.mojo.versions.api.recording.ChangeRecorder; import org.codehaus.mojo.versions.ordering.MavenVersionComparator; -import org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader; +import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader; import org.codehaus.mojo.versions.utils.DefaultArtifactVersionCache; import org.codehaus.mojo.versions.utils.DependencyBuilder; import org.codehaus.mojo.versions.utils.PluginComparator; -import org.codehaus.plexus.util.IOUtil; -import org.codehaus.plexus.util.ReaderFactory; import org.eclipse.aether.RepositorySystem; import static java.util.Collections.emptyMap; import static java.util.Optional.ofNullable; import static java.util.stream.Collectors.toMap; +import static javax.xml.stream.XMLStreamConstants.END_DOCUMENT; /** * Displays all plugins that have newer versions available, taking care of Maven version prerequisites. @@ -127,6 +127,7 @@ public class DisplayPluginUpdatesMojo extends AbstractVersionsDisplayMojo { public static final Pattern PATTERN_PROJECT_PLUGIN = Pattern.compile( "/project(/profiles/profile)?" + "((/build(/pluginManagement)?)|(/reporting))" + "/plugins/plugin"); + public static final String SUPERPOM_PATH = "org/apache/maven/model/pom-4.0.0.xml"; /** * @since 1.0-alpha-1 @@ -197,65 +198,57 @@ private Map getSuperPomPluginManagement() { .stream() .collect(LinkedHashMap::new, (m, p) -> m.put(p.getKey(), p.getVersion()), Map::putAll); - URL superPom = getClass().getClassLoader().getResource("org/apache/maven/model/pom-4.0.0.xml"); - if (superPom != null) { - try { - try (Reader reader = ReaderFactory.newXmlReader(superPom)) { - StringBuilder buf = new StringBuilder(IOUtil.toString(reader)); - ModifiedPomXMLEventReader pom = newModifiedPomXER(buf, superPom.toString()); - - Stack pathStack = new Stack<>(); - StackState curState = null; - while (pom.hasNext()) { - XMLEvent event = pom.nextEvent(); - if (event.isStartDocument()) { - curState = new StackState(""); - pathStack.clear(); - } else if (event.isStartElement()) { - if (curState != null) { - String elementName = - event.asStartElement().getName().getLocalPart(); - if (PATTERN_PROJECT_PLUGIN - .matcher(curState.path) - .matches()) { - if ("groupId".equals(elementName)) { - curState.groupId = pom.getElementText().trim(); - continue; - } else if ("artifactId".equals(elementName)) { - curState.artifactId = - pom.getElementText().trim(); - continue; - - } else if ("version".equals(elementName)) { - curState.version = pom.getElementText().trim(); - continue; - } - } - - pathStack.push(curState); - curState = new StackState(curState.path + "/" + elementName); - } - } else if (event.isEndElement()) { - if (curState != null - && curState.artifactId != null - && PATTERN_PROJECT_PLUGIN - .matcher(curState.path) - .matches()) { - result.putIfAbsent( - Plugin.constructKey( - curState.groupId == null - ? PomHelper.APACHE_MAVEN_PLUGINS_GROUPID - : curState.groupId, - curState.artifactId), - curState.version); + try (InputStream superPomIs = getClass().getClassLoader().getResourceAsStream(SUPERPOM_PATH)) { + Objects.requireNonNull(superPomIs); + MutableXMLStreamReader pomReader = new MutableXMLStreamReader(superPomIs, Paths.get(SUPERPOM_PATH)); + + Stack pathStack = new Stack<>(); + StackState curState = new StackState(""); + + for (int event = pomReader.getEventType(); + event != END_DOCUMENT && pomReader.hasNext(); + event = pomReader.next()) { + if (pomReader.isStartElement()) { + if (curState != null) { + String elementName = pomReader.getLocalName(); + if (PATTERN_PROJECT_PLUGIN.matcher(curState.path).matches()) { + switch (elementName) { + case "groupId": + curState.groupId = + pomReader.getElementText().trim(); + break; + case "artifactId": + curState.artifactId = + pomReader.getElementText().trim(); + break; + case "version": + curState.version = + pomReader.getElementText().trim(); + break; + default: + break; } - curState = pathStack.pop(); } + pathStack.push(curState); + curState = new StackState(curState.path + "/" + elementName); + } + } else if (pomReader.isEndElement()) { + if (curState != null + && curState.artifactId != null + && PATTERN_PROJECT_PLUGIN.matcher(curState.path).matches()) { + result.putIfAbsent( + Plugin.constructKey( + curState.groupId == null + ? PomHelper.APACHE_MAVEN_PLUGINS_GROUPID + : curState.groupId, + curState.artifactId), + curState.version); } + curState = pathStack.pop(); } - } catch (IOException | XMLStreamException e) { - // ignore } + } catch (IOException | XMLStreamException | TransformerException e) { + // ignore } return result; @@ -318,11 +311,10 @@ private Map getPluginManagement(Model model) { public void execute() throws MojoExecutionException, MojoFailureException { logInit(); Set pluginsWithVersionsSpecified; - try { - MavenProject project1 = getProject(); - pluginsWithVersionsSpecified = findPluginsWithVersionsSpecified( - PomHelper.readXmlFile(project1.getFile()), getSafeProjectPathInfo(project1)); - } catch (XMLStreamException | IOException e) { + try (MutableXMLStreamReader pomReader = + new MutableXMLStreamReader(getProject().getFile().toPath())) { + pluginsWithVersionsSpecified = findPluginsWithVersionsSpecified(pomReader); + } catch (XMLStreamException | IOException | TransformerException e) { throw new MojoExecutionException(e.getMessage(), e); } @@ -685,22 +677,28 @@ private Map getParentsPlugins(List parents) throws interpolatedModel = modelInterpolator.interpolateModel( originalModel, null, modelBuildingRequest, new IgnoringModelProblemCollector()); if (havePom) { - try { - Set withVersionSpecified = findPluginsWithVersionsSpecified( - new StringBuilder(writer.toString()), getSafeProjectPathInfo(parentProject)); - - Map map = getPluginManagement(interpolatedModel); - map.keySet().retainAll(withVersionSpecified); - parentPlugins.putAll(map); - - map = getBuildPlugins(interpolatedModel, true); - map.keySet().retainAll(withVersionSpecified); - parentPlugins.putAll(map); - - map = getReportPlugins(interpolatedModel, true); - map.keySet().retainAll(withVersionSpecified); - parentPlugins.putAll(map); - } catch (XMLStreamException e) { + try (ByteArrayInputStream bais = + new ByteArrayInputStream(writer.toString().getBytes())) { + try (MutableXMLStreamReader pomReader = new MutableXMLStreamReader( + bais, + ofNullable(parentProject.getFile()) + .map(File::toPath) + .orElse(null))) { + Set withVersionSpecified = findPluginsWithVersionsSpecified(pomReader); + + Map map = getPluginManagement(interpolatedModel); + map.keySet().retainAll(withVersionSpecified); + parentPlugins.putAll(map); + + map = getBuildPlugins(interpolatedModel, true); + map.keySet().retainAll(withVersionSpecified); + parentPlugins.putAll(map); + + map = getReportPlugins(interpolatedModel, true); + map.keySet().retainAll(withVersionSpecified); + parentPlugins.putAll(map); + } + } catch (XMLStreamException | TransformerException | IOException e) { throw new MojoExecutionException(e.getMessage(), e); } } else { @@ -712,14 +710,6 @@ private Map getParentsPlugins(List parents) throws return parentPlugins; } - private String getSafeProjectPathInfo(MavenProject project) { - return ofNullable(project.getFile()) - .map(File::getAbsolutePath) - // path is used only as information in error message, - // we can fallback to project artifact info here - .orElse(project.toString()); - } - private boolean isMavenPluginProject() { return "maven-plugin".equals(getProject().getPackaging()); } @@ -752,34 +742,28 @@ public String toString() { /** * Returns a set of Strings which correspond to the plugin coordinates where there is a version specified. * - * @param pomContents The project to get the plugins with versions specified. - * @param path Path that points to the source of the XML + * @param pom a {@link MutableXMLStreamReader} instance for the pom project to get the plugins with versions specified. * @return a set of Strings which correspond to the plugin coordinates where there is a version specified. */ - private Set findPluginsWithVersionsSpecified(StringBuilder pomContents, String path) - throws XMLStreamException { + private Set findPluginsWithVersionsSpecified(MutableXMLStreamReader pom) + throws XMLStreamException, IOException, TransformerException { Set result = new HashSet<>(); - ModifiedPomXMLEventReader pom = newModifiedPomXER(pomContents, path); - Stack pathStack = new Stack<>(); - StackState curState = null; + StackState curState = new StackState(""); + while (pom.hasNext()) { - XMLEvent event = pom.nextEvent(); - if (event.isStartDocument()) { - curState = new StackState(""); - pathStack.clear(); - } else if (event.isStartElement()) { - String elementName = event.asStartElement().getName().getLocalPart(); + pom.next(); + if (pom.isStartElement()) { if (curState != null && PATTERN_PROJECT_PLUGIN.matcher(curState.path).matches()) { - if ("groupId".equals(elementName)) { + if ("groupId".equals(pom.getLocalName())) { curState.groupId = pom.getElementText().trim(); continue; - } else if ("artifactId".equals(elementName)) { + } else if ("artifactId".equals(pom.getLocalName())) { curState.artifactId = pom.getElementText().trim(); continue; - } else if ("version".equals(elementName)) { + } else if ("version".equals(pom.getLocalName())) { curState.version = pom.getElementText().trim(); continue; } @@ -787,8 +771,10 @@ private Set findPluginsWithVersionsSpecified(StringBuilder pomContents, assert curState != null; pathStack.push(curState); - curState = new StackState(curState.path + "/" + elementName); - } else if (event.isEndElement()) { + curState = new StackState(curState.path + "/" + pom.getLocalName()); + } + // for empty elements, pom can be both start- and end element + if (pom.isEndElement()) { if (curState != null && PATTERN_PROJECT_PLUGIN.matcher(curState.path).matches()) { if (curState.artifactId != null && curState.version != null) { @@ -810,10 +796,10 @@ private Set findPluginsWithVersionsSpecified(StringBuilder pomContents, /** * Get the minimum required Maven version of the given plugin * Same logic as in - * @see PluginReport * * @param pluginProject the plugin for which to retrieve the minimum Maven version which is required * @return The minimally required Maven version (never {@code null}) + * @see PluginReport */ private ArtifactVersion getPrerequisitesMavenVersion(MavenProject pluginProject) { return ofNullable(pluginProject.getPrerequisites()) @@ -875,7 +861,7 @@ private static boolean getPluginInherited(Object plugin) { * Gets the plugins that are bound to the defined phases. This does not find plugins bound in the pom to a phase * later than the plugin is executing. * - * @param project the project + * @param project the project * @return the bound plugins */ // pilfered this from enforcer-rules @@ -1154,10 +1140,10 @@ private Map getReportPlugins(Model model, boolean onlyIncludeInh /** * @param pom the pom to update. - * @see AbstractVersionsUpdaterMojo#update(ModifiedPomXMLEventReader) + * @see AbstractVersionsUpdaterMojo#update(MutableXMLStreamReader) * @since 1.0-alpha-1 */ - protected void update(ModifiedPomXMLEventReader pom) { + protected void update(MutableXMLStreamReader pom) { // do nothing } diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/DisplayPropertyUpdatesMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/DisplayPropertyUpdatesMojo.java index 4dd1c8617b..28663868cd 100644 --- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/DisplayPropertyUpdatesMojo.java +++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/DisplayPropertyUpdatesMojo.java @@ -42,7 +42,7 @@ import org.codehaus.mojo.versions.api.VersionsHelper; import org.codehaus.mojo.versions.api.recording.ChangeRecorder; import org.codehaus.mojo.versions.ordering.InvalidSegmentException; -import org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader; +import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader; import org.eclipse.aether.RepositorySystem; import static java.util.Optional.empty; @@ -267,5 +267,5 @@ public void execute() throws MojoExecutionException, MojoFailureException { } @Override - protected void update(ModifiedPomXMLEventReader pom) {} + protected void update(MutableXMLStreamReader pom) {} } diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/ForceReleasesMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/ForceReleasesMojo.java index a9d5c0a4a2..5474d349c8 100644 --- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/ForceReleasesMojo.java +++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/ForceReleasesMojo.java @@ -39,7 +39,7 @@ import org.codehaus.mojo.versions.api.VersionRetrievalException; import org.codehaus.mojo.versions.api.recording.ChangeRecorder; import org.codehaus.mojo.versions.api.recording.DependencyChangeRecord; -import org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader; +import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader; import org.eclipse.aether.RepositorySystem; import static java.util.Collections.singletonList; @@ -76,9 +76,9 @@ public ForceReleasesMojo( * @throws org.apache.maven.plugin.MojoExecutionException when things go wrong * @throws org.apache.maven.plugin.MojoFailureException when things go wrong in a very bad way * @throws javax.xml.stream.XMLStreamException when things go wrong with XML streaming - * @see AbstractVersionsUpdaterMojo#update(org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader) + * @see AbstractVersionsUpdaterMojo#update(MutableXMLStreamReader) */ - protected void update(ModifiedPomXMLEventReader pom) + protected void update(MutableXMLStreamReader pom) throws MojoExecutionException, MojoFailureException, XMLStreamException, VersionRetrievalException { try { if (isProcessingDependencyManagement()) { @@ -103,7 +103,7 @@ protected void update(ModifiedPomXMLEventReader pom) } private void useReleases( - ModifiedPomXMLEventReader pom, + MutableXMLStreamReader pom, Collection dependencies, DependencyChangeRecord.ChangeKind changeKind) throws XMLStreamException, MojoExecutionException, VersionRetrievalException { diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/LockSnapshotsMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/LockSnapshotsMojo.java index 1351b110d0..474a688f6c 100644 --- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/LockSnapshotsMojo.java +++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/LockSnapshotsMojo.java @@ -42,7 +42,7 @@ import org.codehaus.mojo.versions.api.PomHelper; import org.codehaus.mojo.versions.api.VersionsHelper; import org.codehaus.mojo.versions.api.recording.ChangeRecorder; -import org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader; +import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader; import org.eclipse.aether.RepositorySystem; import org.eclipse.aether.resolution.VersionRequest; import org.eclipse.aether.resolution.VersionResolutionException; @@ -83,9 +83,9 @@ public LockSnapshotsMojo( * @throws MojoExecutionException when things go wrong * @throws MojoFailureException when things go wrong in a very bad way * @throws XMLStreamException when things go wrong with XML streaming - * @see AbstractVersionsUpdaterMojo#update(ModifiedPomXMLEventReader) + * @see AbstractVersionsUpdaterMojo#update(MutableXMLStreamReader) */ - protected void update(ModifiedPomXMLEventReader pom) + protected void update(MutableXMLStreamReader pom) throws MojoExecutionException, MojoFailureException, XMLStreamException { try { if (isProcessingDependencyManagement()) { @@ -106,7 +106,7 @@ protected void update(ModifiedPomXMLEventReader pom) } } - protected void lockSnapshots(ModifiedPomXMLEventReader pom, Collection dependencies) + protected void lockSnapshots(MutableXMLStreamReader pom, Collection dependencies) throws XMLStreamException, MojoExecutionException, VersionResolutionException { for (Dependency dep : dependencies) { if (isExcludeReactor() && isProducedByReactor(dep)) { @@ -145,7 +145,7 @@ protected void lockSnapshots(ModifiedPomXMLEventReader pom, Collection dependencies) + private void resolveRanges(MutableXMLStreamReader pom, Collection dependencies) throws XMLStreamException, MojoExecutionException, VersionRetrievalException { for (Dependency dep : dependencies) { @@ -277,13 +276,11 @@ private void resolveRanges(ModifiedPomXMLEventReader pom, Collection } } - private void resolvePropertyRanges(ModifiedPomXMLEventReader pom) - throws XMLStreamException, MojoExecutionException { + private void resolvePropertyRanges(MutableXMLStreamReader pom) throws XMLStreamException, MojoExecutionException { if (includeProperties == null) { Properties originalProperties = getProject().getOriginalModel().getProperties(); - includeProperties = - originalProperties.stringPropertyNames().stream().collect(Collectors.joining(",")); + includeProperties = String.join(",", originalProperties.stringPropertyNames()); } Map propertyVersions = this.getHelper() .getVersionPropertiesMap(VersionsHelper.VersionPropertiesMapRequest.builder() @@ -323,10 +320,9 @@ private void resolvePropertyRanges(ModifiedPomXMLEventReader pom) .map(Segment::toString) .orElse("ALL") + " version changes allowed"); } - Optional unchangedSegment = unchangedSegment1; // TODO: Check if we could add allowDowngrade ? try { - updatePropertyToNewestVersion(pom, property, version, currentVersion, false, unchangedSegment); + updatePropertyToNewestVersion(pom, property, version, currentVersion, false, unchangedSegment1); } catch (InvalidSegmentException | InvalidVersionSpecificationException e) { getLog().warn(String.format( "Skipping the processing of %s:%s due to: %s", diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/SetMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/SetMojo.java index b1b9fef939..baa70fcf92 100644 --- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/SetMojo.java +++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/SetMojo.java @@ -54,7 +54,7 @@ import org.codehaus.mojo.versions.change.VersionChanger; import org.codehaus.mojo.versions.change.VersionChangerFactory; import org.codehaus.mojo.versions.ordering.ReactorDepthComparator; -import org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader; +import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader; import org.codehaus.mojo.versions.utils.ContextualLog; import org.codehaus.mojo.versions.utils.DelegatingContextualLog; import org.codehaus.mojo.versions.utils.RegexUtils; @@ -542,11 +542,12 @@ private void applyChange( * @throws org.apache.maven.plugin.MojoFailureException when things go wrong. * @throws javax.xml.stream.XMLStreamException when things go wrong. */ - protected synchronized void update(ModifiedPomXMLEventReader pom) + protected synchronized void update(MutableXMLStreamReader pom) throws MojoExecutionException, MojoFailureException, XMLStreamException { ContextualLog log = new DelegatingContextualLog(getLog()); try { - Model model = PomHelper.getRawModel(pom); + Model model = + PomHelper.getRawModel(pom.getSource(), pom.getFileName().toFile()); log.setContext("Processing " + PomHelper.getGroupId(model) + ":" + PomHelper.getArtifactId(model)); VersionChangerFactory versionChangerFactory = new VersionChangerFactory(); @@ -573,7 +574,7 @@ protected synchronized void update(ModifiedPomXMLEventReader pom) log.clearContext(); } - private void updateBuildOutputTimestamp(ModifiedPomXMLEventReader pom, Model model) throws XMLStreamException { + private void updateBuildOutputTimestamp(MutableXMLStreamReader pom, Model model) throws XMLStreamException { String buildOutputTimestamp = model.getProperties().getProperty("project.build.outputTimestamp"); if (buildOutputTimestamp == null || isEmpty(buildOutputTimestamp)) { diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/SetPropertyMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/SetPropertyMojo.java index fecc9716e8..ddf5d9ecca 100644 --- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/SetPropertyMojo.java +++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/SetPropertyMojo.java @@ -37,7 +37,7 @@ import org.codehaus.mojo.versions.api.PropertyVersions; import org.codehaus.mojo.versions.api.VersionsHelper; import org.codehaus.mojo.versions.api.recording.ChangeRecorder; -import org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader; +import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader; import org.codehaus.mojo.versions.utils.PropertiesVersionsFileReader; import org.eclipse.aether.RepositorySystem; @@ -108,9 +108,9 @@ public SetPropertyMojo( * @throws MojoExecutionException when things go wrong * @throws MojoFailureException when things go wrong in a very bad way * @throws XMLStreamException when things go wrong with XML streaming - * @see AbstractVersionsUpdaterMojo#update(ModifiedPomXMLEventReader) + * @see AbstractVersionsUpdaterMojo#update(MutableXMLStreamReader) */ - protected void update(ModifiedPomXMLEventReader pom) + protected void update(MutableXMLStreamReader pom) throws MojoExecutionException, MojoFailureException, XMLStreamException { Property[] propertiesConfig; String properties; @@ -144,7 +144,7 @@ protected void update(ModifiedPomXMLEventReader pom) update(pom, propertiesConfig, properties); } - private void update(ModifiedPomXMLEventReader pom, Property[] propertiesConfig, String properties) + private void update(MutableXMLStreamReader pom, Property[] propertiesConfig, String properties) throws MojoExecutionException, XMLStreamException { Map propertyVersions = this.getHelper() .getVersionPropertiesMap(VersionsHelper.VersionPropertiesMapRequest.builder() diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/SetScmTagMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/SetScmTagMojo.java index 5d8fa051aa..e9e51338bf 100644 --- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/SetScmTagMojo.java +++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/SetScmTagMojo.java @@ -17,7 +17,7 @@ import org.apache.maven.wagon.Wagon; import org.codehaus.mojo.versions.api.PomHelper; import org.codehaus.mojo.versions.api.recording.ChangeRecorder; -import org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader; +import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader; import org.eclipse.aether.RepositorySystem; import static org.apache.commons.lang3.StringUtils.isAllBlank; @@ -90,10 +90,11 @@ public void execute() throws MojoExecutionException, MojoFailureException { } @Override - protected void update(ModifiedPomXMLEventReader pom) + protected void update(MutableXMLStreamReader pom) throws MojoExecutionException, MojoFailureException, XMLStreamException { try { - Scm scm = PomHelper.getRawModel(pom).getScm(); + Scm scm = PomHelper.getRawModel(pom.getSource(), pom.getFileName().toFile()) + .getScm(); if (scm == null) { throw new MojoFailureException("No was present"); } diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UnlockSnapshotsMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UnlockSnapshotsMojo.java index 979cff0703..259215fdae 100644 --- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UnlockSnapshotsMojo.java +++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UnlockSnapshotsMojo.java @@ -37,7 +37,7 @@ import org.codehaus.mojo.versions.api.recording.ChangeRecorder; import org.codehaus.mojo.versions.api.recording.DependencyChangeRecord; import org.codehaus.mojo.versions.recording.DefaultDependencyChangeRecord; -import org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader; +import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader; import org.eclipse.aether.RepositorySystem; /** @@ -75,9 +75,9 @@ public UnlockSnapshotsMojo( * @throws MojoExecutionException when things go wrong * @throws MojoFailureException when things go wrong in a very bad way * @throws XMLStreamException when things go wrong with XML streaming - * @see AbstractVersionsUpdaterMojo#update(ModifiedPomXMLEventReader) + * @see AbstractVersionsUpdaterMojo#update(MutableXMLStreamReader) */ - protected void update(ModifiedPomXMLEventReader pom) + protected void update(MutableXMLStreamReader pom) throws MojoExecutionException, MojoFailureException, XMLStreamException { try { if (isProcessingDependencyManagement()) { @@ -102,7 +102,7 @@ protected void update(ModifiedPomXMLEventReader pom) } private void unlockSnapshots( - ModifiedPomXMLEventReader pom, List dependencies, DependencyChangeRecord.ChangeKind changeKind) + MutableXMLStreamReader pom, List dependencies, DependencyChangeRecord.ChangeKind changeKind) throws XMLStreamException, MojoExecutionException { for (Dependency dep : dependencies) { if (isExcludeReactor() && isProducedByReactor(dep)) { @@ -144,7 +144,7 @@ private void unlockSnapshots( } } - private void unlockParentSnapshot(ModifiedPomXMLEventReader pom, MavenProject parent) + private void unlockParentSnapshot(MutableXMLStreamReader pom, MavenProject parent) throws XMLStreamException, MojoExecutionException { if (parent == null) { getLog().info("Project does not have a parent"); diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UpdateChildModulesMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UpdateChildModulesMojo.java index d8c0a6ae46..4aa331ed1e 100644 --- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UpdateChildModulesMojo.java +++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UpdateChildModulesMojo.java @@ -38,7 +38,7 @@ import org.apache.maven.wagon.Wagon; import org.codehaus.mojo.versions.api.PomHelper; import org.codehaus.mojo.versions.api.recording.ChangeRecorder; -import org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader; +import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader; import org.eclipse.aether.RepositorySystem; /** @@ -172,7 +172,7 @@ public void execute() throws MojoExecutionException, MojoFailureException { * @throws MojoFailureException when things go wrong. * @throws XMLStreamException when things go wrong. */ - protected synchronized void update(ModifiedPomXMLEventReader pom) + protected synchronized void update(MutableXMLStreamReader pom) throws MojoExecutionException, MojoFailureException, XMLStreamException { getLog().debug("Updating parent to " + sourceVersion); diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UpdateParentMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UpdateParentMojo.java index 8f37aa8393..b992255a55 100644 --- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UpdateParentMojo.java +++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UpdateParentMojo.java @@ -42,7 +42,7 @@ import org.codehaus.mojo.versions.api.recording.DependencyChangeRecord; import org.codehaus.mojo.versions.ordering.InvalidSegmentException; import org.codehaus.mojo.versions.recording.DefaultDependencyChangeRecord; -import org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader; +import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader; import org.codehaus.mojo.versions.utils.DefaultArtifactVersionCache; import org.codehaus.mojo.versions.utils.DependencyBuilder; import org.codehaus.mojo.versions.utils.SegmentUtils; @@ -145,10 +145,10 @@ public UpdateParentMojo( * @throws MojoExecutionException when things go wrong * @throws MojoFailureException when things go wrong in a very bad way * @throws XMLStreamException when things go wrong with XML streaming - * @see AbstractVersionsUpdaterMojo#update(ModifiedPomXMLEventReader) + * @see AbstractVersionsUpdaterMojo#update(MutableXMLStreamReader) * @since 1.0-alpha-1 */ - protected void update(ModifiedPomXMLEventReader pom) + protected void update(MutableXMLStreamReader pom) throws MojoExecutionException, MojoFailureException, XMLStreamException, VersionRetrievalException { if (getProject().getParent() == null) { getLog().info("Project does not have a parent"); diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UpdatePropertiesMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UpdatePropertiesMojo.java index 188eeb6dd9..a0adb196ca 100644 --- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UpdatePropertiesMojo.java +++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UpdatePropertiesMojo.java @@ -33,7 +33,7 @@ import org.codehaus.mojo.versions.api.Property; import org.codehaus.mojo.versions.api.VersionsHelper; import org.codehaus.mojo.versions.api.recording.ChangeRecorder; -import org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader; +import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader; import org.eclipse.aether.RepositorySystem; /** @@ -82,10 +82,10 @@ public UpdatePropertiesMojo( * @throws MojoExecutionException when things go wrong * @throws MojoFailureException when things go wrong in a very bad way * @throws XMLStreamException when things go wrong with XML streaming - * @see AbstractVersionsUpdaterMojo#update(ModifiedPomXMLEventReader) + * @see AbstractVersionsUpdaterMojo#update(MutableXMLStreamReader) * @since 1.0-alpha-1 */ - protected void update(ModifiedPomXMLEventReader pom) + protected void update(MutableXMLStreamReader pom) throws MojoExecutionException, MojoFailureException, XMLStreamException { update( pom, diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UpdatePropertiesMojoBase.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UpdatePropertiesMojoBase.java index bd635fe28a..b567ecebb4 100644 --- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UpdatePropertiesMojoBase.java +++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UpdatePropertiesMojoBase.java @@ -36,7 +36,7 @@ import org.codehaus.mojo.versions.ordering.InvalidSegmentException; import org.codehaus.mojo.versions.recording.DefaultDependencyChangeRecord; import org.codehaus.mojo.versions.recording.DefaultPropertyChangeRecord; -import org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader; +import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader; import org.eclipse.aether.RepositorySystem; import static java.util.Optional.empty; @@ -115,7 +115,7 @@ public UpdatePropertiesMojoBase( super(artifactHandlerManager, repositorySystem, wagonMap, changeRecorders); } - protected void update(ModifiedPomXMLEventReader pom, Map propertyVersions) + protected void update(MutableXMLStreamReader pom, Map propertyVersions) throws XMLStreamException { for (Map.Entry entry : propertyVersions.entrySet()) { Property property = entry.getKey(); @@ -148,18 +148,17 @@ protected void update(ModifiedPomXMLEventReader pom, Map unchangedSegment1 = allowMajorUpdates && allowMinorUpdates && allowIncrementalUpdates + Optional unchangedSegment = allowMajorUpdates && allowMinorUpdates && allowIncrementalUpdates ? empty() : allowMinorUpdates && allowIncrementalUpdates ? of(MAJOR) : allowIncrementalUpdates ? of(MINOR) : of(INCREMENTAL); if (log != null && log.isDebugEnabled()) { - log.debug(unchangedSegment1 + log.debug(unchangedSegment .map(Segment::minorTo) .map(Segment::toString) .orElse("ALL") + " version changes allowed"); } - Optional unchangedSegment = unchangedSegment1; try { ArtifactVersion targetVersion = updatePropertyToNewestVersion( pom, property, version, currentVersion, allowDowngrade, unchangedSegment); diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UpdatePropertyMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UpdatePropertyMojo.java index 02088666e4..e03a6e0ad1 100644 --- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UpdatePropertyMojo.java +++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UpdatePropertyMojo.java @@ -33,7 +33,7 @@ import org.codehaus.mojo.versions.api.Property; import org.codehaus.mojo.versions.api.VersionsHelper; import org.codehaus.mojo.versions.api.recording.ChangeRecorder; -import org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader; +import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader; import org.eclipse.aether.RepositorySystem; /** @@ -85,10 +85,10 @@ public UpdatePropertyMojo( * @throws MojoExecutionException when things go wrong * @throws MojoFailureException when things go wrong in a very bad way * @throws XMLStreamException when things go wrong with XML streaming - * @see AbstractVersionsUpdaterMojo#update(ModifiedPomXMLEventReader) + * @see AbstractVersionsUpdaterMojo#update(MutableXMLStreamReader) * @since 1.0-alpha-1 */ - protected void update(ModifiedPomXMLEventReader pom) + protected void update(MutableXMLStreamReader pom) throws MojoExecutionException, MojoFailureException, XMLStreamException { update( pom, diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseDepVersionMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseDepVersionMojo.java index 6d5b75ed05..f195da38b7 100644 --- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseDepVersionMojo.java +++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseDepVersionMojo.java @@ -17,8 +17,11 @@ import javax.inject.Inject; import javax.xml.stream.XMLStreamException; +import javax.xml.transform.TransformerException; import java.io.IOException; +import java.io.Writer; +import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; @@ -35,6 +38,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager; @@ -52,7 +56,7 @@ import org.codehaus.mojo.versions.api.recording.ChangeRecorder; import org.codehaus.mojo.versions.api.recording.DependencyChangeRecord.ChangeKind; import org.codehaus.mojo.versions.recording.DefaultPropertyChangeRecord; -import org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader; +import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader; import org.codehaus.mojo.versions.utils.DependencyComparator; import org.codehaus.mojo.versions.utils.ModelNode; import org.eclipse.aether.RepositorySystem; @@ -114,7 +118,7 @@ public UseDepVersionMojo( @Override protected void validateInput() throws MojoExecutionException { super.validateInput(); - if (depVersion == null || depVersion.equals("")) { + if (StringUtils.isBlank(depVersion)) { throw new IllegalArgumentException( "depVersion must be supplied with use-specific-version, and cannot be blank."); } @@ -128,7 +132,7 @@ protected void validateInput() throws MojoExecutionException { } @Override - protected void update(ModifiedPomXMLEventReader pom) + protected void update(MutableXMLStreamReader pom) throws MojoExecutionException, MojoFailureException, XMLStreamException, VersionRetrievalException { // not used } @@ -139,26 +143,28 @@ public void execute() throws MojoExecutionException, MojoFailureException { List rawModels; try { - ModifiedPomXMLEventReader pomReader = newModifiedPomXER( - PomHelper.readXmlFile(getProject().getFile()), - getProject().getFile().toPath().toString()); - ModelNode rootNode = new ModelNode(PomHelper.getRawModel(pomReader), pomReader); + MutableXMLStreamReader pomReader = + new MutableXMLStreamReader(getProject().getFile().toPath()); + ModelNode rootNode = new ModelNode( + PomHelper.getRawModel(pomReader.getSource(), getProject().getFile()), pomReader); rawModels = PomHelper.getRawModelTree(rootNode, getLog()); // reversing to process depth-first Collections.reverse(rawModels); - } catch (IOException e) { - throw new MojoFailureException(e.getMessage(), e); - } - try { Set propertyBacklog = new HashSet<>(); Map> propertyConflicts = new HashMap<>(); for (ModelNode node : rawModels) { - processModel(node, propertyBacklog, propertyConflicts); + processModel( + node, + propertyBacklog, + propertyConflicts, + ofNullable(pomReader.getEncoding()) + .map(Charset::forName) + .orElse(Charset.defaultCharset())); } - propertyBacklog.forEach(p -> { - getLog().warn("Not updating property ${" + p + "}: defined in parent"); - }); + propertyBacklog.forEach(p -> getLog().warn("Not updating property ${" + p + "}: defined in parent")); + } catch (IOException | XMLStreamException | TransformerException e) { + throw new MojoFailureException(e.getMessage(), e); } catch (RuntimeException e) { if (e.getCause() instanceof MojoFailureException) { throw (MojoFailureException) e.getCause(); @@ -179,10 +185,14 @@ public void execute() throws MojoExecutionException, MojoFailureException { * which are associated with dependencies which do not fit the filter and thus may not * be changed. This is then used for conflict detection if a dependency to be changed * used one of these properties. Such a change is not allowed and must be reported instead. + * @param charset charset for file writing * @return {@code true} if the file has been changed */ protected boolean processModel( - ModelNode node, Set propertyBacklog, Map> propertyConflicts) + ModelNode node, + Set propertyBacklog, + Map> propertyConflicts, + Charset charset) throws MojoFailureException, MojoExecutionException { // 1) process the properties carried over from children propertyBacklog.removeIf(p -> updatePropertyValue(node, p)); @@ -225,7 +235,7 @@ protected boolean processModel( e); } - if (node.getModifiedPomXMLEventReader().isModified()) { + if (node.getMutableXMLStreamReader().isModified()) { if (generateBackupPoms) { Objects.requireNonNull(node.getModel().getPomFile()); Objects.requireNonNull(node.getModel().getPomFile().toPath().getParent()); @@ -252,10 +262,9 @@ protected boolean processModel( } else { getLog().debug("Skipping the generation of a backup file"); } - try { - writeFile( - node.getModel().getPomFile(), - node.getModifiedPomXMLEventReader().asStringBuilder()); + try (Writer writer = + Files.newBufferedWriter(node.getModel().getPomFile().toPath(), charset)) { + writer.write(node.getMutableXMLStreamReader().getSource()); } catch (IOException e) { throw new MojoFailureException( "Unable to write the changed file " + node.getModel().getPomFile(), e); @@ -271,7 +280,7 @@ protected boolean processModel( e); } - return node.getModifiedPomXMLEventReader().isModified(); + return node.getMutableXMLStreamReader().isModified(); } private static List getDependencies(Model model) { @@ -288,7 +297,7 @@ private static List getDependencies(Model model) { } /** - *

Will process the given module tree node, updating the {@link ModifiedPomXMLEventReader} associated with the + *

Will process the given module tree node, updating the {@link MutableXMLStreamReader} associated with the * node if it finds a dependency matching the filter that needs to be changed or, if {@link #processProperties} * is {@code true}, a property value that can be updated.

*

The method will use the set passed as the {@code backlog} argument to store the properties which it needs @@ -311,7 +320,7 @@ private static List getDependencies(Model model) { * be changed. This is then used for conflict detection if a dependency to be changed * used one of these properties. Such a change is not allowed and must be reported instead. * @throws MojoExecutionException thrown if a version may not be changed - * @throws XMLStreamException thrown if a {@link ModifiedPomXMLEventReader} can't be updated + * @throws XMLStreamException thrown if a {@link MutableXMLStreamReader} can't be updated * @throws VersionRetrievalException thrown if dependency versions cannot be retrieved */ private void useDepVersion( @@ -377,7 +386,7 @@ private void useDepVersion( } } if (!propertyName.isPresent()) { - updateDependencyVersion(node.getModifiedPomXMLEventReader(), dep, depVersion, changeKind); + updateDependencyVersion(node.getMutableXMLStreamReader(), dep, depVersion, changeKind); } else { // propertyName is present ofNullable(propertyConflicts.get(propertyName.get())) @@ -427,14 +436,14 @@ private boolean updatePropertyValue(ModelNode node, String property) { node.getModel().getProfiles().stream() .map(profile -> new ImmutablePair<>(profile, profile.getProperties())) .map(pair -> ofNullable(pair.getRight().getProperty(property)) - .map(value -> new ImmutablePair(pair.getLeft(), value)) + .map(value -> new ImmutablePair<>(pair.getLeft(), value)) .orElse(null))) // and processing them .filter(Objects::nonNull) .map(pair -> { try { boolean result = PomHelper.setPropertyVersion( - node.getModifiedPomXMLEventReader(), + node.getMutableXMLStreamReader(), ofNullable(pair.getLeft()).map(Profile::getId).orElse(null), property, depVersion); diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseLatestReleasesMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseLatestReleasesMojo.java index a45751897c..05faf42852 100644 --- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseLatestReleasesMojo.java +++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseLatestReleasesMojo.java @@ -44,7 +44,7 @@ import org.codehaus.mojo.versions.api.recording.ChangeRecorder; import org.codehaus.mojo.versions.api.recording.DependencyChangeRecord; import org.codehaus.mojo.versions.ordering.InvalidSegmentException; -import org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader; +import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader; import org.eclipse.aether.RepositorySystem; import static java.util.Collections.singletonList; @@ -123,9 +123,9 @@ public UseLatestReleasesMojo( * @throws org.apache.maven.plugin.MojoExecutionException when things go wrong * @throws org.apache.maven.plugin.MojoFailureException when things go wrong in a very bad way * @throws javax.xml.stream.XMLStreamException when things go wrong with XML streaming - * @see org.codehaus.mojo.versions.AbstractVersionsUpdaterMojo#update(org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader) + * @see org.codehaus.mojo.versions.AbstractVersionsUpdaterMojo#update(MutableXMLStreamReader) */ - protected void update(ModifiedPomXMLEventReader pom) + protected void update(MutableXMLStreamReader pom) throws MojoExecutionException, MojoFailureException, XMLStreamException, VersionRetrievalException { try { if (isProcessingDependencyManagement()) { @@ -150,7 +150,7 @@ protected void update(ModifiedPomXMLEventReader pom) } private void useLatestReleases( - ModifiedPomXMLEventReader pom, + MutableXMLStreamReader pom, Collection dependencies, DependencyChangeRecord.ChangeKind changeKind) throws XMLStreamException, MojoExecutionException, VersionRetrievalException { @@ -163,18 +163,17 @@ private void useLatestReleases( log.info("Assuming allowMajorUpdates false because allowMinorUpdates is false."); } - Optional unchangedSegment1 = allowMajorUpdates && allowMinorUpdates && allowIncrementalUpdates + Optional unchangedSegment = allowMajorUpdates && allowMinorUpdates && allowIncrementalUpdates ? empty() : allowMinorUpdates && allowIncrementalUpdates ? of(MAJOR) : allowIncrementalUpdates ? of(MINOR) : of(INCREMENTAL); if (log != null && log.isDebugEnabled()) { - log.debug(unchangedSegment1 + log.debug(unchangedSegment .map(Segment::minorTo) .map(Segment::toString) .orElse("ALL") + " version changes allowed"); } - Optional unchangedSegment = unchangedSegment1; useLatestVersions( pom, diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseLatestSnapshotsMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseLatestSnapshotsMojo.java index 847fc3c739..dad9137582 100644 --- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseLatestSnapshotsMojo.java +++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseLatestSnapshotsMojo.java @@ -40,7 +40,7 @@ import org.codehaus.mojo.versions.api.recording.ChangeRecorder; import org.codehaus.mojo.versions.api.recording.DependencyChangeRecord; import org.codehaus.mojo.versions.ordering.InvalidSegmentException; -import org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader; +import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader; import org.eclipse.aether.RepositorySystem; import static java.util.Collections.singletonList; @@ -102,9 +102,9 @@ public UseLatestSnapshotsMojo( * @throws org.apache.maven.plugin.MojoExecutionException when things go wrong * @throws org.apache.maven.plugin.MojoFailureException when things go wrong in a very bad way * @throws javax.xml.stream.XMLStreamException when things go wrong with XML streaming - * @see AbstractVersionsUpdaterMojo#update(org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader) + * @see AbstractVersionsUpdaterMojo#update(MutableXMLStreamReader) */ - protected void update(ModifiedPomXMLEventReader pom) + protected void update(MutableXMLStreamReader pom) throws MojoExecutionException, MojoFailureException, XMLStreamException, VersionRetrievalException { try { if (isProcessingDependencyManagement()) { @@ -129,7 +129,7 @@ protected void update(ModifiedPomXMLEventReader pom) } private void useLatestSnapshots( - ModifiedPomXMLEventReader pom, + MutableXMLStreamReader pom, Collection dependencies, DependencyChangeRecord.ChangeKind changeKind) throws XMLStreamException, MojoExecutionException, VersionRetrievalException { @@ -142,18 +142,17 @@ private void useLatestSnapshots( log.info("Assuming allowMajorUpdates false because allowMinorUpdates is false."); } - Optional unchangedSegment1 = allowMajorUpdates && allowMinorUpdates && allowIncrementalUpdates + Optional unchangedSegment = allowMajorUpdates && allowMinorUpdates && allowIncrementalUpdates ? empty() : allowMinorUpdates && allowIncrementalUpdates ? of(MAJOR) : allowIncrementalUpdates ? of(MINOR) : of(INCREMENTAL); if (log != null && log.isDebugEnabled()) { - log.debug(unchangedSegment1 + log.debug(unchangedSegment .map(Segment::minorTo) .map(Segment::toString) .orElse("ALL") + " version changes allowed"); } - Optional unchangedSegment = unchangedSegment1; useLatestVersions( pom, diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseLatestVersionsMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseLatestVersionsMojo.java index 665b081512..9b3669f7cd 100644 --- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseLatestVersionsMojo.java +++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseLatestVersionsMojo.java @@ -38,7 +38,7 @@ import org.codehaus.mojo.versions.api.recording.ChangeRecorder; import org.codehaus.mojo.versions.api.recording.DependencyChangeRecord; import org.codehaus.mojo.versions.ordering.InvalidSegmentException; -import org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader; +import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader; import org.eclipse.aether.RepositorySystem; import static java.util.Collections.singletonList; @@ -117,9 +117,9 @@ public void execute() throws MojoExecutionException, MojoFailureException { * @throws org.apache.maven.plugin.MojoExecutionException when things go wrong * @throws org.apache.maven.plugin.MojoFailureException when things go wrong in a very bad way * @throws javax.xml.stream.XMLStreamException when things go wrong with XML streaming - * @see AbstractVersionsUpdaterMojo#update(org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader) + * @see AbstractVersionsUpdaterMojo#update(MutableXMLStreamReader) */ - protected void update(ModifiedPomXMLEventReader pom) + protected void update(MutableXMLStreamReader pom) throws MojoExecutionException, MojoFailureException, XMLStreamException, VersionRetrievalException { try { if (isProcessingDependencyManagement()) { @@ -144,7 +144,7 @@ protected void update(ModifiedPomXMLEventReader pom) } private void useLatestVersions( - ModifiedPomXMLEventReader pom, + MutableXMLStreamReader pom, Collection dependencies, DependencyChangeRecord.ChangeKind changeKind) throws XMLStreamException, MojoExecutionException, VersionRetrievalException { @@ -157,18 +157,17 @@ private void useLatestVersions( log.info("Assuming allowMajorUpdates false because allowMinorUpdates is false."); } - Optional unchangedSegment1 = allowMajorUpdates && allowMinorUpdates && allowIncrementalUpdates + Optional unchangedSegment = allowMajorUpdates && allowMinorUpdates && allowIncrementalUpdates ? empty() : allowMinorUpdates && allowIncrementalUpdates ? of(MAJOR) : allowIncrementalUpdates ? of(MINOR) : of(INCREMENTAL); if (log != null && log.isDebugEnabled()) { - log.debug(unchangedSegment1 + log.debug(unchangedSegment .map(Segment::minorTo) .map(Segment::toString) .orElse("ALL") + " version changes allowed"); } - Optional unchangedSegment = unchangedSegment1; useLatestVersions( pom, diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseLatestVersionsMojoBase.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseLatestVersionsMojoBase.java index 413fd1adc0..c28897beea 100644 --- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseLatestVersionsMojoBase.java +++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseLatestVersionsMojoBase.java @@ -34,7 +34,7 @@ import org.codehaus.mojo.versions.api.VersionRetrievalException; import org.codehaus.mojo.versions.api.recording.ChangeRecorder; import org.codehaus.mojo.versions.api.recording.DependencyChangeRecord; -import org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader; +import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader; import org.codehaus.mojo.versions.utils.DefaultArtifactVersionCache; import org.eclipse.aether.RepositorySystem; @@ -67,7 +67,7 @@ public UseLatestVersionsMojoBase( */ @SafeVarargs protected final void useLatestVersions( - ModifiedPomXMLEventReader pom, + MutableXMLStreamReader pom, Collection dependencies, BiFunction> newestVersionProducer, DependencyChangeRecord.ChangeKind changeKind, diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseNextReleasesMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseNextReleasesMojo.java index 2fd09ea769..b71f25e78f 100644 --- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseNextReleasesMojo.java +++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseNextReleasesMojo.java @@ -37,7 +37,7 @@ import org.codehaus.mojo.versions.api.recording.ChangeRecorder; import org.codehaus.mojo.versions.api.recording.DependencyChangeRecord; import org.codehaus.mojo.versions.ordering.InvalidSegmentException; -import org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader; +import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader; import org.eclipse.aether.RepositorySystem; import static java.util.Collections.singletonList; @@ -78,9 +78,9 @@ public UseNextReleasesMojo( * @throws org.apache.maven.plugin.MojoExecutionException when things go wrong * @throws org.apache.maven.plugin.MojoFailureException when things go wrong in a very bad way * @throws javax.xml.stream.XMLStreamException when things go wrong with XML streaming - * @see AbstractVersionsUpdaterMojo#update(org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader) + * @see AbstractVersionsUpdaterMojo#update(MutableXMLStreamReader) */ - protected void update(ModifiedPomXMLEventReader pom) + protected void update(MutableXMLStreamReader pom) throws MojoExecutionException, MojoFailureException, XMLStreamException, VersionRetrievalException { try { if (isProcessingDependencyManagement()) { @@ -104,7 +104,7 @@ protected void update(ModifiedPomXMLEventReader pom) } private void useNextReleases( - ModifiedPomXMLEventReader pom, + MutableXMLStreamReader pom, Collection dependencies, DependencyChangeRecord.ChangeKind changeKind) throws XMLStreamException, MojoExecutionException, VersionRetrievalException { diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseNextSnapshotsMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseNextSnapshotsMojo.java index 17c78bc6c0..de093e7aa7 100644 --- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseNextSnapshotsMojo.java +++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseNextSnapshotsMojo.java @@ -39,7 +39,7 @@ import org.codehaus.mojo.versions.api.recording.ChangeRecorder; import org.codehaus.mojo.versions.api.recording.DependencyChangeRecord; import org.codehaus.mojo.versions.ordering.InvalidSegmentException; -import org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader; +import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader; import org.eclipse.aether.RepositorySystem; import static java.util.Collections.singletonList; @@ -103,9 +103,9 @@ public UseNextSnapshotsMojo( * @throws org.apache.maven.plugin.MojoExecutionException when things go wrong * @throws org.apache.maven.plugin.MojoFailureException when things go wrong in a very bad way * @throws javax.xml.stream.XMLStreamException when things go wrong with XML streaming - * @see org.codehaus.mojo.versions.AbstractVersionsUpdaterMojo#update(org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader) + * @see org.codehaus.mojo.versions.AbstractVersionsUpdaterMojo#update(MutableXMLStreamReader) */ - protected void update(ModifiedPomXMLEventReader pom) + protected void update(MutableXMLStreamReader pom) throws MojoExecutionException, MojoFailureException, XMLStreamException, VersionRetrievalException { try { DependencyManagement dependencyManagement = @@ -128,7 +128,7 @@ protected void update(ModifiedPomXMLEventReader pom) } private void useNextSnapshots( - ModifiedPomXMLEventReader pom, + MutableXMLStreamReader pom, Collection dependencies, DependencyChangeRecord.ChangeKind changeKind) throws XMLStreamException, MojoExecutionException, VersionRetrievalException { @@ -141,18 +141,17 @@ private void useNextSnapshots( log.info("Assuming allowMajorUpdates false because allowMinorUpdates is false."); } - Optional unchangedSegment1 = allowMajorUpdates && allowMinorUpdates && allowIncrementalUpdates + Optional unchangedSegment = allowMajorUpdates && allowMinorUpdates && allowIncrementalUpdates ? empty() : allowMinorUpdates && allowIncrementalUpdates ? of(MAJOR) : allowIncrementalUpdates ? of(MINOR) : of(INCREMENTAL); if (log != null && log.isDebugEnabled()) { - log.debug(unchangedSegment1 + log.debug(unchangedSegment .map(Segment::minorTo) .map(Segment::toString) .orElse("ALL") + " version changes allowed"); } - Optional unchangedSegment = unchangedSegment1; useLatestVersions( pom, diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseNextVersionsMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseNextVersionsMojo.java index 1b46270940..ab54807649 100644 --- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseNextVersionsMojo.java +++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseNextVersionsMojo.java @@ -37,7 +37,7 @@ import org.codehaus.mojo.versions.api.recording.ChangeRecorder; import org.codehaus.mojo.versions.api.recording.DependencyChangeRecord; import org.codehaus.mojo.versions.ordering.InvalidSegmentException; -import org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader; +import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader; import org.eclipse.aether.RepositorySystem; import static java.util.Collections.singletonList; @@ -80,9 +80,9 @@ public UseNextVersionsMojo( * @throws org.apache.maven.plugin.MojoExecutionException when things go wrong * @throws org.apache.maven.plugin.MojoFailureException when things go wrong in a very bad way * @throws javax.xml.stream.XMLStreamException when things go wrong with XML streaming - * @see org.codehaus.mojo.versions.AbstractVersionsUpdaterMojo#update(org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader) + * @see org.codehaus.mojo.versions.AbstractVersionsUpdaterMojo#update(MutableXMLStreamReader) */ - protected void update(ModifiedPomXMLEventReader pom) + protected void update(MutableXMLStreamReader pom) throws MojoExecutionException, MojoFailureException, XMLStreamException, VersionRetrievalException { try { if (isProcessingDependencyManagement()) { @@ -104,7 +104,7 @@ protected void update(ModifiedPomXMLEventReader pom) } private void useNextVersions( - ModifiedPomXMLEventReader pom, + MutableXMLStreamReader pom, Collection dependencies, DependencyChangeRecord.ChangeKind changeKind) throws XMLStreamException, MojoExecutionException, VersionRetrievalException { diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseReactorMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseReactorMojo.java index 0808ce0898..3fd045f25f 100644 --- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseReactorMojo.java +++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseReactorMojo.java @@ -39,7 +39,7 @@ import org.codehaus.mojo.versions.api.PomHelper; import org.codehaus.mojo.versions.api.VersionRetrievalException; import org.codehaus.mojo.versions.api.recording.ChangeRecorder; -import org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader; +import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader; import org.eclipse.aether.RepositorySystem; /** @@ -67,9 +67,9 @@ public UseReactorMojo( * @throws org.apache.maven.plugin.MojoExecutionException when things go wrong * @throws org.apache.maven.plugin.MojoFailureException when things go wrong in a very bad way * @throws javax.xml.stream.XMLStreamException when things go wrong with XML streaming - * @see AbstractVersionsUpdaterMojo#update(org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader) + * @see AbstractVersionsUpdaterMojo#update(MutableXMLStreamReader) */ - protected void update(ModifiedPomXMLEventReader pom) + protected void update(MutableXMLStreamReader pom) throws MojoExecutionException, MojoFailureException, XMLStreamException, VersionRetrievalException { try { if (isProcessingParent() && getProject().hasParent()) { @@ -90,7 +90,7 @@ protected void update(ModifiedPomXMLEventReader pom) } } - private void useReactor(ModifiedPomXMLEventReader pom, Collection dependencies) + private void useReactor(MutableXMLStreamReader pom, Collection dependencies) throws XMLStreamException, MojoExecutionException, VersionRetrievalException { for (Dependency dep : dependencies) { @@ -100,19 +100,18 @@ private void useReactor(ModifiedPomXMLEventReader pom, Collection de } for (MavenProject reactorProject : reactorProjects) { - MavenProject project = reactorProject; - if (StringUtils.equals(project.getGroupId(), dep.getGroupId()) - && StringUtils.equals(project.getArtifactId(), dep.getArtifactId()) - && !StringUtils.equals(project.getVersion(), dep.getVersion())) { + if (StringUtils.equals(reactorProject.getGroupId(), dep.getGroupId()) + && StringUtils.equals(reactorProject.getArtifactId(), dep.getArtifactId()) + && !StringUtils.equals(reactorProject.getVersion(), dep.getVersion())) { if (PomHelper.setDependencyVersion( pom, dep.getGroupId(), dep.getArtifactId(), dep.getVersion(), - project.getVersion(), + reactorProject.getVersion(), getProject().getModel(), getLog())) { - getLog().info("Updated " + toString(dep) + " to version " + project.getVersion()); + getLog().info("Updated " + toString(dep) + " to version " + reactorProject.getVersion()); } break; } @@ -120,7 +119,7 @@ private void useReactor(ModifiedPomXMLEventReader pom, Collection de } } - private void useReactor(ModifiedPomXMLEventReader pom, MavenProject parent) + private void useReactor(MutableXMLStreamReader pom, MavenProject parent) throws XMLStreamException, VersionRetrievalException { for (MavenProject project : reactorProjects) { if (StringUtils.equals(project.getGroupId(), parent.getGroupId()) diff --git a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseReleasesMojo.java b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseReleasesMojo.java index a115a84f47..ce1249f2c9 100644 --- a/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseReleasesMojo.java +++ b/versions-maven-plugin/src/main/java/org/codehaus/mojo/versions/UseReleasesMojo.java @@ -40,7 +40,7 @@ import org.codehaus.mojo.versions.api.VersionRetrievalException; import org.codehaus.mojo.versions.api.recording.ChangeRecorder; import org.codehaus.mojo.versions.api.recording.DependencyChangeRecord; -import org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader; +import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader; import org.eclipse.aether.RepositorySystem; import static java.util.Collections.singletonList; @@ -90,9 +90,9 @@ public UseReleasesMojo( * @throws org.apache.maven.plugin.MojoExecutionException when things go wrong * @throws org.apache.maven.plugin.MojoFailureException when things go wrong in a very bad way * @throws javax.xml.stream.XMLStreamException when things go wrong with XML streaming - * @see org.codehaus.mojo.versions.AbstractVersionsUpdaterMojo#update(org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader) + * @see org.codehaus.mojo.versions.AbstractVersionsUpdaterMojo#update(MutableXMLStreamReader) */ - protected void update(ModifiedPomXMLEventReader pom) + protected void update(MutableXMLStreamReader pom) throws MojoExecutionException, MojoFailureException, XMLStreamException, VersionRetrievalException { try { if (isProcessingDependencyManagement()) { @@ -117,7 +117,7 @@ protected void update(ModifiedPomXMLEventReader pom) } private void useReleases( - ModifiedPomXMLEventReader pom, + MutableXMLStreamReader pom, Collection dependencies, DependencyChangeRecord.ChangeKind changeKind) throws XMLStreamException, MojoExecutionException, VersionRetrievalException { @@ -165,7 +165,7 @@ private void useReleases( } private Optional findReleaseVersion( - ModifiedPomXMLEventReader pom, + MutableXMLStreamReader pom, Dependency dep, String version, String releaseVersion, diff --git a/versions-maven-plugin/src/test/java/org/codehaus/mojo/versions/LockSnapshotsMojoTest.java b/versions-maven-plugin/src/test/java/org/codehaus/mojo/versions/LockSnapshotsMojoTest.java index 9d61d1d043..613713be2c 100644 --- a/versions-maven-plugin/src/test/java/org/codehaus/mojo/versions/LockSnapshotsMojoTest.java +++ b/versions-maven-plugin/src/test/java/org/codehaus/mojo/versions/LockSnapshotsMojoTest.java @@ -27,6 +27,7 @@ import org.apache.maven.plugin.testing.stubs.DefaultArtifactHandlerStub; import org.apache.maven.project.MavenProject; import org.codehaus.mojo.versions.api.PomHelper; +import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader; import org.codehaus.mojo.versions.utils.DependencyBuilder; import org.codehaus.mojo.versions.utils.MockUtils; import org.eclipse.aether.RepositorySystem; @@ -120,7 +121,7 @@ public void testNoTimestampedParentFoundNull() LockSnapshotsMojo mojo = createMojo(repositorySystem); try (MockedStatic pomHelper = mockStatic(PomHelper.class)) { pomHelper - .when(() -> PomHelper.setProjectParentVersion(any(), any())) + .when(() -> PomHelper.setProjectParentVersion(any(MutableXMLStreamReader.class), any())) .thenThrow(new RuntimeException("Not supposed to modify the parent")); mojo.lockParentSnapshot( null, @@ -153,7 +154,7 @@ public void testNoTimestampedParentFoundSameVersion() LockSnapshotsMojo mojo = createMojo(repositorySystem); try (MockedStatic pomHelper = mockStatic(PomHelper.class)) { pomHelper - .when(() -> PomHelper.setProjectParentVersion(any(), any())) + .when(() -> PomHelper.setProjectParentVersion(any(MutableXMLStreamReader.class), any())) .thenThrow(new RuntimeException("Not supposed to modify the parent")); mojo.lockParentSnapshot( null, diff --git a/versions-maven-plugin/src/test/java/org/codehaus/mojo/versions/RewriteWithStAXTest.java b/versions-maven-plugin/src/test/java/org/codehaus/mojo/versions/RewriteWithStAXTest.java deleted file mode 100644 index 459a55ea71..0000000000 --- a/versions-maven-plugin/src/test/java/org/codehaus/mojo/versions/RewriteWithStAXTest.java +++ /dev/null @@ -1,293 +0,0 @@ -package org.codehaus.mojo.versions; - -/* - * 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. - */ - -import javax.xml.stream.XMLEventReader; -import javax.xml.stream.XMLEventWriter; -import javax.xml.stream.XMLInputFactory; -import javax.xml.stream.XMLOutputFactory; -import javax.xml.stream.events.EndElement; -import javax.xml.stream.events.StartElement; -import javax.xml.stream.events.XMLEvent; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.nio.charset.StandardCharsets; -import java.util.Stack; - -import org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader; -import org.codehaus.stax2.XMLInputFactory2; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; - -/** - * Basic tests for rewriting XML with a StAX (JSR-173) implementation. - * - * @author Stephen Connolly - */ -public class RewriteWithStAXTest { - @Test - public void testBasic() throws Exception { - String input = "\n" + "\n\r\n\r\n\r\n\r" + " \r\n" - + " org.codehaus.mojo\n" - + " mojo-&sandbox-parent\n" + " 5-SNAPSHOT\r" - + " \r" + ""; - - byte[] rawInput = input.getBytes(StandardCharsets.UTF_8); - ByteArrayInputStream source = new ByteArrayInputStream(rawInput); - ByteArrayOutputStream dest = new ByteArrayOutputStream(); - XMLInputFactory inputFactory = XMLInputFactory2.newInstance(); - inputFactory.setProperty(XMLInputFactory2.P_PRESERVE_LOCATION, Boolean.TRUE); - XMLOutputFactory outputFactory = XMLOutputFactory.newInstance(); - XMLEventReader eventReader = inputFactory.createXMLEventReader(source); - XMLEventWriter eventWriter = outputFactory.createXMLEventWriter(dest, "utf-8"); - while (eventReader.hasNext()) { - eventWriter.add(eventReader.nextEvent()); - } - - String output = dest.toString("utf-8"); - - assertNotEquals("StAX implementation is not good enough", input, output); - } - - @Test - public void testReplace() throws Exception { - String input = "\n" + "\n\r\n\r\n\r\n\r" + " \r\n" - + " org.codehaus.mojo\n" - + " mojo-&sandbox-parent\n" + " 5-SNAPSHOT\r" - + " \r" + ""; - String expected = "\n" + "\n\r\n\r\n\r\n\r" + " \r\n" - + " org.codehaus.mojo\n" - + " my-artifact\n" - + " 5-SNAPSHOT\r" + " \r" + ""; - - StringBuilder output = new StringBuilder(input); - - XMLInputFactory inputFactory = XMLInputFactory2.newInstance(); - inputFactory.setProperty(XMLInputFactory2.P_PRESERVE_LOCATION, Boolean.TRUE); - ModifiedPomXMLEventReader eventReader = new ModifiedPomXMLEventReader(output, inputFactory, null); - while (eventReader.hasNext()) { - XMLEvent event = eventReader.nextEvent(); - if (event instanceof StartElement - && event.asStartElement().getName().getLocalPart().equals("artifactId")) { - eventReader.mark(0); - } - if (event instanceof EndElement - && event.asEndElement().getName().getLocalPart().equals("artifactId")) { - eventReader.mark(1); - if (eventReader.hasMark(0)) { - eventReader.replaceBetween(0, 1, "my-artifact"); - } - } - } - - assertEquals(expected, output.toString()); - } - - @SuppressWarnings({"checkstyle:MethodLength", "checkstyle:LineLength"}) - @Test - public void testReplaceFancy() throws Exception { - String input = - "\n" - + " 4.0.0\n" + "\n" + " \n" - + " org.codehaus.mojo\n" - + " mojo-sandbox-parent\n" - + " 5-SNAPSHOT\n" + " \n" + "\n" - + " org.codehaus.mojo\n" - + " versions-maven-plugin\n" - + " 1.0.0-alpha-1-SNAPSHOT\n" + " maven-plugin\n" - + "\n" - + " Versions Maven Plugin\n" + " \n" - + " Versions plugin for Maven 2. The versions plugin updates the versions of components in the pom.\n" - + " \n" + " 2008\n" + " \n" - + " \n" + " The Apache Software License, Version 2.0\n" - + " http://www.apache.org/licenses/LICENSE-2.0\n" - + " repo\n" + " \n" + " \n" + "\n" - + " \n" - + " scm:svn:http://svn.codehaus.org/mojo/trunk/sandbox/versions-maven-plugin\n" - + " scm:svn:https://svn.codehaus.org/mojo/trunk/sandbox/versions-maven-plugin\n" - + " http://svn.codehaus.org/mojo/trunk/sandbox/versions-maven-plugin\n" - + " \n" - + "\n" + " \n" + " \n" + " Stephen Connolly\n" - + " stephen.alan.connolly@gmail.com\n" + " \n" - + " Java Developer\n" + " \n" - + " 0\n" - + " \n" + " \n" + "\n" + " \n" - + " 2.0.6\n" + " \n" + "\n" + " \n" - + " \n" + " junit\n" - + " junit\n" - + " 3.8.1\n" + " test\n" + " \n" - + " \n" + " org.apache.maven\n" - + " maven-project\n" + " 2.0\n" - + " \n" + " \n" + " org.apache.maven\n" - + " maven-settings\n" + " 2.0\n" - + " \n" + " \n" + " org.apache.maven\n" - + " maven-plugin-api\n" + " 2.0\n" - + " \n" + " \n" - + " org.codehaus.plexus\n" - + " plexus-utils\n" + " 1.3\n" - + " \n" + " \n" - + " org.codehaus.plexus\n" - + " plexus-interactivity-api\n" - + " 1.0-alpha-6\n" - + " \n" + " \n" - + " plexus-utils\n" - + " plexus\n" + " \n" + " \n" - + " \n" + " \n" + " javax.xml.stream\n" - + " stax-api\n" + " 1.0-2\n" - + " \n" + " \n" + " stax\n" - + " stax\n" + " 1.1.1-dev\n" - + " \n" + " \n" + "\n" + " \n" + " \n" - + " \n" + " maven-plugin-plugin\n" - + " 2.3\n" + " \n" - + " versions\n" + " \n" - + " \n" - + " \n" + " \n" + "\n" + ""; - String expected = - "\n" - + " 4.0.0\n" + "\n" + " \n" - + " org.codehaus.mojo\n" - + " mojo-sandbox-parent\n" - + " 4\n" + " \n" + "\n" - + " org.codehaus.mojo\n" - + " versions-maven-plugin\n" - + " 1.0.0-alpha-1-SNAPSHOT\n" - + " maven-plugin\n" + "\n" + " Versions Maven Plugin\n" - + " \n" - + " Versions plugin for Maven 2. The versions plugin updates the versions of components in the pom.\n" - + " \n" + " 2008\n" + " \n" - + " \n" + " The Apache Software License, Version 2.0\n" - + " http://www.apache.org/licenses/LICENSE-2.0\n" - + " repo\n" + " \n" + " \n" + "\n" - + " \n" - + " scm:svn:http://svn.codehaus.org/mojo/trunk/sandbox/versions-maven-plugin\n" - + " scm:svn:https://svn.codehaus.org/mojo/trunk/sandbox/versions-maven-plugin\n" - + " http://svn.codehaus.org/mojo/trunk/sandbox/versions-maven-plugin\n" - + " \n" - + "\n" + " \n" + " \n" + " Stephen Connolly\n" - + " stephen.alan.connolly@gmail.com\n" + " \n" - + " Java Developer\n" + " \n" - + " 0\n" - + " \n" + " \n" + "\n" + " \n" - + " 2.0.6\n" + " \n" + "\n" + " \n" - + " \n" + " junit\n" - + " junit\n" - + " 3.8.2\n" + " test\n" + " \n" - + " \n" + " org.apache.maven\n" - + " maven-project\n" + " 2.0\n" - + " \n" + " \n" + " org.apache.maven\n" - + " maven-settings\n" + " 2.0\n" - + " \n" + " \n" + " org.apache.maven\n" - + " maven-plugin-api\n" + " 2.0\n" - + " \n" + " \n" - + " org.codehaus.plexus\n" - + " plexus-utils\n" + " 1.3\n" - + " \n" + " \n" - + " org.codehaus.plexus\n" - + " plexus-interactivity-api\n" - + " 1.0-alpha-6\n" - + " \n" + " \n" - + " plexus-utils\n" - + " plexus\n" + " \n" + " \n" - + " \n" + " \n" + " javax.xml.stream\n" - + " stax-api\n" + " 1.0-2\n" - + " \n" + " \n" + " stax\n" - + " stax\n" + " 1.1.1-dev\n" - + " \n" + " \n" + "\n" + " \n" + " \n" - + " \n" + " maven-plugin-plugin\n" - + " 2.3\n" + " \n" - + " versions\n" + " \n" - + " \n" - + " \n" + " \n" + "\n" + ""; - - StringBuilder output = new StringBuilder(input); - - XMLInputFactory inputFactory = XMLInputFactory2.newInstance(); - inputFactory.setProperty(XMLInputFactory2.P_PRESERVE_LOCATION, Boolean.TRUE); - ModifiedPomXMLEventReader eventReader = new ModifiedPomXMLEventReader(output, inputFactory, null); - - Stack stack = new Stack<>(); - String path = ""; - - while (eventReader.hasNext()) { - XMLEvent event = eventReader.nextEvent(); - if (event.isStartElement()) { - stack.push(path); - path += "/" + event.asStartElement().getName().getLocalPart(); - - if ("/project/parent/version".equals(path)) { - eventReader.mark(0); - } - } - if (event.isEndElement()) { - if ("/project/parent/version".equals(path)) { - eventReader.mark(1); - if (eventReader.hasMark(0)) { - eventReader.replaceBetween(0, 1, "4"); - } - } - path = stack.pop(); - } - } - - boolean inDependency = false; - boolean groupIdMatches = false; - boolean artifactIdMatches = false; - eventReader.rewind(); - - while (eventReader.hasNext()) { - XMLEvent event = eventReader.nextEvent(); - if (event.isStartElement()) { - String name = event.asStartElement().getName().getLocalPart(); - if (inDependency) { - if ("groupId".equals(name)) { - groupIdMatches = "junit".equals(eventReader.getElementText()); - } else if ("artifactId".equals(name)) { - artifactIdMatches = "junit".equals(eventReader.getElementText()); - } else if ("version".equals(name)) { - eventReader.mark(1); - } - } else if ("dependency".equals(name)) { - inDependency = true; - groupIdMatches = false; - artifactIdMatches = false; - } - } - if (event.isEndElement()) { - String name = event.asEndElement().getName().getLocalPart(); - if (inDependency) { - if ("version".equals(name)) { - eventReader.mark(2); - - } else if ("dependency".equals(name)) { - if (groupIdMatches && artifactIdMatches && eventReader.hasMark(1) && eventReader.hasMark(2)) { - eventReader.replaceBetween(1, 2, "3.8.2"); - } - inDependency = false; - } - } - } - } - - assertEquals(expected, output.toString()); - } -} diff --git a/versions-maven-plugin/src/test/java/org/codehaus/mojo/versions/SeparatePatternsForIncludesAnExcludesTest.java b/versions-maven-plugin/src/test/java/org/codehaus/mojo/versions/SeparatePatternsForIncludesAnExcludesTest.java index eddda8473c..1d7c0d9cc3 100644 --- a/versions-maven-plugin/src/test/java/org/codehaus/mojo/versions/SeparatePatternsForIncludesAnExcludesTest.java +++ b/versions-maven-plugin/src/test/java/org/codehaus/mojo/versions/SeparatePatternsForIncludesAnExcludesTest.java @@ -2,7 +2,7 @@ import java.util.List; -import org.codehaus.mojo.versions.rewriting.ModifiedPomXMLEventReader; +import org.codehaus.mojo.versions.rewriting.MutableXMLStreamReader; import org.junit.Before; import org.junit.Test; @@ -16,7 +16,7 @@ public class SeparatePatternsForIncludesAnExcludesTest { public void setUp() throws Exception { mojo = new AbstractVersionsDependencyUpdaterMojo(null, null, null, null) { @Override - protected void update(ModifiedPomXMLEventReader pom) {} + protected void update(MutableXMLStreamReader pom) {} }; } diff --git a/versions-maven-plugin/src/test/java/org/codehaus/mojo/versions/UpdatePropertiesMojoTestBase.java b/versions-maven-plugin/src/test/java/org/codehaus/mojo/versions/UpdatePropertiesMojoTestBase.java index b27290997f..9a4f073214 100644 --- a/versions-maven-plugin/src/test/java/org/codehaus/mojo/versions/UpdatePropertiesMojoTestBase.java +++ b/versions-maven-plugin/src/test/java/org/codehaus/mojo/versions/UpdatePropertiesMojoTestBase.java @@ -20,12 +20,10 @@ import java.nio.file.Path; import java.util.HashMap; -import java.util.Map; import org.apache.maven.plugin.Mojo; import org.apache.maven.plugin.testing.AbstractMojoTestCase; import org.apache.maven.plugin.testing.MojoRule; -import org.codehaus.mojo.versions.api.recording.ChangeRecorder; import org.codehaus.mojo.versions.utils.TestChangeRecorder; import org.eclipse.aether.RepositorySystem; import org.junit.After; @@ -72,9 +70,9 @@ protected T setUpMojo(String goal) throws Exception { T mojo = (T) mojoRule.lookupConfiguredMojo(pomDir.toFile(), goal); setVariableValueToObject(mojo, "repositorySystem", repositorySystem); setVariableValueToObject(mojo, "generateBackupPoms", false); - setVariableValueToObject(mojo, "changeRecorderFormat", "test"); - changeRecorder = (TestChangeRecorder) - ((Map) getVariableValueFromObject(mojo, "changeRecorders")).get("test"); + setVariableValueToObject(mojo, "changeRecorderFormat", "none"); + changeRecorder = new TestChangeRecorder(); + setVariableValueToObject(mojo, "changeRecorders", changeRecorder.asTestMap()); return (T) mojo; }