background:
动手写一个去掉js comment的Maven Plugin, 用英文写练习练习,哈哈
steps:
1. New a maven project, the pom is like below. At the beginning I do not add the maven project api to the project, it is exhausting to find the project strutcture, build path etc and filter the resources that i want. It is better to include it in my project,

<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.5</source> <target>1.5</target> </configuration> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>org.apache.maven</groupId> <artifactId>maven-plugin-api</artifactId> <version>2.0</version> </dependency> <dependency> <groupId>org.apache.maven</groupId> <artifactId>maven-project</artifactId> <version>2.0.9</version> <scope>provided</scope> </dependency> </dependencies>
2. Js comment is deleted by using regular expression. the code maybe like as below. The single line comment as "//...." without existing in string literal is hard to match. And a big js file is loaded into memory at one time and is treated as a really string by regular expression may cause java fatal error. So it is not very prefect, but it is enough to be fullfill my situation.
package com.mycompany.mojo.jsmin; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileWriter; import java.io.IOException; import java.util.regex.Pattern; public abstract class JsFileProcessor { private static final int buffer_size = 512; private static final Pattern block = Pattern.compile( "(?:/\\*(?:[^*]|(?:\\*+[^*/]))*\\*+/)" ); private static final Pattern singleLine = Pattern.compile( "(?<=.*)//[^\"\\n\\r]*(?=[\r\n])" ); public static void process(File inputFile, File outputFile) throws IOException { FileInputStream fis = null; FileWriter fw = null; ByteArrayOutputStream baos = new ByteArrayOutputStream(buffer_size * 2); try { fis = new FileInputStream(inputFile); fw = new FileWriter(outputFile); int length = -1; byte[] buffer = new byte[buffer_size]; while( (length = fis.read(buffer)) != -1) { baos.write(buffer, 0, length); } } catch (IOException e) { throw e; } finally { fis.close(); baos.flush(); baos.close(); } String text = singleLine.matcher( block.matcher(baos.toString()).replaceAll("") ).replaceAll(""); try { fw.write(text); } finally { fw.flush(); fw.close(); } } }
3. Mojo is like as below, the annotation is required by Maven plugin to dependecy inject the parms value at runtime. It is really very convenient.


package com.mycompany.mojo.jsmin; import java.io.File; import java.io.IOException; import java.util.List; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.codehaus.plexus.util.DirectoryScanner; /** * delete the js file comment * @goal minify * @phase process-resources */ public class JsCommentMojo extends AbstractMojo { /** * Single directory for extra files to include in the WAR. * * @parameter expression="${basedir}/src/main/webapp" */ private File warSourceDirectory; /** * The folder where the webapp is built. * * @parameter expression="${project.build.directory}/${project.build.finalName}" */ private File webappDirectory; /** * excludes file * * @parameter */ private List<String> excludes; /** * javascript file extension * * @parameter default-value=".js" */ private String extension; /** * Whether to skip execution. * * @parameter expression="${maven.jsmin.skip}" default-value="false" */ private boolean skip; /** * total count of processed javascript file * */ private int executedCount; public void execute() throws MojoExecutionException, MojoFailureException { if(skip) { getLog().info("Run of javascript files process skipped"); return; } getLog().info("Run of javascript files process is starting..."); DirectoryScanner directoryScanner = new DirectoryScanner(); directoryScanner.setBasedir(warSourceDirectory); if ( excludes != null && !excludes.isEmpty() ) { directoryScanner.setExcludes( excludes.toArray(new String[0]) ); } directoryScanner.setIncludes(new String[]{"**/*" + extension}); directoryScanner.addDefaultExcludes(); directoryScanner.scan(); for(String relativePath : directoryScanner.getIncludedFiles() ) { try { processFile( new File(warSourceDirectory, relativePath), getTargetFile(relativePath)); } catch (IOException e) { getLog().error(warSourceDirectory + relativePath + " failed to be processed"); getLog().error(e); throw new MojoExecutionException(e.getMessage()); } } getLog().info("Total " + executedCount + " javascript files processed"); } private File getTargetFile(String relativePath) throws MojoExecutionException { File file = new File(webappDirectory.getPath() + File.separator + relativePath); file.getParentFile().mkdirs(); if(getLog().isDebugEnabled()) { getLog().debug("src file [ " + relativePath + " ] ==>> target [ " + file.getPath() + " ]"); } return file; } private void processFile(File inputFile, File outputFile) throws IOException { JsFileProcessor.process(inputFile, outputFile); executedCount++; getLog().info("process file : " + inputFile.getPath() ); } }
作为记录, 以资参考