All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.github.zlika.reproducible.StripJaxbMojo Maven / Gradle / Ivy

There is a newer version: 0.17
Show newest version
/*
 * 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 io.github.zlika.reproducible;

import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.List;

import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;

/**
 * Normalizes ObjectFactory java files generated by the JAXB xjc tool
 * and removes timestamps from JAXB generated files.
 */
@Mojo(name = "strip-jaxb", defaultPhase = LifecyclePhase.PROCESS_SOURCES, threadSafe = true)
public final class StripJaxbMojo extends AbstractMojo
{
    private static final int JAXB_FILE_JAXB_COMMENT_LINE_NUMBER = 1;
    private static final int JAXB_FILE_TIMESTAMP_LINE_NUMBER = 4;
    private static final int JAXB_EPISODE_JAXB_COMMENT_LINE_NUMBER = 4;
    private static final int JAXB_EPISODE_TIMESTAMP_LINE_NUMBER = 7;
    
    /**
     * The file encoding to use when reading the source files.
     * If the property project.build.sourceEncoding is not set,
     * the platform default encoding is used.
     */
    @Parameter(defaultValue = "${project.build.sourceEncoding}")
    private String encoding;
    
    /**
     * Directory where to find the source files generated by xjc.
     */
    @Parameter(defaultValue = "${project.build.directory}/generated-sources",
            property = "reproducible.generatedDirectory", required = true)
    private File generatedDirectory;
    
    /**
     * If true, skips the execution of the goal.
     */
    @Parameter(defaultValue = "false", property = "reproducible.skip")
    private boolean skip;
    
    /**
     * Fixes ObjectFactory java files generated by the JAXB xjc tool.
     * xjc (before JAXB 2.2.11) generates ObjectFactory.java files where the methods
     * are put in a non-predictable order (cf.https://java.net/jira/browse/JAXB-598).
     * If true, the methods in ObjectFactory.java file will be sorted in a reproducible order.
     */
    @Parameter(defaultValue = "true", property = "reproducible.fixJaxbOrder")
    private boolean fixJaxbOrder;
    
    /**
     * If true, the timestamps generated by JAXB will be removed.
     */
    @Parameter(defaultValue = "true", property = "reproducible.removeJaxbTimestamps")
    private boolean removeJaxbTimestamps;
    
    @Override
    public void execute() throws MojoExecutionException
    {
        if (skip)
        {
            getLog().info("Skipping execution of goal \"strip-jaxb\"");
        }
        else
        {
            fix();
        }
    }
    
    private void fix() throws MojoExecutionException
    {
        if (!generatedDirectory.exists() || !generatedDirectory.isDirectory())
        {
            return;
        }
        final Charset charset = Charset.forName(encoding);
        final JaxbObjectFactoryFixer objectFactoryFixer = new JaxbObjectFactoryFixer(charset);
        final LineNumberStripper jaxbFileDateStripper = new LineNumberStripper(JAXB_FILE_TIMESTAMP_LINE_NUMBER);
        final LineNumberStripper jaxbEpisodeDateStripper = new LineNumberStripper(JAXB_EPISODE_TIMESTAMP_LINE_NUMBER);
        final File tmpFile = createTempFile();
        
        try
        {
            Files.walk(generatedDirectory.toPath())
                .filter(Files::isRegularFile)
                .forEach(f ->
                {
                    try
                    {
                        final List lines = Files.readAllLines(f, charset);
                        // We cannot rely on an exact comment text to check if it is a JAXB generated file
                        // because it depends on the current locale
                        final boolean isJaxbFile = isJaxbFile(lines);
                        final boolean isObjectFactoryFile = isJaxbFile
                                && "ObjectFactory.java".equals(f.toFile().getName());
                        final boolean isEpisodeFile = isEpisodeFile(f.toFile().getName(), lines);
                                        
                        if (isObjectFactoryFile || isJaxbFile || isEpisodeFile)
                        {
                            getLog().info("Stripping " + f.toFile().getAbsolutePath());
                            if (isObjectFactoryFile && fixJaxbOrder)
                            {
                                objectFactoryFixer.strip(f.toFile(), tmpFile);
                                Files.move(tmpFile.toPath(), f, StandardCopyOption.REPLACE_EXISTING);
                            }
                            if (isJaxbFile && removeJaxbTimestamps)
                            {
                                jaxbFileDateStripper.strip(f.toFile(), tmpFile);
                                Files.move(tmpFile.toPath(), f, StandardCopyOption.REPLACE_EXISTING);
                            }
                            if (isEpisodeFile && removeJaxbTimestamps)
                            {
                                jaxbEpisodeDateStripper.strip(f.toFile(), tmpFile);
                                Files.move(tmpFile.toPath(), f, StandardCopyOption.REPLACE_EXISTING);
                            }
                        }
                    }
                    catch (IOException e)
                    {
                        getLog().error("Error when normalizing " + f.toFile().getAbsolutePath(), e);
                    }
                });
        }
        catch (IOException e)
        {
            throw new MojoExecutionException("Error when visiting " + generatedDirectory.getAbsolutePath(), e);
        }
    }
    
    private boolean isJaxbFile(List lines)
    {
        return lines.size() > JAXB_FILE_TIMESTAMP_LINE_NUMBER
                && lines.get(0).equals("//")
                && lines.get(JAXB_FILE_JAXB_COMMENT_LINE_NUMBER)
                    .contains("JavaTM Architecture for XML Binding (JAXB)")
                    && lines.get(JAXB_FILE_TIMESTAMP_LINE_NUMBER).contains(":");
    }
    
    private boolean isEpisodeFile(String filename, List lines)
    {
        return filename.endsWith(".episode")
                && lines.size() > JAXB_EPISODE_TIMESTAMP_LINE_NUMBER
                && lines.get(JAXB_EPISODE_JAXB_COMMENT_LINE_NUMBER)
                    .contains("JavaTM Architecture for XML Binding (JAXB)")
                && lines.get(JAXB_EPISODE_TIMESTAMP_LINE_NUMBER).contains(":");
    }

    private File createTempFile() throws MojoExecutionException
    {
        try
        {
            final File out = File.createTempFile("ObjectFactory", null);
            out.deleteOnExit();
            return out;
        }
        catch (IOException e)
        {
            throw new MojoExecutionException("Cannot create temp file", e);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy