com.helger.maven.schematron.SchematronValidationMojo Maven / Gradle / Ivy
/*
* Copyright (C) 2014-2024 Philip Helger (www.helger.com)
* philip[at]helger[dot]com
*
* 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.
*/
package com.helger.maven.schematron;
import java.io.File;
import java.util.Locale;
import java.util.Map;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.util.DirectoryScanner;
import org.sonatype.plexus.build.incremental.BuildContext;
import com.helger.commons.annotation.ReturnsMutableCopy;
import com.helger.commons.annotation.Since;
import com.helger.commons.annotation.VisibleForTesting;
import com.helger.commons.collection.ArrayHelper;
import com.helger.commons.collection.impl.CommonsArrayList;
import com.helger.commons.collection.impl.CommonsHashMap;
import com.helger.commons.collection.impl.ICommonsList;
import com.helger.commons.collection.impl.ICommonsMap;
import com.helger.commons.error.IError;
import com.helger.commons.error.level.EErrorLevel;
import com.helger.commons.error.list.IErrorList;
import com.helger.commons.io.file.FileIOError;
import com.helger.commons.io.file.FileOperationManager;
import com.helger.commons.io.resource.FileSystemResource;
import com.helger.commons.string.StringHelper;
import com.helger.schematron.CSchematron;
import com.helger.schematron.ESchematronMode;
import com.helger.schematron.ISchematronResource;
import com.helger.schematron.pure.SchematronResourcePure;
import com.helger.schematron.pure.errorhandler.CollectingPSErrorHandler;
import com.helger.schematron.sch.SchematronResourceSCH;
import com.helger.schematron.sch.TransformerCustomizerSCH;
import com.helger.schematron.schxslt.xslt2.SchematronResourceSchXslt_XSLT2;
import com.helger.schematron.svrl.AbstractSVRLMessage;
import com.helger.schematron.svrl.SVRLHelper;
import com.helger.schematron.svrl.SVRLMarshaller;
import com.helger.schematron.svrl.jaxb.SchematronOutputType;
import com.helger.schematron.xslt.SchematronResourceXSLT;
import com.helger.xml.transform.CollectingTransformErrorListener;
import com.helger.xml.transform.TransformSourceFactory;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
/**
* Applies Schematron validation onto an XML file
*
* @author Philip Helger
*/
@SuppressFBWarnings ({ "NP_UNWRITTEN_FIELD", "UWF_UNWRITTEN_FIELD" })
@Mojo (name = "validate", defaultPhase = LifecyclePhase.PROCESS_RESOURCES, threadSafe = true)
public final class SchematronValidationMojo extends AbstractMojo
{
/**
* BuildContext for m2e (it's a pass-though straight to the filesystem when
* invoked from the Maven cli)
*/
@Component
private BuildContext buildContext;
/**
* The Maven Project.
*/
@Parameter (defaultValue = "${project}", readonly = true)
private MavenProject project;
/**
* The Schematron file. This may also be an XSLT file if it is precompiled.
*/
@Parameter (name = "schematronFile", required = true)
private File m_aSchematronFile;
/**
* The processing engine to use. Can be one of the following:
*
* - pure - for SCH files
* - schematron - for SCH files that will be converted to XSLT and applied
* from there.
* - xslt - apply pre-build XSLT files
*
*/
@Parameter (name = "schematronProcessingEngine", required = true)
private String m_sSchematronProcessingEngine = ESchematronMode.SCHEMATRON.getID ();
/**
* The directory where the XML files reside that are expected to match the
* Schematron rules.
*/
@Parameter (name = "xmlDirectory", required = true)
private File m_aXmlDirectory;
/**
* A pattern for the XML files that should be included. Can contain Ant-style
* wildcards and double wildcards. All files that match the pattern will be
* converted. Files in the xmlDirectory and its subdirectories will be
* considered.
*/
@Parameter (name = "xmlIncludes", defaultValue = "**/*.xml", required = true)
private String [] m_aXmlIncludes;
/**
* A pattern for the XML files that should be excluded. Can contain Ant-style
* wildcards and double wildcards. All files that match the pattern will NOT
* be converted. Only files in the xmlDirectory and its subdirectories will be
* considered.
*/
@Parameter (name = "xmlExcludes")
private String [] m_aXmlExcludes;
/**
* The SVRL path to write to (for positive tests). The filenames are based on
* the source XML filenames. If this parameter is not set, the SVRL files are
* not written.
*/
@Parameter (name = "svrlDirectory")
private File m_aSvrlDirectory;
/**
* The directory where the erroneous XML files reside that are expected to NOT
* match the Schematron rules.
*/
@Parameter (name = "xmlErrorDirectory")
private File m_aXmlErrorDirectory;
/**
* A pattern for the erroneous XML files that should be included. Can contain
* Ant-style wildcards and double wildcards. All files that match the pattern
* will be converted. Files in the xmlDirectory and its subdirectories will be
* considered.
*/
@Parameter (name = "xmlErrorIncludes", defaultValue = "**/*.xml")
private String [] m_aXmlErrorIncludes;
/**
* A pattern for the erroneous XML files that should be excluded. Can contain
* Ant-style wildcards and double wildcards. All files that match the pattern
* will NOT be converted. Only files in the xmlDirectory and its
* subdirectories will be considered.
*/
@Parameter (name = "xmlErrorExcludes")
private String [] m_aXmlErrorExcludes;
/**
* The SVRL path to write to (for negative tests). The filenames are based on
* the source XML filenames. If this parameter is not set, the SVRL files are
* not written.
*/
@Parameter (name = "svrlErrorDirectory")
private File m_aSvrlErrorDirectory;
/**
* Define the phase to be used for Schematron validation. By default the
* defaultPhase
attribute of the Schematron file is used. This
* phase name is only used if the processing engine pure
or
* schematron
are used.
*/
@Parameter (name = "phaseName")
private String m_sPhaseName;
/**
* Define the language code to be used for Schematron validation. Default is
* English. Supported language codes are: cs, de, en, fr, nl. This parameter
* takes only effect when using schematronProcessingEngine "schematron".
*/
@Parameter (name = "languageCode")
private String m_sLanguageCode;
/**
* Custom attributes to be used for the SCH to XSLT conversion. This parameter
* takes only effect when using schematronProcessingEngine "schematron" or
* "xslt".
*/
@Parameter (name = "parameters")
@Since ("5.0.2")
private Map m_aCustomParameters;
/**
* When validating multiple files, this flag indicates, whether validation
* should fail at the first file with an error (this is the default) or at the
* end only.
*/
@Parameter (name = "failFast", defaultValue = "true", required = true)
@Since ("5.0.5")
private boolean m_bFailFast = true;
/**
* Force the results to be cached. This only applies when Schematron to XSLT
* conversion is performed.
*/
@Parameter (name = "forceCacheResult", defaultValue = "false")
@Since ("5.2.1")
private boolean m_bForceCacheResult = TransformerCustomizerSCH.DEFAULT_FORCE_CACHE_RESULT;
/**
* Define if old namespace URIs should be supported or not. By default this is
* disabled. This parameter takes only effect when using
* schematronProcessingEngine "pure".
*/
@Parameter (name = "lenient", defaultValue = "false")
@Since ("5.4.1")
private boolean m_bLenient = CSchematron.DEFAULT_ALLOW_DEPRECATED_NAMESPACES;
/**
* true
to ignore all warnings, false
to also show
* warning messages,
*/
@Parameter (name = "ignoreWarnings", defaultValue = "false")
@Since ("7.1.3")
private boolean m_bIgnoreWarnings = false;
public void setSchematronFile (@Nonnull final File aFile)
{
m_aSchematronFile = aFile;
if (!m_aSchematronFile.isAbsolute ())
m_aSchematronFile = new File (project.getBasedir (), aFile.getPath ());
if (getLog ().isDebugEnabled ())
getLog ().debug ("Using Schematron file '" + m_aSchematronFile + "'");
}
public void setSchematronProcessingEngine (@Nullable final String sEngine)
{
final ESchematronMode eMode = ESchematronMode.getFromIDOrNull (sEngine);
m_sSchematronProcessingEngine = eMode == null ? null : eMode.getID ();
if (getLog ().isDebugEnabled ())
getLog ().debug ("Schematron processing mode set to '" + eMode + "'");
}
public void setXmlDirectory (@Nonnull final File aDir)
{
m_aXmlDirectory = aDir;
if (!m_aXmlDirectory.isAbsolute ())
m_aXmlDirectory = new File (project.getBasedir (), aDir.getPath ());
if (getLog ().isDebugEnabled ())
getLog ().debug ("Searching XML files in the directory '" + m_aXmlDirectory + "'");
}
public void setXmlIncludes (@Nullable final String [] aPattern)
{
m_aXmlIncludes = aPattern;
if (getLog ().isDebugEnabled ())
getLog ().debug ("Setting XML file includes to " +
StringHelper.imploder ().source (aPattern, x -> "'" + x + "'").separator (", ").build ());
}
public void setXmlExcludes (@Nullable final String [] aPattern)
{
m_aXmlExcludes = aPattern;
if (getLog ().isDebugEnabled ())
getLog ().debug ("Setting XML file excludes to " +
StringHelper.imploder ().source (aPattern, x -> "'" + x + "'").separator (", ").build ());
}
public void setSvrlDirectory (@Nonnull final File aDir)
{
m_aSvrlDirectory = aDir;
if (!m_aSvrlDirectory.isAbsolute ())
m_aSvrlDirectory = new File (project.getBasedir (), aDir.getPath ());
if (getLog ().isDebugEnabled ())
getLog ().debug ("Writing SVRL files to directory '" + m_aSvrlDirectory + "'");
}
public void setXmlErrorDirectory (@Nonnull final File aDir)
{
m_aXmlErrorDirectory = aDir;
if (!m_aXmlErrorDirectory.isAbsolute ())
m_aXmlErrorDirectory = new File (project.getBasedir (), aDir.getPath ());
if (getLog ().isDebugEnabled ())
getLog ().debug ("Searching erroneous XML files in the directory '" + m_aXmlDirectory + "'");
}
public void setXmlErrorIncludes (@Nullable final String [] aPattern)
{
m_aXmlErrorIncludes = aPattern;
if (getLog ().isDebugEnabled ())
getLog ().debug ("Setting erroneous XML file includes to " +
StringHelper.imploder ().source (aPattern, x -> "'" + x + "'").separator (", ").build ());
}
public void setXmlErrorExcludes (@Nullable final String [] aPattern)
{
m_aXmlErrorExcludes = aPattern;
if (getLog ().isDebugEnabled ())
getLog ().debug ("Setting erroneous XML file excludes to " +
StringHelper.imploder ().source (aPattern, x -> "'" + x + "'").separator (", ").build ());
}
public void setSvrlErrorDirectory (@Nonnull final File aDir)
{
m_aSvrlErrorDirectory = aDir;
if (!m_aSvrlErrorDirectory.isAbsolute ())
m_aSvrlErrorDirectory = new File (project.getBasedir (), aDir.getPath ());
if (getLog ().isDebugEnabled ())
getLog ().debug ("Writing erroneous SVRL files to directory '" + m_aSvrlErrorDirectory + "'");
}
public void setPhaseName (@Nullable final String sPhaseName)
{
m_sPhaseName = sPhaseName;
if (getLog ().isDebugEnabled ())
if (m_sPhaseName == null)
getLog ().debug ("Using default phase");
else
getLog ().debug ("Using the phase '" + m_sPhaseName + "'");
}
public void setLanguageCode (@Nullable final String sLanguageCode)
{
m_sLanguageCode = sLanguageCode;
if (getLog ().isDebugEnabled ())
if (m_sLanguageCode == null)
getLog ().debug ("Using default language code");
else
getLog ().debug ("Using the language code '" + m_sLanguageCode + "'");
}
public void setParameters (@Nullable final Map aParameters)
{
m_aCustomParameters = aParameters;
if (m_aCustomParameters == null || m_aCustomParameters.isEmpty ())
getLog ().debug ("Using no custom parameters");
else
getLog ().debug ("Using custom parameters " + m_aCustomParameters.toString ());
}
public void setFailFast (final boolean bFailFast)
{
m_bFailFast = bFailFast;
if (bFailFast)
getLog ().debug ("Failing at the first erroneous file");
else
getLog ().debug ("Failing after validating all files");
}
public void setForceCacheResult (final boolean bForceCacheResult)
{
m_bForceCacheResult = bForceCacheResult;
if (m_bForceCacheResult)
getLog ().debug ("Results are forcebly cached");
else
getLog ().debug ("Results not not forcebly cached");
}
public void setLenient (final boolean bLenient)
{
m_bLenient = bLenient;
if (m_bLenient)
getLog ().debug ("Old deprecated namespace URIs are supported");
else
getLog ().debug ("Old deprecated namespace URIs are not supported");
}
public void setIgnoreWarnings (final boolean bIgnoreWarnings)
{
m_bIgnoreWarnings = bIgnoreWarnings;
if (m_bIgnoreWarnings)
getLog ().debug ("Warnings will be ignored and only errors will be displayed");
else
getLog ().debug ("Warning and errors will be displayed");
}
@Nonnull
@ReturnsMutableCopy
@VisibleForTesting
ICommonsMap getParameters ()
{
return new CommonsHashMap <> (m_aCustomParameters);
}
/**
* @param aSch
* Schematron resource to apply on validation artefacts
* @param aXMLDirectory
* XML directory to be scanned
* @param aXMLIncludes
* XML include mask - may be null
or empty
* @param aXMLExcludes
* XML exclude mask - may be null
or empty
* @param aSVRLDirectory
* SVRL directory to write to (maybe null
in which case
* the SVRL is not written)
* @param bExpectSuccess
* true
if this is a positive validation,
* false
if error is expected
* @param aErrorMessages
* The list of collected error messages (only used if fail-fast is
* disabled)
* @throws MojoExecutionException
* Internal error
* @throws MojoFailureException
* Validation error
*/
private void _performValidation (@Nonnull final ISchematronResource aSch,
@Nonnull final File aXMLDirectory,
@Nullable final String [] aXMLIncludes,
@Nullable final String [] aXMLExcludes,
@Nullable final File aSVRLDirectory,
final boolean bExpectSuccess,
@Nonnull final ICommonsList aErrorMessages) throws MojoExecutionException,
MojoFailureException
{
final DirectoryScanner aScanner = new DirectoryScanner ();
aScanner.setBasedir (aXMLDirectory);
if (ArrayHelper.isNotEmpty (aXMLIncludes))
aScanner.setIncludes (aXMLIncludes);
if (ArrayHelper.isNotEmpty (aXMLExcludes))
aScanner.setExcludes (aXMLExcludes);
aScanner.setCaseSensitive (true);
aScanner.scan ();
final String [] aXMLFilenames = aScanner.getIncludedFiles ();
if (aXMLFilenames != null)
{
for (final String sXMLFilename : aXMLFilenames)
{
final File aXMLFile = new File (aXMLDirectory, sXMLFilename);
// Validate XML file
getLog ().info ("Validating XML file '" +
aXMLFile.getPath () +
"' against Schematron rules from '" +
m_aSchematronFile +
"' expecting " +
(bExpectSuccess ? "success" : "failure"));
try
{
final SchematronOutputType aSOT = aSch.applySchematronValidationToSVRL (TransformSourceFactory.create (aXMLFile));
if (aSVRLDirectory != null)
{
// Save SVRL
final File aSVRLFile = new File (aSVRLDirectory, sXMLFilename + ".svrl");
final FileIOError aIOErr = FileOperationManager.INSTANCE.createDirRecursiveIfNotExisting (aSVRLFile.getParentFile ());
if (aIOErr.isFailure ())
getLog ().error ("Failed to create parent directory of '" +
aSVRLFile.getAbsolutePath () +
"': " +
aIOErr.toString ());
if (new SVRLMarshaller ().write (aSOT, aSVRLFile).isSuccess ())
getLog ().info ("Successfully saved SVRL file '" + aSVRLFile.getPath () + "'");
else
getLog ().error ("Error saving SVRL file '" + aSVRLFile.getPath () + "'");
}
// Failed asserts and Successful reports
ICommonsList aSVRLErrors = SVRLHelper.getAllFailedAssertionsAndSuccessfulReports (aSOT);
if (m_bIgnoreWarnings)
{
// Use errors only
final int nOld = aSVRLErrors.size ();
aSVRLErrors = aSVRLErrors.getAll (x -> x.getFlag ().isError ());
final int nNew = aSVRLErrors.size ();
if (nOld > nNew)
getLog ().info ("Ignoring " + (nOld - nNew) + " Schematron warnings");
}
if (bExpectSuccess)
{
// No failed assertions expected
if (aSVRLErrors.isNotEmpty ())
{
final String sMessage = aSVRLErrors.size () +
" failed Schematron assertions for XML file '" +
aXMLFile.getPath () +
"'";
getLog ().error (sMessage);
aSVRLErrors.forEach (x -> getLog ().error (x.getAsResourceError (aXMLFile.getPath ())
.getAsString (Locale.US)));
if (m_bFailFast)
throw new MojoFailureException (sMessage);
aErrorMessages.add (sMessage);
}
}
else
{
// At least one failed assertions expected
if (aSVRLErrors.isEmpty ())
{
final String sMessage = "No failed Schematron assertions for erroneous XML file '" +
aXMLFile.getPath () +
"'";
getLog ().error (sMessage);
if (m_bFailFast)
throw new MojoFailureException (sMessage);
aErrorMessages.add (sMessage);
}
}
}
catch (final MojoExecutionException | MojoFailureException up)
{
throw up;
}
catch (final Exception ex)
{
final String sMessage = "Exception validating XML '" +
aXMLFile.getPath () +
"' against Schematron rules from '" +
m_aSchematronFile +
"'";
getLog ().error (sMessage, ex);
throw new MojoExecutionException (sMessage, ex);
}
}
}
}
public void execute () throws MojoExecutionException, MojoFailureException
{
if (m_aSchematronFile == null)
throw new MojoExecutionException ("No Schematron file specified!");
if (m_aSchematronFile.exists () && !m_aSchematronFile.isFile ())
throw new MojoExecutionException ("The specified Schematron file " + m_aSchematronFile + " is not a file!");
if (m_sSchematronProcessingEngine == null)
throw new MojoExecutionException ("An invalid Schematron processing instance is specified! Only one of the following values is allowed: " +
StringHelper.getImplodedMapped (", ",
ESchematronMode.values (),
x -> "'" + x.getID () + "'"));
if (m_aXmlDirectory == null && m_aXmlErrorDirectory == null)
throw new MojoExecutionException ("No XML directory specified - positive or negative directory must be present!");
if (m_aXmlDirectory != null)
{
if (m_aXmlDirectory.exists () && !m_aXmlDirectory.isDirectory ())
throw new MojoExecutionException ("The specified XML directory " + m_aXmlDirectory + " is not a directory!");
if (ArrayHelper.isEmpty (m_aXmlIncludes))
throw new MojoExecutionException ("No XML include pattern specified!");
if (m_aSvrlDirectory != null)
{
if (!m_aSvrlDirectory.exists () && !m_aSvrlDirectory.mkdirs ())
throw new MojoExecutionException ("Failed to create the SVRL directory " + m_aSvrlDirectory);
}
}
if (m_aXmlErrorDirectory != null)
{
if (m_aXmlErrorDirectory.exists () && !m_aXmlErrorDirectory.isDirectory ())
throw new MojoExecutionException ("The specified erroneous XML directory " +
m_aXmlErrorDirectory +
" is not a directory!");
if (ArrayHelper.isEmpty (m_aXmlErrorIncludes))
throw new MojoExecutionException ("No erroneous XML include pattern specified!");
if (m_aSvrlErrorDirectory != null)
{
if (!m_aSvrlErrorDirectory.exists () && !m_aSvrlErrorDirectory.mkdirs ())
throw new MojoExecutionException ("Failed to create the erroneous SVRL directory " + m_aSvrlErrorDirectory);
}
}
// 1. Parse Schematron file
ISchematronResource aSch;
IErrorList aSCHErrors;
switch (ESchematronMode.getFromIDOrNull (m_sSchematronProcessingEngine))
{
case PURE:
{
// pure
final CollectingPSErrorHandler aErrorHdl = new CollectingPSErrorHandler ();
final SchematronResourcePure aRealSCH = new SchematronResourcePure (new FileSystemResource (m_aSchematronFile));
aRealSCH.setPhase (m_sPhaseName);
aRealSCH.setLenient (m_bLenient);
// language code is ignored
// custom parameters are ignored
aRealSCH.setErrorHandler (aErrorHdl);
aRealSCH.validateCompletely ();
aSch = aRealSCH;
aSCHErrors = aErrorHdl.getAllErrors ();
break;
}
case SCHEMATRON:
{
// SCH
final CollectingTransformErrorListener aErrorHdl = new CollectingTransformErrorListener ();
final SchematronResourceSCH aRealSCH = new SchematronResourceSCH (new FileSystemResource (m_aSchematronFile));
aRealSCH.setPhase (m_sPhaseName);
aRealSCH.setLanguageCode (m_sLanguageCode);
aRealSCH.setForceCacheResult (m_bForceCacheResult);
aRealSCH.parameters ().setAll (m_aCustomParameters);
aRealSCH.setErrorListener (aErrorHdl);
aRealSCH.isValidSchematron ();
aSch = aRealSCH;
aSCHErrors = aErrorHdl.getErrorList ();
break;
}
case SCHXSLT_XSLT2:
{
// SchXslt
final CollectingTransformErrorListener aErrorHdl = new CollectingTransformErrorListener ();
final SchematronResourceSchXslt_XSLT2 aRealSCH = new SchematronResourceSchXslt_XSLT2 (new FileSystemResource (m_aSchematronFile));
aRealSCH.setPhase (m_sPhaseName);
aRealSCH.setLanguageCode (m_sLanguageCode);
aRealSCH.setForceCacheResult (m_bForceCacheResult);
aRealSCH.parameters ().setAll (m_aCustomParameters);
aRealSCH.setErrorListener (aErrorHdl);
aRealSCH.isValidSchematron ();
aSch = aRealSCH;
aSCHErrors = aErrorHdl.getErrorList ();
break;
}
case XSLT:
{
// SCH
final CollectingTransformErrorListener aErrorHdl = new CollectingTransformErrorListener ();
final SchematronResourceXSLT aRealSCH = new SchematronResourceXSLT (new FileSystemResource (m_aSchematronFile));
// phase is ignored
// language code is ignored
aRealSCH.parameters ().setAll (m_aCustomParameters);
aRealSCH.setErrorListener (aErrorHdl);
aRealSCH.isValidSchematron ();
aSch = aRealSCH;
aSCHErrors = aErrorHdl.getErrorList ();
break;
}
default:
throw new MojoExecutionException ("No handler for processing engine '" + m_sSchematronProcessingEngine + "'");
}
if (aSCHErrors != null)
{
// Error validating the Schematrons!!
boolean bAnyError = false;
for (final IError aError : aSCHErrors)
{
if (aError.getErrorLevel ().isGE (EErrorLevel.ERROR))
bAnyError = true;
PluginErrorListener.logIError (buildContext, m_aSchematronFile, aError);
}
if (bAnyError)
throw new MojoExecutionException ("The provided Schematron file contains errors. See log for details.");
}
getLog ().info ("Successfully parsed Schematron file '" + m_aSchematronFile.getPath () + "'");
// 2. for all XML files that match the pattern
final ICommonsList aErrorMessages = new CommonsArrayList <> ();
if (m_aXmlDirectory != null)
{
// Expect success
_performValidation (aSch,
m_aXmlDirectory,
m_aXmlIncludes,
m_aXmlExcludes,
m_aSvrlDirectory,
true,
aErrorMessages);
}
if (m_aXmlErrorDirectory != null)
{
// Expect error
_performValidation (aSch,
m_aXmlErrorDirectory,
m_aXmlErrorIncludes,
m_aXmlErrorExcludes,
m_aSvrlErrorDirectory,
false,
aErrorMessages);
}
if (!m_bFailFast && aErrorMessages.isNotEmpty ())
{
// Build collecting error message
aErrorMessages.add (0, aErrorMessages.size () + " errors found:");
final String sCollectedErrorMessages = StringHelper.getImploded ("\n ", aErrorMessages);
throw new MojoFailureException (sCollectedErrorMessages);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy