1818 */
1919package org .apache .maven .plugins .jar ;
2020
21+ import java .io .File ;
2122import java .io .IOException ;
22- import java .nio .file .FileSystems ;
2323import java .nio .file .Files ;
2424import java .nio .file .Path ;
2525import java .util .Arrays ;
2626import java .util .Map ;
27+ import java .util .Objects ;
28+ import java .util .jar .Attributes ;
2729import java .util .stream .Stream ;
2830
2931import org .apache .maven .api .ProducedArtifact ;
4345import org .codehaus .plexus .archiver .jar .JarArchiver ;
4446
4547/**
46- * Base class for creating a jar from project classes.
48+ * Base class for creating a <abbr>JAR</abbr> file from project classes.
4749 *
4850 * @author <a href="evenisse@apache.org">Emmanuel Venisse</a>
49- * @version $Id$
5051 */
5152public abstract class AbstractJarMojo implements org .apache .maven .api .plugin .Mojo {
5253
@@ -56,8 +57,6 @@ public abstract class AbstractJarMojo implements org.apache.maven.api.plugin.Moj
5657
5758 private static final String MODULE_DESCRIPTOR_FILE_NAME = "module-info.class" ;
5859
59- private static final String SEPARATOR = FileSystems .getDefault ().getSeparator ();
60-
6160 /**
6261 * List of files to include. Specified as fileset patterns which are relative to the input directory whose contents
6362 * is being packaged into the JAR.
@@ -85,19 +84,19 @@ public abstract class AbstractJarMojo implements org.apache.maven.api.plugin.Moj
8584 private String finalName ;
8685
8786 /**
88- * The Jar archiver.
87+ * The JAR archiver.
8988 */
9089 @ Inject
9190 private Map <String , Archiver > archivers ;
9291
9392 /**
94- * The {@link Project} .
93+ * The Maven project .
9594 */
9695 @ Inject
9796 private Project project ;
9897
9998 /**
100- * The {@link Session} .
99+ * The session .
101100 */
102101 @ Inject
103102 private Session session ;
@@ -109,22 +108,20 @@ public abstract class AbstractJarMojo implements org.apache.maven.api.plugin.Moj
109108 @ Parameter
110109 private MavenArchiveConfiguration archive = new MavenArchiveConfiguration ();
111110
112- /**
113- *
114- */
115111 @ Inject
116112 private ProjectManager projectManager ;
117113
118114 /**
119- * Require the jar plugin to build a new JAR even if none of the contents appear to have changed. By default, this
120- * plugin looks to see if the output jar exists and inputs have not changed. If these conditions are true, the
121- * plugin skips creation of the jar. This does not work when other plugins, like the maven-shade-plugin, are
122- * configured to post-process the jar. This plugin can not detect the post-processing, and so leaves the
123- * post-processed jar in place. This can lead to failures when those plugins do not expect to find their own output
124- * as an input. Set this parameter to <tt>true</tt> to avoid these problems by forcing this plugin to recreate the
125- * jar every time.<br/>
126- * Starting with <b>3.0.0</b> the property has been renamed from <code>jar.forceCreation</code> to
127- * <code>maven.jar.forceCreation</code>.
115+ * Require the jar plugin to build a new JAR even if none of the contents appear to have changed.
116+ * By default, this plugin looks to see if the output JAR exists and inputs have not changed.
117+ * If these conditions are true, the plugin skips creation of the JAR file.
118+ * This does not work when other plugins, like the maven-shade-plugin, are configured to post-process the JAR.
119+ * This plugin can not detect the post-processing, and so leaves the post-processed JAR file in place.
120+ * This can lead to failures when those plugins do not expect to find their own output as an input.
121+ * Set this parameter to {@code true} to avoid these problems by forcing this plugin to recreate the JAR every time.
122+ *
123+ * <p>Starting with <b>3.0.0</b> the property has been renamed from {@code jar.forceCreation}
124+ * to {@code maven.jar.forceCreation}.</p>
128125 */
129126 @ Parameter (property = "maven.jar.forceCreation" , defaultValue = "false" )
130127 private boolean forceCreation ;
@@ -136,9 +133,10 @@ public abstract class AbstractJarMojo implements org.apache.maven.api.plugin.Moj
136133 private boolean skipIfEmpty ;
137134
138135 /**
139- * Timestamp for reproducible output archive entries, either formatted as ISO 8601 extended offset date-time
136+ * Timestamp for reproducible output archive entries.
137+ * This is either formatted as ISO 8601 extended offset date-time
140138 * (e.g. in UTC such as '2011-12-03T10:15:30Z' or with an offset '2019-10-05T20:37:42+06:00'),
141- * or as an int representing seconds since the epoch
139+ * or as an integer representing seconds since the epoch
142140 * (like <a href="https://reproducible-builds.org/docs/source-date-epoch/">SOURCE_DATE_EPOCH</a>).
143141 *
144142 * @since 3.2.0
@@ -147,76 +145,79 @@ public abstract class AbstractJarMojo implements org.apache.maven.api.plugin.Moj
147145 private String outputTimestamp ;
148146
149147 /**
148+ * Whether to detect multi-release JAR files.
150149 * If the JAR contains the {@code META-INF/versions} directory it will be detected as a multi-release JAR file
151- * ("MRJAR"), adding the {@code Multi-Release: true} attribute to the main section of the JAR MANIFEST.MF.
150+ * ("MRJAR"), adding the {@code Multi-Release: true} attribute to the main section of the JAR {@code MANIFEST.MF} .
152151 *
153152 * @since 3.4.0
154153 */
155154 @ Parameter (property = "maven.jar.detectMultiReleaseJar" , defaultValue = "true" )
156155 private boolean detectMultiReleaseJar ;
157156
158157 /**
159- * The mojo logger
158+ * The <abbr>MOJO</abbr> logger.
160159 */
161160 @ Inject
162161 private Log log ;
163162
164163 /**
165- * Return the specific output directory to serve as the root for the archive.
166- * @return get classes directory.
164+ * Creates a new <abbr>MOJO</abbr>.
165+ */
166+ protected AbstractJarMojo () {}
167+
168+ /**
169+ * {@return the specific output directory to serve as the root for the archive}
167170 */
168171 protected abstract Path getClassesDirectory ();
169172
170173 /**
171- * Return the {@link #project MavenProject}
174+ * Return the {@linkplain #project Maven project}.
172175 *
173- * @return the MavenProject.
176+ * @return the Maven project
174177 */
175178 protected final Project getProject () {
176179 return project ;
177180 }
178181
182+ /**
183+ * {@return the <abbr>MOJO</abbr> logger}
184+ */
179185 protected final Log getLog () {
180186 return log ;
181187 }
182188
183189 /**
184- * Overload this to produce a jar with another classifier, for example a test-jar.
185- * @return get the classifier .
190+ * {@return the classifier of the JAR file to produce}
191+ * This is usually null or empty for the main artifact, or {@code "tests"} for the JAR file of test code .
186192 */
187193 protected abstract String getClassifier ();
188194
189195 /**
190- * Overload this to produce a test-jar, for example.
191- * @return return the type .
196+ * {@return the type of the JAR file to produce}
197+ * This is usually {@code "jar"} for the main artifact, or {@code "test-jar"} for the JAR file of test code .
192198 */
193199 protected abstract String getType ();
194200
195201 /**
196- * Returns the Jar file to generate, based on an optional classifier.
202+ * Returns the JAR file to generate, based on an optional classifier.
197203 *
198204 * @param basedir the output directory
199205 * @param resultFinalName the name of the ear file
200206 * @param classifier an optional classifier
201207 * @return the file to generate
202208 */
203209 protected Path getJarFile (Path basedir , String resultFinalName , String classifier ) {
204- if (basedir == null ) {
205- throw new IllegalArgumentException ("basedir is not allowed to be null" );
206- }
207- if (resultFinalName == null ) {
208- throw new IllegalArgumentException ("finalName is not allowed to be null" );
209- }
210-
211- String fileName = resultFinalName + (hasClassifier () ? "-" + classifier : "" ) + ".jar" ;
212-
210+ Objects .requireNonNull (basedir , "basedir is not allowed to be null" );
211+ Objects .requireNonNull (resultFinalName , "finalName is not allowed to be null" );
212+ String fileName = resultFinalName + (hasClassifier (classifier ) ? '-' + classifier : "" ) + ".jar" ;
213213 return basedir .resolve (fileName );
214214 }
215215
216216 /**
217217 * Generates the JAR.
218- * @return The instance of File for the created archive file.
219- * @throws MojoException in case of an error.
218+ *
219+ * @return the path to the created archive file
220+ * @throws MojoException in case of an error
220221 */
221222 public Path createArchive () throws MojoException {
222223 Path jarFile = getJarFile (outputDirectory , finalName , getClassifier ());
@@ -231,9 +232,10 @@ public Path createArchive() throws MojoException {
231232
232233 if (detectMultiReleaseJar
233234 && Arrays .stream (includedFiles )
234- .anyMatch (p -> p .startsWith ("META-INF" + SEPARATOR + "versions" + SEPARATOR ))) {
235+ .anyMatch (
236+ p -> p .startsWith ("META-INF" + File .separatorChar + "versions" + File .separatorChar ))) {
235237 getLog ().debug ("Adding 'Multi-Release: true' manifest entry." );
236- archive .addManifestEntry ("Multi-Release" , "true" );
238+ archive .addManifestEntry (Attributes . Name . MULTI_RELEASE . toString () , "true" );
237239 }
238240
239241 // May give false positives if the files is named as module descriptor
@@ -280,21 +282,23 @@ public Path createArchive() throws MojoException {
280282
281283 /**
282284 * Generates the JAR.
283- * @throws MojoException in case of an error.
285+ *
286+ * @throws MojoException in case of an error
284287 */
285288 @ Override
286289 public void execute () throws MojoException {
287290 if (skipIfEmpty && isEmpty (getClassesDirectory ())) {
288- getLog ().info ("Skipping packaging of the " + getType ());
291+ getLog ().info (String . format ( "Skipping packaging of the %s." , getType () ));
289292 } else {
290293 Path jarFile = createArchive ();
291294 ProducedArtifact artifact ;
292- if (hasClassifier ()) {
295+ String classifier = getClassifier ();
296+ if (hasClassifier (classifier )) {
293297 artifact = session .createProducedArtifact (
294298 project .getGroupId (),
295299 project .getArtifactId (),
296300 project .getVersion (),
297- getClassifier () ,
301+ classifier ,
298302 null ,
299303 getType ());
300304 } else {
@@ -308,12 +312,12 @@ public void execute() throws MojoException {
308312 }
309313 }
310314
311- private boolean isEmpty (Path directory ) {
315+ private static boolean isEmpty (Path directory ) {
312316 if (!Files .isDirectory (directory )) {
313317 return true ;
314318 }
315319 try (Stream <Path > children = Files .list (directory )) {
316- return ! children .findAny ().isPresent ();
320+ return children .findAny ().isEmpty ();
317321 } catch (IOException e ) {
318322 throw new MavenArchiverException ("Unable to access directory" , e );
319323 }
@@ -327,10 +331,11 @@ private boolean projectHasAlreadySetAnArtifact() {
327331 /**
328332 * Return {@code true} in case where the classifier is not {@code null} and contains something else than white spaces.
329333 *
330- * @return {@code true} if the classifier is set.
334+ * @param classifier the classifier to verify
335+ * @return {@code true} if the classifier is set
331336 */
332- protected boolean hasClassifier () {
333- return getClassifier () != null && !getClassifier (). trim (). isEmpty ();
337+ private static boolean hasClassifier (String classifier ) {
338+ return classifier != null && !classifier . isBlank ();
334339 }
335340
336341 private String [] getIncludes () {
0 commit comments