diff --git a/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/BuildResult.java b/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/BuildHandler.java similarity index 54% rename from spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/BuildResult.java rename to spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/BuildHandler.java index 3fc1e870c7..cae8bdfbde 100644 --- a/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/BuildResult.java +++ b/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/BuildHandler.java @@ -13,35 +13,30 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.boot.configurationprocessor; -import java.util.Set; +import javax.annotation.processing.RoundEnvironment; import org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata; /** - * Data object containing information about a finished build. + * A {@code BuildTracker} tracks a build in which configuration processing has been + * performed and is responsible for managing the associated state including the resulting + * metadata. * - * @author Kris De Volder + * @author Andy Wilkinson */ -public class BuildResult { +public interface BuildHandler { - public final ConfigurationMetadata metadata; + void addGroup(String name, String type, String sourceType, String sourceMethod); - public final Set processedTypes; + void addProperty(String prefix, String name, String type, String sourceType, + String sourceMethod, String description, Object defaultValue, + boolean deprecated); - public final boolean isIncremental; + void processing(RoundEnvironment environment); - public BuildResult(boolean isIncremental, ConfigurationMetadata metadata, - Set processedTypes) { - this.isIncremental = isIncremental; - this.metadata = metadata; - this.processedTypes = processedTypes; - } - - public BuildResult(TestConfigurationMetadataAnnotationProcessor processor) { - this(processor.isIncremental(), processor.getMetadata(), - processor.processedSourceTypes); - } + ConfigurationMetadata produceMetadata(); } diff --git a/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/ConfigurationMetadataAnnotationProcessor.java b/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/ConfigurationMetadataAnnotationProcessor.java index ee810139b6..32830eae99 100644 --- a/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/ConfigurationMetadataAnnotationProcessor.java +++ b/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/ConfigurationMetadataAnnotationProcessor.java @@ -16,18 +16,12 @@ package org.springframework.boot.configurationprocessor; -import java.io.File; -import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; import java.io.PrintWriter; import java.io.StringWriter; import java.util.Collections; -import java.util.HashSet; import java.util.LinkedHashMap; -import java.util.List; import java.util.Map; import java.util.Set; @@ -49,14 +43,10 @@ import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; import javax.lang.model.util.Elements; import javax.tools.Diagnostic.Kind; -import javax.tools.FileObject; -import javax.tools.StandardLocation; import org.springframework.boot.configurationprocessor.fieldvalues.FieldValuesParser; import org.springframework.boot.configurationprocessor.fieldvalues.javac.JavaCompilerFieldValuesParser; import org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata; -import org.springframework.boot.configurationprocessor.metadata.ItemMetadata; -import org.springframework.boot.configurationprocessor.metadata.JsonMarshaller; /** * Annotation {@link Processor} that writes meta-data file for @@ -70,8 +60,6 @@ import org.springframework.boot.configurationprocessor.metadata.JsonMarshaller; @SupportedAnnotationTypes({ "*" }) public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor { - public static final String METADATA_PATH = "META-INF/spring-configuration-metadata.json"; - static final String CONFIGURATION_PROPERTIES_ANNOTATION = "org.springframework.boot." + "context.properties.ConfigurationProperties"; @@ -84,22 +72,9 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor static final String LOMBOK_SETTER_ANNOTATION = "lombok.Setter"; - private static final String RESOURCES_FOLDER = "resources"; + private MetadataStore metadataStore; - private static final String CLASSES_FOLDER = "classes"; - - private ConfigurationMetadata metadata; - - /** - * On incremental builds, holds the 'old' metadata (created by the previous build). - */ - private ConfigurationMetadata oldmetadata; - - /** - * On incremental builds, keeps track of the types that where presented to the - * processor. This includes types that are not annotated. - */ - protected Set processedSourceTypes; + private BuildHandler buildHandler; private TypeUtils typeUtils; @@ -123,12 +98,9 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor @Override public synchronized void init(ProcessingEnvironment env) { super.init(env); - this.metadata = new ConfigurationMetadata(); this.typeUtils = new TypeUtils(env); - this.oldmetadata = readMetadata(); - if (isIncremental()) { - this.processedSourceTypes = new HashSet(); - } + this.metadataStore = new MetadataStore(env); + this.buildHandler = createBuildHandler(env, this.metadataStore); try { this.fieldValuesParser = new JavaCompilerFieldValuesParser(env); } @@ -139,43 +111,28 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor } } - protected boolean isIncremental() { - return this.oldmetadata != null; - } - - protected boolean isDeleted(String sourceType) { - return this.processingEnv.getElementUtils().getTypeElement(sourceType) == null; - } - - protected boolean isProcessed(String sourceType) { - return this.processedSourceTypes.contains(sourceType); - } - - /** - * Called during incremental build on all the 'root elements' that are being presented - * to the processor. - */ - protected void markAsProcessed(Element element) { - if (element instanceof TypeElement) { - this.processedSourceTypes.add(this.typeUtils.getType(element)); + private BuildHandler createBuildHandler(ProcessingEnvironment env, + MetadataStore metadataStore) { + ConfigurationMetadata existingMetadata = metadataStore.readMetadata(); + if (existingMetadata != null) { + return new IncrementalBuildHandler(env, existingMetadata); + } + else { + return new StandardBuildHandler(); } } @Override public boolean process(Set annotations, RoundEnvironment roundEnv) { + this.buildHandler.processing(roundEnv); Elements elementUtils = this.processingEnv.getElementUtils(); - if (isIncremental()) { - for (Element element : roundEnv.getRootElements()) { - markAsProcessed(element); - } - } for (Element element : roundEnv.getElementsAnnotatedWith(elementUtils .getTypeElement(configurationPropertiesAnnotation()))) { processElement(element); } if (roundEnv.processingOver()) { - writeMetaData(this.metadata); + writeMetaData(); } return false; } @@ -196,7 +153,7 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor private void processAnnotatedTypeElement(String prefix, TypeElement element) { String type = this.typeUtils.getType(element); - this.metadata.add(ItemMetadata.newGroup(prefix, type, type, null)); + this.buildHandler.addGroup(prefix, type, type, null); processTypeElement(prefix, element); } @@ -206,10 +163,9 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor Element returns = this.processingEnv.getTypeUtils().asElement( element.getReturnType()); if (returns instanceof TypeElement) { - this.metadata.add(ItemMetadata.newGroup(prefix, - this.typeUtils.getType(returns), + this.buildHandler.addGroup(prefix, this.typeUtils.getType(returns), this.typeUtils.getType(element.getEnclosingElement()), - element.toString())); + element.toString()); processTypeElement(prefix, (TypeElement) returns); } } @@ -254,8 +210,8 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor boolean deprecated = hasDeprecateAnnotation(getter) || hasDeprecateAnnotation(setter) || hasDeprecateAnnotation(element); - this.metadata.add(ItemMetadata.newProperty(prefix, name, dataType, - sourceType, null, description, defaultValue, deprecated)); + this.buildHandler.addProperty(prefix, name, dataType, sourceType, null, + description, defaultValue, deprecated); } } } @@ -282,8 +238,8 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor Object defaultValue = fieldValues.get(name); boolean deprecated = hasDeprecateAnnotation(field) || hasDeprecateAnnotation(element); - this.metadata.add(ItemMetadata.newProperty(prefix, name, dataType, - sourceType, null, description, defaultValue, deprecated)); + this.buildHandler.addProperty(prefix, name, dataType, sourceType, null, + description, defaultValue, deprecated); } } } @@ -316,9 +272,9 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor if (returnType != null && returnType instanceof TypeElement && annotation == null && isNested) { String nestedPrefix = ConfigurationMetadata.nestedPrefix(prefix, name); - this.metadata.add(ItemMetadata.newGroup(nestedPrefix, + this.buildHandler.addGroup(nestedPrefix, this.typeUtils.getType(returnType), - this.typeUtils.getType(element), getter.toString())); + this.typeUtils.getType(element), getter.toString()); processTypeElement(nestedPrefix, (TypeElement) returnType); } } @@ -375,89 +331,33 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor return values; } - protected ConfigurationMetadata writeMetaData(ConfigurationMetadata metadata) { + protected ConfigurationMetadata writeMetaData() { + ConfigurationMetadata metadata = this.buildHandler.produceMetadata(); metadata = mergeAdditionalMetadata(metadata); - if (isIncremental()) { - mergeOldMetadata(metadata); - } if (!metadata.getItems().isEmpty()) { try { - FileObject resource = this.processingEnv.getFiler().createResource( - StandardLocation.CLASS_OUTPUT, "", METADATA_PATH); - OutputStream outputStream = resource.openOutputStream(); - try { - new JsonMarshaller().write(metadata, outputStream); - return metadata; - } - finally { - outputStream.close(); - } + this.metadataStore.writeMetadata(metadata); } - catch (Exception ex) { - throw new IllegalStateException(ex); + catch (IOException ex) { + throw new IllegalStateException("Failed to write metadata", ex); } + return metadata; } return null; } - protected ConfigurationMetadata readMetadata() { - try { - FileObject resource = this.processingEnv.getFiler().getResource( - StandardLocation.CLASS_OUTPUT, "", METADATA_PATH); - InputStream in = resource.openInputStream(); - try { - ConfigurationMetadata data = new ConfigurationMetadata(); - data.addAll(new JsonMarshaller().read(in)); - if (!data.getItems().isEmpty()) { - return data; - } - } - finally { - in.close(); - } - } - catch (IOException e) { - // no 'old' metadata - } - return null; - } - - private void mergeOldMetadata(ConfigurationMetadata metadata) { - List items = this.oldmetadata.getItems(); - for (ItemMetadata oldItem : items) { - String sourceType = oldItem.getSourceType(); - if (sourceType == null || isProcessed(sourceType) || isDeleted(sourceType)) { - // skip - } - else { - metadata.add(oldItem); - } - } - } - private ConfigurationMetadata mergeAdditionalMetadata(ConfigurationMetadata metadata) { try { - InputStream inputStream = getAdditionalMetadata(); - try { - ConfigurationMetadata merged = new ConfigurationMetadata(metadata); - try { - merged.addAll(new JsonMarshaller().read(inputStream)); - } - catch (Exception ex) { - throw new IllegalStateException(ex); - } - return merged; - } - finally { - inputStream.close(); - } + ConfigurationMetadata merged = new ConfigurationMetadata(metadata); + merged.addAll(this.metadataStore.readAdditionalMetadata()); + return merged; } catch (FileNotFoundException ex) { // No additional metadata return metadata; } catch (Exception ex) { - logWarning("Unable to merge additional-spring-configuration-metadata.json"); + logWarning("Unable to merge additional metadata"); logWarning(getStackTrace(ex)); return metadata; } @@ -469,26 +369,6 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor return writer.toString(); } - private InputStream getAdditionalMetadata() throws IOException { - // Most build systems will have copied the file to the class output location - FileObject fileObject = this.processingEnv.getFiler().createResource( - StandardLocation.CLASS_OUTPUT, "", - "META-INF/additional-spring-configuration-metadata.json"); - File file = new File(fileObject.toUri()); - if (!file.exists()) { - // Gradle keeps things separate - String path = file.getPath(); - int index = path.lastIndexOf(CLASSES_FOLDER); - if (index >= 0) { - path = path.substring(0, index) + RESOURCES_FOLDER - + path.substring(index + CLASSES_FOLDER.length()); - file = new File(path); - } - } - return (file.exists() ? new FileInputStream(file) : fileObject.toUri().toURL() - .openStream()); - } - private void logWarning(String msg) { this.processingEnv.getMessager().printMessage(Kind.WARNING, msg); } diff --git a/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/IncrementalBuildHandler.java b/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/IncrementalBuildHandler.java new file mode 100644 index 0000000000..e480a667bc --- /dev/null +++ b/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/IncrementalBuildHandler.java @@ -0,0 +1,109 @@ +/* + * Copyright 2012-2014 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.HashSet; +import java.util.List; +import java.util.Set; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.annotation.processing.RoundEnvironment; +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; + +import org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata; +import org.springframework.boot.configurationprocessor.metadata.ItemMetadata; + +/** + * {@code BuildHandler} that provides incremental build support by merging the metadata + * from the current incremental build with any existing metadata. + * + * @author Andy Wilkinson + * @author Kris De Volder + * @since 1.2.2 + */ +public class IncrementalBuildHandler extends StandardBuildHandler { + + private final Set processedSourceTypes = new HashSet(); + + private final ProcessingEnvironment processingEnvironment; + + private final ConfigurationMetadata existingMetadata; + + private final TypeUtils typeUtils; + + /** + * Creates a new {@code IncrementalBuildTracker} that will merge the metadata produced + * by an incremental build with the given {@code existingMetadata}. + * + * @param processingEnvironment The processing environment of the build + * @param existingMetadata The existing metadata + */ + public IncrementalBuildHandler(ProcessingEnvironment processingEnvironment, + ConfigurationMetadata existingMetadata) { + this.existingMetadata = existingMetadata; + this.processingEnvironment = processingEnvironment; + this.typeUtils = new TypeUtils(processingEnvironment); + } + + @Override + public void processing(RoundEnvironment environment) { + for (Element element : environment.getRootElements()) { + markAsProcessed(element); + } + } + + @Override + public ConfigurationMetadata produceMetadata() { + ConfigurationMetadata metadata = super.produceMetadata(); + mergeExistingMetadata(metadata); + return metadata; + } + + private void markAsProcessed(Element element) { + if (element instanceof TypeElement) { + this.processedSourceTypes.add(this.typeUtils.getType(element)); + } + } + + private void mergeExistingMetadata(ConfigurationMetadata metadata) { + List items = this.existingMetadata.getItems(); + for (ItemMetadata oldItem : items) { + if (shouldBeMerged(oldItem)) { + metadata.add(oldItem); + } + } + } + + private boolean shouldBeMerged(ItemMetadata itemMetadata) { + String sourceType = itemMetadata.getSourceType(); + if (sourceType == null || deletedInCurrentBuild(sourceType) + || processedInCurrentBuild(sourceType)) { + return false; + } + return true; + } + + private boolean deletedInCurrentBuild(String sourceType) { + return this.processingEnvironment.getElementUtils().getTypeElement(sourceType) == null; + } + + private boolean processedInCurrentBuild(String sourceType) { + return this.processedSourceTypes.contains(sourceType); + } + +} diff --git a/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/MetadataStore.java b/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/MetadataStore.java new file mode 100644 index 0000000000..154b26ffb9 --- /dev/null +++ b/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/MetadataStore.java @@ -0,0 +1,122 @@ +/* + * 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.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.tools.FileObject; +import javax.tools.StandardLocation; + +import org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata; +import org.springframework.boot.configurationprocessor.metadata.JsonMarshaller; + +/** + * A {@code MetadataStore} is responsible for the storage of metadata on the filesystem + * + * @author Andy Wilkinson + * @since 1.2.2 + */ +public class MetadataStore { + + static final String METADATA_PATH = "META-INF/spring-configuration-metadata.json"; + + private static final String ADDITIONAL_METADATA_PATH = "META-INF/additional-spring-configuration-metadata.json"; + + private static final String RESOURCES_FOLDER = "resources"; + + private static final String CLASSES_FOLDER = "classes"; + + private final ProcessingEnvironment environment; + + public MetadataStore(ProcessingEnvironment environment) { + this.environment = environment; + } + + public ConfigurationMetadata readMetadata() { + try { + return readMetadata(getMetadataResource().openInputStream()); + } + catch (IOException ex) { + return null; + } + } + + public void writeMetadata(ConfigurationMetadata metadata) throws IOException { + if (!metadata.getItems().isEmpty()) { + OutputStream outputStream = createMetadataResource().openOutputStream(); + try { + new JsonMarshaller().write(metadata, outputStream); + } + finally { + outputStream.close(); + } + } + } + + public ConfigurationMetadata readAdditionalMetadata() throws IOException { + return readMetadata(getAdditionalMetadataStream()); + } + + private ConfigurationMetadata readMetadata(InputStream in) throws IOException { + try { + return new JsonMarshaller().read(in); + } + catch (IOException ex) { + return null; + } + finally { + in.close(); + } + } + + private FileObject getMetadataResource() throws IOException { + FileObject resource = this.environment.getFiler().getResource( + StandardLocation.CLASS_OUTPUT, "", METADATA_PATH); + return resource; + } + + private FileObject createMetadataResource() throws IOException { + FileObject resource = this.environment.getFiler().createResource( + StandardLocation.CLASS_OUTPUT, "", METADATA_PATH); + return resource; + } + + private InputStream getAdditionalMetadataStream() throws IOException { + // Most build systems will have copied the file to the class output location + FileObject fileObject = this.environment.getFiler().getResource( + StandardLocation.CLASS_OUTPUT, "", ADDITIONAL_METADATA_PATH); + File file = new File(fileObject.toUri()); + if (!file.exists()) { + // Gradle keeps things separate + String path = file.getPath(); + int index = path.lastIndexOf(CLASSES_FOLDER); + if (index >= 0) { + path = path.substring(0, index) + RESOURCES_FOLDER + + path.substring(index + CLASSES_FOLDER.length()); + file = new File(path); + } + } + return (file.exists() ? new FileInputStream(file) : fileObject.toUri().toURL() + .openStream()); + } + +} diff --git a/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/StandardBuildHandler.java b/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/StandardBuildHandler.java new file mode 100644 index 0000000000..7e60315b76 --- /dev/null +++ b/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/StandardBuildHandler.java @@ -0,0 +1,58 @@ +/* + * Copyright 2012-2014 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 javax.annotation.processing.RoundEnvironment; + +import org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata; +import org.springframework.boot.configurationprocessor.metadata.ItemMetadata; + +/** + * Standard implementation of {@code BuildHandler} that handles the state of a single + * build. + * + * @author Andy Wilkinson + * @since 1.2.2 + */ +public class StandardBuildHandler implements BuildHandler { + + private final ConfigurationMetadata metadata = new ConfigurationMetadata(); + + @Override + public void addGroup(String name, String type, String sourceType, String sourceMethod) { + this.metadata.add(ItemMetadata.newGroup(name, type, sourceType, sourceMethod)); + } + + @Override + public void addProperty(String prefix, String name, String type, String sourceType, + String sourceMethod, String description, Object defaultValue, + boolean deprecated) { + this.metadata.add(ItemMetadata.newProperty(prefix, name, type, sourceType, + sourceMethod, description, defaultValue, deprecated)); + } + + @Override + public void processing(RoundEnvironment environment) { + + } + + @Override + public ConfigurationMetadata produceMetadata() { + return this.metadata; + } + +} diff --git a/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/ConfigurationMetadataAnnotationProcessorTests.java b/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/ConfigurationMetadataAnnotationProcessorTests.java index 207a397c6a..f843670be1 100644 --- a/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/ConfigurationMetadataAnnotationProcessorTests.java +++ b/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/ConfigurationMetadataAnnotationProcessorTests.java @@ -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, diff --git a/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/TestConfigurationMetadataAnnotationProcessor.java b/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/TestConfigurationMetadataAnnotationProcessor.java index 4964d7506b..6ed037db89 100644 --- a/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/TestConfigurationMetadataAnnotationProcessor.java +++ b/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/TestConfigurationMetadataAnnotationProcessor.java @@ -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 getProcessedTypes() { - return this.processedSourceTypes; - } - - @Override - public boolean isIncremental() { - return super.isIncremental(); - } } \ No newline at end of file diff --git a/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/TestProject.java b/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/TestProject.java index d17a9b1a87..23b6eeb578 100644 --- a/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/TestProject.java +++ b/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/TestProject.java @@ -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 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); } diff --git a/spring-boot-tools/spring-boot-configuration-processor/src/test/resources/org/springframework/boot/configurationsample/incremental/BarProperties.snippet b/spring-boot-tools/spring-boot-configuration-processor/src/test/resources/org/springframework/boot/configurationsample/incremental/BarProperties.snippet new file mode 100644 index 0000000000..a9f7727aa6 --- /dev/null +++ b/spring-boot-tools/spring-boot-configuration-processor/src/test/resources/org/springframework/boot/configurationsample/incremental/BarProperties.snippet @@ -0,0 +1,9 @@ + private String extra; + + public String getExtra() { + return extra; + } + + public void setExtra(String extra) { + this.extra = extra; + } \ No newline at end of file