Polish metadata annotation processor’s incremental build support
The main change in this commit is to introduce a new BuildHandler abstraction. A BuildHandler is responsible for producing the metadata for a build. Two implementations are provided; one for standard builds and one for incremental builds. This change means that the annotation processor is no longer concerned with the two different build types and can use the same logic in each case. The code for reading and writing metadata files has also been moved out into a separate class, MetadataStore, to allow it to be easily utilised from multiple places. Closes gh-2313
This commit is contained in:
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2015 the original author or authors.
|
||||
*
|
||||
* 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 org.springframework.boot.configurationprocessor;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata;
|
||||
|
||||
/**
|
||||
* Data object containing information about a finished build.
|
||||
*
|
||||
* @author Kris De Volder
|
||||
*/
|
||||
public class BuildResult {
|
||||
|
||||
public final ConfigurationMetadata metadata;
|
||||
|
||||
public final Set<String> processedTypes;
|
||||
|
||||
public final boolean isIncremental;
|
||||
|
||||
public BuildResult(boolean isIncremental, ConfigurationMetadata metadata,
|
||||
Set<String> processedTypes) {
|
||||
this.isIncremental = isIncremental;
|
||||
this.metadata = metadata;
|
||||
this.processedTypes = processedTypes;
|
||||
}
|
||||
|
||||
public BuildResult(TestConfigurationMetadataAnnotationProcessor processor) {
|
||||
this(processor.isIncremental(), processor.getMetadata(),
|
||||
processor.processedSourceTypes);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -57,9 +57,9 @@ import static org.hamcrest.Matchers.not;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.springframework.boot.configurationprocessor.ConfigurationMetadataAnnotationProcessor.METADATA_PATH;
|
||||
import static org.springframework.boot.configurationprocessor.ConfigurationMetadataMatchers.containsGroup;
|
||||
import static org.springframework.boot.configurationprocessor.ConfigurationMetadataMatchers.containsProperty;
|
||||
import static org.springframework.boot.configurationprocessor.MetadataStore.METADATA_PATH;
|
||||
|
||||
/**
|
||||
* Tests for {@link ConfigurationMetadataAnnotationProcessor}.
|
||||
@@ -81,92 +81,6 @@ public class ConfigurationMetadataAnnotationProcessorTests {
|
||||
this.compiler = new TestCompiler(this.temporaryFolder);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void incrementalBuild() throws Exception {
|
||||
TestProject project = new TestProject(this.temporaryFolder, FooProperties.class,
|
||||
BarProperties.class);
|
||||
assertFalse(project.getOutputFile(METADATA_PATH).exists());
|
||||
|
||||
BuildResult r = project.fullBuild();
|
||||
assertFalse(r.isIncremental);
|
||||
assertTrue(project.getOutputFile(METADATA_PATH).exists());
|
||||
|
||||
assertThat(r.metadata,
|
||||
containsProperty("foo.counter").fromSource(FooProperties.class));
|
||||
assertThat(r.metadata,
|
||||
containsProperty("bar.counter").fromSource(BarProperties.class));
|
||||
|
||||
r = project.incrementalBuild(BarProperties.class);
|
||||
assertTrue(r.isIncremental);
|
||||
assertTrue(r.processedTypes.contains(BarProperties.class.getName()));
|
||||
assertFalse(r.processedTypes.contains(FooProperties.class.getName()));
|
||||
|
||||
assertThat(r.metadata,
|
||||
containsProperty("foo.counter").fromSource(FooProperties.class));
|
||||
assertThat(r.metadata,
|
||||
containsProperty("bar.counter").fromSource(BarProperties.class));
|
||||
|
||||
assertTrue(r.processedTypes.contains(BarProperties.class.getName()));
|
||||
assertFalse(r.processedTypes.contains(FooProperties.class.getName()));
|
||||
|
||||
project.addSourceCode(BarProperties.class, " private String extra;\n" + " \n"
|
||||
+ " public String getExtra() {\n" + " return extra;\n" + " }\n" + "\n"
|
||||
+ " public void setExtra(String extra) {\n" + " this.extra = extra;\n"
|
||||
+ " }\n");
|
||||
r = project.incrementalBuild(BarProperties.class);
|
||||
assertTrue(r.isIncremental);
|
||||
assertThat(r.metadata, containsProperty("bar.extra"));
|
||||
assertThat(r.metadata, containsProperty("foo.counter"));
|
||||
assertThat(r.metadata, containsProperty("bar.counter"));
|
||||
|
||||
project.revert(BarProperties.class);
|
||||
r = project.incrementalBuild(BarProperties.class);
|
||||
assertTrue(r.isIncremental);
|
||||
assertThat(r.metadata, not(containsProperty("bar.extra")));
|
||||
assertThat(r.metadata, containsProperty("foo.counter"));
|
||||
assertThat(r.metadata, containsProperty("bar.counter"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void incremenalBuildAnnotationRemoved() throws Exception {
|
||||
TestProject project = new TestProject(this.temporaryFolder, FooProperties.class,
|
||||
BarProperties.class);
|
||||
BuildResult r = project.fullBuild();
|
||||
assertThat(r.metadata, containsProperty("foo.counter"));
|
||||
assertThat(r.metadata, containsProperty("bar.counter"));
|
||||
|
||||
project.replaceText(BarProperties.class, "@ConfigurationProperties",
|
||||
"//@ConfigurationProperties");
|
||||
r = project.incrementalBuild(BarProperties.class);
|
||||
assertThat(r.metadata, containsProperty("foo.counter"));
|
||||
assertThat(r.metadata, not(containsProperty("bar.counter")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void incremenalBuildTypeRenamed() throws Exception {
|
||||
TestProject project = new TestProject(this.temporaryFolder, FooProperties.class,
|
||||
BarProperties.class);
|
||||
BuildResult r = project.fullBuild();
|
||||
assertThat(r.metadata,
|
||||
containsProperty("foo.counter").fromSource(FooProperties.class));
|
||||
assertThat(r.metadata,
|
||||
containsProperty("bar.counter").fromSource(BarProperties.class));
|
||||
assertThat(r.metadata,
|
||||
not(containsProperty("bar.counter")
|
||||
.fromSource(RenamedBarProperties.class)));
|
||||
|
||||
project.delete(BarProperties.class);
|
||||
project.add(RenamedBarProperties.class);
|
||||
r = project.incrementalBuild(RenamedBarProperties.class);
|
||||
assertThat(r.metadata,
|
||||
containsProperty("foo.counter").fromSource(FooProperties.class));
|
||||
assertThat(r.metadata,
|
||||
not(containsProperty("bar.counter").fromSource(BarProperties.class)));
|
||||
assertThat(r.metadata,
|
||||
containsProperty("bar.counter").fromSource(RenamedBarProperties.class));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void notAnnotated() throws Exception {
|
||||
ConfigurationMetadata metadata = compile(NotAnnotated.class);
|
||||
@@ -436,7 +350,80 @@ public class ConfigurationMetadataAnnotationProcessorTests {
|
||||
assertThat(metadata,
|
||||
containsProperty("foo", String.class)
|
||||
.fromSource(AdditionalMetadata.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void incrementalBuild() throws Exception {
|
||||
TestProject project = new TestProject(this.temporaryFolder, FooProperties.class,
|
||||
BarProperties.class);
|
||||
assertFalse(project.getOutputFile(METADATA_PATH).exists());
|
||||
|
||||
ConfigurationMetadata metadata = project.fullBuild();
|
||||
assertTrue(project.getOutputFile(METADATA_PATH).exists());
|
||||
|
||||
assertThat(metadata,
|
||||
containsProperty("foo.counter").fromSource(FooProperties.class));
|
||||
assertThat(metadata,
|
||||
containsProperty("bar.counter").fromSource(BarProperties.class));
|
||||
|
||||
metadata = project.incrementalBuild(BarProperties.class);
|
||||
|
||||
assertThat(metadata,
|
||||
containsProperty("foo.counter").fromSource(FooProperties.class));
|
||||
assertThat(metadata,
|
||||
containsProperty("bar.counter").fromSource(BarProperties.class));
|
||||
|
||||
project.addSourceCode(BarProperties.class,
|
||||
BarProperties.class.getResourceAsStream("BarProperties.snippet"));
|
||||
metadata = project.incrementalBuild(BarProperties.class);
|
||||
assertThat(metadata, containsProperty("bar.extra"));
|
||||
assertThat(metadata, containsProperty("foo.counter"));
|
||||
assertThat(metadata, containsProperty("bar.counter"));
|
||||
|
||||
project.revert(BarProperties.class);
|
||||
metadata = project.incrementalBuild(BarProperties.class);
|
||||
assertThat(metadata, not(containsProperty("bar.extra")));
|
||||
assertThat(metadata, containsProperty("foo.counter"));
|
||||
assertThat(metadata, containsProperty("bar.counter"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void incremenalBuildAnnotationRemoved() throws Exception {
|
||||
TestProject project = new TestProject(this.temporaryFolder, FooProperties.class,
|
||||
BarProperties.class);
|
||||
ConfigurationMetadata metadata = project.fullBuild();
|
||||
assertThat(metadata, containsProperty("foo.counter"));
|
||||
assertThat(metadata, containsProperty("bar.counter"));
|
||||
|
||||
project.replaceText(BarProperties.class, "@ConfigurationProperties",
|
||||
"//@ConfigurationProperties");
|
||||
metadata = project.incrementalBuild(BarProperties.class);
|
||||
assertThat(metadata, containsProperty("foo.counter"));
|
||||
assertThat(metadata, not(containsProperty("bar.counter")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void incremenalBuildTypeRenamed() throws Exception {
|
||||
TestProject project = new TestProject(this.temporaryFolder, FooProperties.class,
|
||||
BarProperties.class);
|
||||
ConfigurationMetadata metadata = project.fullBuild();
|
||||
assertThat(metadata,
|
||||
containsProperty("foo.counter").fromSource(FooProperties.class));
|
||||
assertThat(metadata,
|
||||
containsProperty("bar.counter").fromSource(BarProperties.class));
|
||||
assertThat(metadata,
|
||||
not(containsProperty("bar.counter")
|
||||
.fromSource(RenamedBarProperties.class)));
|
||||
|
||||
project.delete(BarProperties.class);
|
||||
project.add(RenamedBarProperties.class);
|
||||
metadata = project.incrementalBuild(RenamedBarProperties.class);
|
||||
assertThat(metadata,
|
||||
containsProperty("foo.counter").fromSource(FooProperties.class));
|
||||
assertThat(metadata,
|
||||
not(containsProperty("bar.counter").fromSource(BarProperties.class)));
|
||||
assertThat(metadata,
|
||||
containsProperty("bar.counter").fromSource(RenamedBarProperties.class));
|
||||
}
|
||||
|
||||
private void assertSimpleLombokProperties(ConfigurationMetadata metadata,
|
||||
|
||||
@@ -18,7 +18,6 @@ package org.springframework.boot.configurationprocessor;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.processing.SupportedAnnotationTypes;
|
||||
import javax.annotation.processing.SupportedSourceVersion;
|
||||
@@ -61,8 +60,8 @@ public class TestConfigurationMetadataAnnotationProcessor extends
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ConfigurationMetadata writeMetaData(ConfigurationMetadata metadata) {
|
||||
super.writeMetaData(metadata);
|
||||
protected ConfigurationMetadata writeMetaData() {
|
||||
super.writeMetaData();
|
||||
try {
|
||||
File metadataFile = new File(this.outputLocation,
|
||||
"META-INF/spring-configuration-metadata.json");
|
||||
@@ -71,7 +70,7 @@ public class TestConfigurationMetadataAnnotationProcessor extends
|
||||
metadataFile));
|
||||
}
|
||||
else {
|
||||
this.metadata = metadata;
|
||||
this.metadata = new ConfigurationMetadata();
|
||||
}
|
||||
return this.metadata;
|
||||
}
|
||||
@@ -84,12 +83,4 @@ public class TestConfigurationMetadataAnnotationProcessor extends
|
||||
return this.metadata;
|
||||
}
|
||||
|
||||
public Set<String> getProcessedTypes() {
|
||||
return this.processedSourceTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isIncremental() {
|
||||
return super.isIncremental();
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,8 @@ import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.StringReader;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Arrays;
|
||||
@@ -30,9 +32,9 @@ import java.util.Set;
|
||||
import org.junit.Assert;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.springframework.boot.configurationprocessor.TestCompiler.TestCompilationTask;
|
||||
import org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata;
|
||||
import org.springframework.boot.configurationsample.ConfigurationProperties;
|
||||
import org.springframework.boot.configurationsample.NestedConfigurationProperty;
|
||||
import org.springframework.boot.configurationsample.incremental.BarProperties;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
import org.springframework.util.FileSystemUtils;
|
||||
|
||||
@@ -94,21 +96,21 @@ public class TestProject {
|
||||
return new File(this.sourceFolder, sourcePathFor(klass));
|
||||
}
|
||||
|
||||
public BuildResult fullBuild() {
|
||||
public ConfigurationMetadata fullBuild() {
|
||||
TestConfigurationMetadataAnnotationProcessor processor = new TestConfigurationMetadataAnnotationProcessor(
|
||||
this.compiler.getOutputLocation());
|
||||
TestCompilationTask task = this.compiler.getTask(this.sourceFiles);
|
||||
deleteFolderContents(this.compiler.getOutputLocation());
|
||||
task.call(processor);
|
||||
return new BuildResult(processor);
|
||||
return processor.getMetadata();
|
||||
}
|
||||
|
||||
public BuildResult incrementalBuild(Class<?>... toRecompile) {
|
||||
public ConfigurationMetadata incrementalBuild(Class<?>... toRecompile) {
|
||||
TestConfigurationMetadataAnnotationProcessor processor = new TestConfigurationMetadataAnnotationProcessor(
|
||||
this.compiler.getOutputLocation());
|
||||
TestCompilationTask task = this.compiler.getTask(toRecompile);
|
||||
task.call(processor);
|
||||
return new BuildResult(processor);
|
||||
return processor.getMetadata();
|
||||
}
|
||||
|
||||
private void deleteFolderContents(File outputFolder) {
|
||||
@@ -127,11 +129,15 @@ public class TestProject {
|
||||
/**
|
||||
* Add source code at the end of file, just before last '}'
|
||||
*/
|
||||
public void addSourceCode(Class<BarProperties> target, String text) throws Exception {
|
||||
public void addSourceCode(Class<?> target, InputStream snippetStream)
|
||||
throws Exception {
|
||||
File targetFile = getSourceFile(target);
|
||||
String contents = getContents(targetFile);
|
||||
int insertAt = contents.lastIndexOf('}');
|
||||
contents = contents.substring(0, insertAt) + text + contents.substring(insertAt);
|
||||
String additionalSource = FileCopyUtils.copyToString(new InputStreamReader(
|
||||
snippetStream));
|
||||
contents = contents.substring(0, insertAt) + additionalSource
|
||||
+ contents.substring(insertAt);
|
||||
putContents(targetFile, contents);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
private String extra;
|
||||
|
||||
public String getExtra() {
|
||||
return extra;
|
||||
}
|
||||
|
||||
public void setExtra(String extra) {
|
||||
this.extra = extra;
|
||||
}
|
||||
Reference in New Issue
Block a user