Skip to content

Commit

Permalink
mapstruct#1420 Add support for Gradle incremental annotation processi…
Browse files Browse the repository at this point in the history
…ng (mapstruct#1971)


* Add relevant file in META-INF
* Add integration test with Gradle test kit dependencies
* Test with Gradle 5 and Gradle 6
  • Loading branch information
ttzn authored and filiphr committed Dec 8, 2019
1 parent ee794d0 commit 779eb1b
Show file tree
Hide file tree
Showing 10 changed files with 302 additions and 0 deletions.
1 change: 1 addition & 0 deletions copyright.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
============

Alexandr Shalugin - https://github.com/shalugin
Amine Touzani - https://github.com/ttzn
Andreas Gudian - https://github.com/agudian
Andrei Arlou - https://github.com/Captain1653
Andres Jose Sebastian Rincon Gonzalez - https://github.com/stianrincon
Expand Down
31 changes: 31 additions & 0 deletions integrationtest/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,19 @@
<mapstruct.version>${project.version}</mapstruct.version>
<maven.deploy.skip>true</maven.deploy.skip>
</properties>

<repositories>
<repository>
<id>gradle</id>
<url>https://repo.gradle.org/gradle/libs-releases</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>

<dependencies>
<!-- Testing -->
Expand All @@ -42,6 +55,24 @@
<artifactId>maven-verifier</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.gradle</groupId>
<artifactId>gradle-test-kit</artifactId>
<version>5.6.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.gradle</groupId>
<artifactId>gradle-tooling-api</artifactId>
<version>5.6.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.itest.tests;

import static org.gradle.testkit.runner.TaskOutcome.SUCCESS;
import static org.gradle.testkit.runner.TaskOutcome.UP_TO_DATE;
import static org.hamcrest.core.StringContains.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;

import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.apache.commons.io.FileUtils;
import org.gradle.testkit.runner.BuildResult;
import org.gradle.testkit.runner.GradleRunner;
import org.gradle.testkit.runner.TaskOutcome;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;

/**
* <p>This is supposed to be run from the mapstruct root project folder.
* Otherwise, use <code>-Dmapstruct_root=path_to_project</code>.
*/
@RunWith( Parameterized.class )
public class GradleIncrementalCompilationTest {
private static Path rootPath;
private static String projectDir = "integrationtest/src/test/resources/gradleIncrementalCompilationTest";
private static String compileTaskName = "compileJava";

@Rule
public final TemporaryFolder testBuildDir = new TemporaryFolder();
@Rule
public final TemporaryFolder testProjectDir = new TemporaryFolder();

private String gradleVersion;
private GradleRunner runner;
private File sourceDirectory;
private List<String> compileArgs; // Gradle compile task arguments

public GradleIncrementalCompilationTest(String gradleVersion) {
this.gradleVersion = gradleVersion;
}

@Parameters( name = "Gradle {0}" )
public static List<String> gradleVersions() {
return Arrays.asList( "5.0", "6.0" );
}

private void replaceInFile(File file, CharSequence target, CharSequence replacement) throws IOException {
String content = FileUtils.readFileToString( file, Charset.defaultCharset() );
FileUtils.writeStringToFile( file, content.replace( target, replacement ), Charset.defaultCharset() );
}

private GradleRunner getRunner(String... additionalArguments) {
List<String> fullArguments = new ArrayList<String>( compileArgs );
fullArguments.addAll( Arrays.asList( additionalArguments ) );
return runner.withArguments( fullArguments );
}

private void assertCompileOutcome(BuildResult result, TaskOutcome outcome) {
assertEquals( outcome, result.task( ":" + compileTaskName ).getOutcome() );
}

private void assertRecompiled(BuildResult result, int recompiledCount) {
assertCompileOutcome( result, recompiledCount > 0 ? SUCCESS : UP_TO_DATE );
assertThat(
result.getOutput(),
containsString( String.format( "Incremental compilation of %d classes completed", recompiledCount ) ) );
}

private List<String> buildCompileArgs() {
// Make Gradle use the temporary build folder by overriding the buildDir property
String buildDirPropertyArg = "-PbuildDir=" + testBuildDir.getRoot().getAbsolutePath();

// Inject the path to the folder containing the mapstruct-processor JAR
String jarDirectoryArg = "-PmapstructRootPath=" + rootPath.toString();
return Arrays.asList( compileTaskName, buildDirPropertyArg, jarDirectoryArg );
}

@BeforeClass
public static void setupClass() throws Exception {
rootPath = Paths.get( System.getProperty( "mapstruct_root", "." ) ).toAbsolutePath();
}

@Before
public void setup() throws IOException {
// Copy test project files to the temp dir
Path gradleProjectPath = rootPath.resolve( projectDir );
FileUtils.copyDirectory( gradleProjectPath.toFile(), testProjectDir.getRoot() );
compileArgs = buildCompileArgs();
sourceDirectory = new File( testProjectDir.getRoot(), "src/main/java" );
runner = GradleRunner.create().withGradleVersion( gradleVersion ).withProjectDir( testProjectDir.getRoot() );
}

@Test
public void testBuildSucceeds() throws IOException {
// Make sure the test build setup actually compiles
BuildResult buildResult = getRunner().build();
assertCompileOutcome( buildResult, SUCCESS );
}

@Test
public void testUpToDate() throws IOException {
getRunner().build();
BuildResult secondBuildResult = getRunner().build();
assertCompileOutcome( secondBuildResult, UP_TO_DATE );
}

@Test
public void testChangeConstant() throws IOException {
getRunner().build();
// Change return value in class Target
File targetFile = new File( sourceDirectory, "org/mapstruct/itest/gradle/model/Target.java" );
replaceInFile( targetFile, "original", "changed" );
BuildResult secondBuildResult = getRunner( "--info" ).build();

// 3 classes should be recompiled: Target -> TestMapper -> TestMapperImpl
assertRecompiled( secondBuildResult, 3 );
}

@Test
public void testChangeTargetField() throws IOException {
getRunner().build();
// Change target field in mapper interface
File mapperFile = new File( sourceDirectory, "org/mapstruct/itest/gradle/lib/TestMapper.java" );
replaceInFile( mapperFile, "field", "otherField" );
BuildResult secondBuildResult = getRunner( "--info" ).build();

// 2 classes should be recompiled: TestMapper -> TestMapperImpl
assertRecompiled( secondBuildResult, 2 );
}

@Test
public void testChangeUnrelatedFile() throws IOException {
getRunner().build();
File unrelatedFile = new File( sourceDirectory, "org/mapstruct/itest/gradle/lib/UnrelatedComponent.java" );
replaceInFile( unrelatedFile, "true", "false" );
BuildResult secondBuildResult = getRunner( "--info" ).build();

// Only the UnrelatedComponent class should be recompiled
assertRecompiled( secondBuildResult, 1 );
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
plugins {
id 'java'
}

if (!project.hasProperty('mapstructRootPath'))
throw new IllegalArgumentException("Missing required property: mapstructRootPath")

repositories {
jcenter()
mavenLocal()
flatDir {
dirs "${mapstructRootPath}/processor/target"
dirs "${mapstructRootPath}/core/target"
}
}

// Extract version and artifactId values
def apPom = new XmlParser().parse(file("${mapstructRootPath}/processor/pom.xml"))
ext.apArtifactId = apPom.artifactId[0].text()
ext.apVersion = apPom.parent[0].version[0].text()

def libPom = new XmlParser().parse(file("${mapstructRootPath}/core/pom.xml"))
ext.libArtifactId = libPom.artifactId[0].text()
ext.libVersion = libPom.parent[0].version[0].text()

dependencies {
annotationProcessor name: "${apArtifactId}-${apVersion}"
implementation name: "${libArtifactId}-${libVersion}"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
rootProject.name = 'gradle-incremental-compilation-test'
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.itest.gradle.lib;

import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.ReportingPolicy;

import org.mapstruct.itest.gradle.model.Target;
import org.mapstruct.itest.gradle.model.Source;

@Mapper(unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface TestMapper {
@Mapping(source = "value", target = "field")
public Target toTarget(Source source);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.itest.gradle.lib;

public class UnrelatedComponent {
public boolean unrelatedMethod() {
return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.itest.gradle.model;

public class Source {
private int value;

public void setValue(int value) {
this.value = value;
}

public int getValue() {
return value;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.itest.gradle.model;

public class Target {
private String field = getDefaultValue();
private String otherField;

public void setField(String field) {
this.field = field;
}

public String getField() {
return field;
}

public void setOtherField(String otherField) {
this.otherField = otherField;
}

public String getOtherField() {
return otherField;
}

public String getDefaultValue() {
return "original";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
org.mapstruct.ap.MappingProcessor,isolating

0 comments on commit 779eb1b

Please sign in to comment.