Merge branch 'gh-2313'
This commit is contained in:
@@ -29,6 +29,10 @@
|
||||
<artifactId>lombok</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
@@ -36,7 +40,7 @@
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<!-- Ensure own annotation processor doens't kick in -->
|
||||
<!-- Ensure own annotation processor doesn't kick in -->
|
||||
<proc>none</proc>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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 javax.annotation.processing.RoundEnvironment;
|
||||
|
||||
import org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata;
|
||||
|
||||
/**
|
||||
* 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 Andy Wilkinson
|
||||
*/
|
||||
public interface BuildHandler {
|
||||
|
||||
void addGroup(String name, String type, String sourceType, String sourceMethod);
|
||||
|
||||
void addProperty(String prefix, String name, String type, String sourceType,
|
||||
String sourceMethod, String description, Object defaultValue,
|
||||
boolean deprecated);
|
||||
|
||||
void processing(RoundEnvironment environment);
|
||||
|
||||
ConfigurationMetadata produceMetadata();
|
||||
|
||||
}
|
||||
@@ -16,12 +16,8 @@
|
||||
|
||||
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;
|
||||
@@ -47,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
|
||||
@@ -62,6 +54,7 @@ import org.springframework.boot.configurationprocessor.metadata.JsonMarshaller;
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Phillip Webb
|
||||
* @author Kris De Volder
|
||||
* @since 1.2.0
|
||||
*/
|
||||
@SupportedAnnotationTypes({ "*" })
|
||||
@@ -79,11 +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;
|
||||
private BuildHandler buildHandler;
|
||||
|
||||
private TypeUtils typeUtils;
|
||||
|
||||
@@ -107,8 +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.metadataStore = new MetadataStore(env);
|
||||
this.buildHandler = createBuildHandler(env, this.metadataStore);
|
||||
try {
|
||||
this.fieldValuesParser = new JavaCompilerFieldValuesParser(env);
|
||||
}
|
||||
@@ -119,16 +111,28 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor
|
||||
}
|
||||
}
|
||||
|
||||
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<? extends TypeElement> annotations,
|
||||
RoundEnvironment roundEnv) {
|
||||
this.buildHandler.processing(roundEnv);
|
||||
Elements elementUtils = this.processingEnv.getElementUtils();
|
||||
for (Element element : roundEnv.getElementsAnnotatedWith(elementUtils
|
||||
.getTypeElement(configurationPropertiesAnnotation()))) {
|
||||
processElement(element);
|
||||
}
|
||||
if (roundEnv.processingOver()) {
|
||||
writeMetaData(this.metadata);
|
||||
writeMetaData();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -149,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);
|
||||
}
|
||||
|
||||
@@ -159,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);
|
||||
}
|
||||
}
|
||||
@@ -207,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -235,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -269,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);
|
||||
}
|
||||
}
|
||||
@@ -328,50 +331,33 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor
|
||||
return values;
|
||||
}
|
||||
|
||||
protected void writeMetaData(ConfigurationMetadata metadata) {
|
||||
protected ConfigurationMetadata writeMetaData() {
|
||||
ConfigurationMetadata metadata = this.buildHandler.produceMetadata();
|
||||
metadata = mergeAdditionalMetadata(metadata);
|
||||
if (!metadata.getItems().isEmpty()) {
|
||||
try {
|
||||
FileObject resource = this.processingEnv.getFiler().createResource(
|
||||
StandardLocation.CLASS_OUTPUT, "",
|
||||
"META-INF/spring-configuration-metadata.json");
|
||||
OutputStream outputStream = resource.openOutputStream();
|
||||
try {
|
||||
new JsonMarshaller().write(metadata, outputStream);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -383,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);
|
||||
}
|
||||
|
||||
@@ -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<String> processedSourceTypes = new HashSet<String>();
|
||||
|
||||
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<ItemMetadata> 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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,14 +17,9 @@
|
||||
package org.springframework.boot.configurationprocessor;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.annotation.processing.SupportedAnnotationTypes;
|
||||
import javax.annotation.processing.SupportedSourceVersion;
|
||||
import javax.lang.model.SourceVersion;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import org.junit.Before;
|
||||
@@ -32,7 +27,9 @@ import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata;
|
||||
import org.springframework.boot.configurationprocessor.metadata.JsonMarshaller;
|
||||
import org.springframework.boot.configurationsample.incremental.BarProperties;
|
||||
import org.springframework.boot.configurationsample.incremental.FooProperties;
|
||||
import org.springframework.boot.configurationsample.incremental.RenamedBarProperties;
|
||||
import org.springframework.boot.configurationsample.lombok.LombokExplicitProperties;
|
||||
import org.springframework.boot.configurationsample.lombok.LombokSimpleDataProperties;
|
||||
import org.springframework.boot.configurationsample.lombok.LombokSimpleProperties;
|
||||
@@ -57,9 +54,12 @@ import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
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.ConfigurationMetadataMatchers.containsGroup;
|
||||
import static org.springframework.boot.configurationprocessor.ConfigurationMetadataMatchers.containsProperty;
|
||||
import static org.springframework.boot.configurationprocessor.MetadataStore.METADATA_PATH;
|
||||
|
||||
/**
|
||||
* Tests for {@link ConfigurationMetadataAnnotationProcessor}.
|
||||
@@ -67,6 +67,7 @@ import static org.springframework.boot.configurationprocessor.ConfigurationMetad
|
||||
* @author Stephane Nicoll
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
* @author Kris De Volder
|
||||
*/
|
||||
public class ConfigurationMetadataAnnotationProcessorTests {
|
||||
|
||||
@@ -349,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,
|
||||
@@ -368,59 +442,12 @@ public class ConfigurationMetadataAnnotationProcessorTests {
|
||||
}
|
||||
|
||||
private ConfigurationMetadata compile(Class<?>... types) throws IOException {
|
||||
TestConfigurationMetadataAnnotationProcessor processor = new TestConfigurationMetadataAnnotationProcessor();
|
||||
TestConfigurationMetadataAnnotationProcessor processor = new TestConfigurationMetadataAnnotationProcessor(
|
||||
this.compiler.getOutputLocation());
|
||||
this.compiler.getTask(types).call(processor);
|
||||
return processor.getMetadata();
|
||||
}
|
||||
|
||||
@SupportedAnnotationTypes({ "*" })
|
||||
@SupportedSourceVersion(SourceVersion.RELEASE_6)
|
||||
private class TestConfigurationMetadataAnnotationProcessor extends
|
||||
ConfigurationMetadataAnnotationProcessor {
|
||||
|
||||
static final String CONFIGURATION_PROPERTIES_ANNOTATION = "org.springframework.boot.configurationsample.ConfigurationProperties";
|
||||
|
||||
static final String NESTED_CONFIGURATION_PROPERTY_ANNOTATION = "org.springframework.boot.configurationsample.NestedConfigurationProperty";
|
||||
|
||||
private ConfigurationMetadata metadata;
|
||||
|
||||
@Override
|
||||
protected String configurationPropertiesAnnotation() {
|
||||
return CONFIGURATION_PROPERTIES_ANNOTATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String nestedConfigurationPropertyAnnotation() {
|
||||
return NESTED_CONFIGURATION_PROPERTY_ANNOTATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeMetaData(ConfigurationMetadata metadata) {
|
||||
super.writeMetaData(metadata);
|
||||
try {
|
||||
File metadataFile = new File(
|
||||
ConfigurationMetadataAnnotationProcessorTests.this.compiler
|
||||
.getOutputLocation(),
|
||||
"META-INF/spring-configuration-metadata.json");
|
||||
if (metadataFile.isFile()) {
|
||||
this.metadata = new JsonMarshaller().read(new FileInputStream(
|
||||
metadataFile));
|
||||
}
|
||||
else {
|
||||
this.metadata = metadata;
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException("Failed to read metadata from disk", e);
|
||||
}
|
||||
}
|
||||
|
||||
public ConfigurationMetadata getMetadata() {
|
||||
return this.metadata;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class AdditionalMetadata {
|
||||
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.springframework.boot.configurationprocessor;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.annotation.processing.Processor;
|
||||
import javax.tools.JavaCompiler;
|
||||
@@ -39,6 +40,8 @@ import org.junit.rules.TemporaryFolder;
|
||||
*/
|
||||
public class TestCompiler {
|
||||
|
||||
public static final File ORIGINAL_SOURCE_FOLDER = new File("src/test/java");
|
||||
|
||||
private final JavaCompiler compiler;
|
||||
|
||||
private final StandardJavaFileManager fileManager;
|
||||
@@ -59,8 +62,18 @@ public class TestCompiler {
|
||||
this.fileManager.setLocation(StandardLocation.SOURCE_OUTPUT, temp);
|
||||
}
|
||||
|
||||
public TestCompilationTask getTask(Collection<File> sourceFiles) {
|
||||
Iterable<? extends JavaFileObject> javaFileObjects = this.fileManager
|
||||
.getJavaFileObjectsFromFiles(sourceFiles);
|
||||
return getTask(javaFileObjects);
|
||||
}
|
||||
|
||||
public TestCompilationTask getTask(Class<?>... types) {
|
||||
Iterable<? extends JavaFileObject> javaFileObjects = getJavaFileObjects(types);
|
||||
return getTask(javaFileObjects);
|
||||
}
|
||||
|
||||
private TestCompilationTask getTask(Iterable<? extends JavaFileObject> javaFileObjects) {
|
||||
return new TestCompilationTask(this.compiler.getTask(null, this.fileManager,
|
||||
null, null, null, javaFileObjects));
|
||||
}
|
||||
@@ -77,8 +90,16 @@ public class TestCompiler {
|
||||
return this.fileManager.getJavaFileObjects(files);
|
||||
}
|
||||
|
||||
private File getFile(Class<?> type) {
|
||||
return new File("src/test/java/" + type.getName().replace(".", "/") + ".java");
|
||||
protected File getFile(Class<?> type) {
|
||||
return new File(getSourceFolder(), sourcePathFor(type));
|
||||
}
|
||||
|
||||
public static String sourcePathFor(Class<?> type) {
|
||||
return type.getName().replace(".", "/") + ".java";
|
||||
}
|
||||
|
||||
protected File getSourceFolder() {
|
||||
return ORIGINAL_SOURCE_FOLDER;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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 javax.annotation.processing.SupportedAnnotationTypes;
|
||||
import javax.annotation.processing.SupportedSourceVersion;
|
||||
import javax.lang.model.SourceVersion;
|
||||
|
||||
import org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata;
|
||||
import org.springframework.boot.configurationprocessor.metadata.JsonMarshaller;
|
||||
|
||||
/**
|
||||
* @author Stephane Nicoll
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
* @author Kris De Volder
|
||||
*/
|
||||
@SupportedAnnotationTypes({ "*" })
|
||||
@SupportedSourceVersion(SourceVersion.RELEASE_6)
|
||||
public class TestConfigurationMetadataAnnotationProcessor extends
|
||||
ConfigurationMetadataAnnotationProcessor {
|
||||
|
||||
static final String CONFIGURATION_PROPERTIES_ANNOTATION = "org.springframework.boot.configurationsample.ConfigurationProperties";
|
||||
|
||||
static final String NESTED_CONFIGURATION_PROPERTY_ANNOTATION = "org.springframework.boot.configurationsample.NestedConfigurationProperty";
|
||||
|
||||
private ConfigurationMetadata metadata;
|
||||
|
||||
private final File outputLocation;
|
||||
|
||||
public TestConfigurationMetadataAnnotationProcessor(File outputLocation) {
|
||||
this.outputLocation = outputLocation;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String configurationPropertiesAnnotation() {
|
||||
return CONFIGURATION_PROPERTIES_ANNOTATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String nestedConfigurationPropertyAnnotation() {
|
||||
return NESTED_CONFIGURATION_PROPERTY_ANNOTATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ConfigurationMetadata writeMetaData() {
|
||||
super.writeMetaData();
|
||||
try {
|
||||
File metadataFile = new File(this.outputLocation,
|
||||
"META-INF/spring-configuration-metadata.json");
|
||||
if (metadataFile.isFile()) {
|
||||
this.metadata = new JsonMarshaller().read(new FileInputStream(
|
||||
metadataFile));
|
||||
}
|
||||
else {
|
||||
this.metadata = new ConfigurationMetadata();
|
||||
}
|
||||
return this.metadata;
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException("Failed to read metadata from disk", e);
|
||||
}
|
||||
}
|
||||
|
||||
public ConfigurationMetadata getMetadata() {
|
||||
return this.metadata;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* 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.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;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
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.util.FileCopyUtils;
|
||||
import org.springframework.util.FileSystemUtils;
|
||||
|
||||
import static org.springframework.boot.configurationprocessor.TestCompiler.ORIGINAL_SOURCE_FOLDER;
|
||||
import static org.springframework.boot.configurationprocessor.TestCompiler.sourcePathFor;
|
||||
|
||||
/**
|
||||
* A TestProject contains a copy of a subset of test sample code.
|
||||
* <p>
|
||||
* Why a copy? Because when doing incremental build testing, we need to make modifications
|
||||
* to the contents of the 'test project'. But we don't want to actually modify the
|
||||
* original content itself.
|
||||
*
|
||||
* @author Kris De Volder
|
||||
*/
|
||||
public class TestProject {
|
||||
|
||||
private static final Class<?>[] ALWAYS_INCLUDE = { ConfigurationProperties.class,
|
||||
NestedConfigurationProperty.class };
|
||||
|
||||
/**
|
||||
* Contains copies of the original source so we can modify it safely to test
|
||||
* incremental builds.
|
||||
*/
|
||||
private File sourceFolder;
|
||||
private TestCompiler compiler;
|
||||
|
||||
private Set<File> sourceFiles = new LinkedHashSet<File>();
|
||||
|
||||
public TestProject(TemporaryFolder tempFolder, Class<?>... classes)
|
||||
throws IOException {
|
||||
this.sourceFolder = tempFolder.newFolder();
|
||||
this.compiler = new TestCompiler(tempFolder) {
|
||||
@Override
|
||||
protected File getSourceFolder() {
|
||||
return TestProject.this.sourceFolder;
|
||||
}
|
||||
};
|
||||
Set<Class<?>> contents = new HashSet<Class<?>>(Arrays.asList(classes));
|
||||
contents.addAll(Arrays.asList(ALWAYS_INCLUDE));
|
||||
copySources(contents);
|
||||
}
|
||||
|
||||
private void copySources(Set<Class<?>> contents) throws IOException {
|
||||
for (Class<?> klass : contents) {
|
||||
copySources(klass);
|
||||
}
|
||||
}
|
||||
|
||||
private void copySources(Class<?> klass) throws IOException {
|
||||
File original = getOriginalSourceFile(klass);
|
||||
File target = getSourceFile(klass);
|
||||
target.getParentFile().mkdirs();
|
||||
FileCopyUtils.copy(original, target);
|
||||
this.sourceFiles.add(target);
|
||||
}
|
||||
|
||||
public File getSourceFile(Class<?> klass) {
|
||||
return new File(this.sourceFolder, sourcePathFor(klass));
|
||||
}
|
||||
|
||||
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 processor.getMetadata();
|
||||
}
|
||||
|
||||
public ConfigurationMetadata incrementalBuild(Class<?>... toRecompile) {
|
||||
TestConfigurationMetadataAnnotationProcessor processor = new TestConfigurationMetadataAnnotationProcessor(
|
||||
this.compiler.getOutputLocation());
|
||||
TestCompilationTask task = this.compiler.getTask(toRecompile);
|
||||
task.call(processor);
|
||||
return processor.getMetadata();
|
||||
}
|
||||
|
||||
private void deleteFolderContents(File outputFolder) {
|
||||
FileSystemUtils.deleteRecursively(outputFolder);
|
||||
outputFolder.mkdirs();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve File relative to project's output folder.
|
||||
*/
|
||||
public File getOutputFile(String relativePath) {
|
||||
Assert.assertFalse(new File(relativePath).isAbsolute());
|
||||
return new File(this.compiler.getOutputLocation(), relativePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add source code at the end of file, just before last '}'
|
||||
*/
|
||||
public void addSourceCode(Class<?> target, InputStream snippetStream)
|
||||
throws Exception {
|
||||
File targetFile = getSourceFile(target);
|
||||
String contents = getContents(targetFile);
|
||||
int insertAt = contents.lastIndexOf('}');
|
||||
String additionalSource = FileCopyUtils.copyToString(new InputStreamReader(
|
||||
snippetStream));
|
||||
contents = contents.substring(0, insertAt) + additionalSource
|
||||
+ contents.substring(insertAt);
|
||||
putContents(targetFile, contents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete source file for given class from project.
|
||||
*/
|
||||
public void delete(Class<?> klass) {
|
||||
File target = getSourceFile(klass);
|
||||
target.delete();
|
||||
this.sourceFiles.remove(target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore source code of given class to its original contents.
|
||||
*/
|
||||
public void revert(Class<?> klass) throws IOException {
|
||||
Assert.assertTrue(getSourceFile(klass).exists());
|
||||
copySources(klass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add source code of given class to this project.
|
||||
*/
|
||||
public void add(Class<?> klass) throws IOException {
|
||||
Assert.assertFalse(getSourceFile(klass).exists());
|
||||
copySources(klass);
|
||||
}
|
||||
|
||||
public void replaceText(Class<?> klass, String find, String replace) throws Exception {
|
||||
File target = getSourceFile(klass);
|
||||
String contents = getContents(target);
|
||||
contents = contents.replace(find, replace);
|
||||
putContents(target, contents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the 'original' source code for given test class. Clients or subclasses should
|
||||
* have no need to know about these. They should work only with the copied source
|
||||
* code.
|
||||
*/
|
||||
private File getOriginalSourceFile(Class<?> klass) {
|
||||
return new File(ORIGINAL_SOURCE_FOLDER, sourcePathFor(klass));
|
||||
}
|
||||
|
||||
private static void putContents(File targetFile, String contents)
|
||||
throws FileNotFoundException, IOException, UnsupportedEncodingException {
|
||||
FileCopyUtils.copy(new StringReader(contents), new FileWriter(targetFile));
|
||||
}
|
||||
|
||||
private static String getContents(File file) throws Exception {
|
||||
return FileCopyUtils.copyToString(new FileReader(file));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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.configurationsample.incremental;
|
||||
|
||||
import org.springframework.boot.configurationsample.ConfigurationProperties;
|
||||
|
||||
@ConfigurationProperties("bar")
|
||||
public class BarProperties {
|
||||
|
||||
private String name;
|
||||
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* A nice counter description.
|
||||
*/
|
||||
private Integer counter = 0;
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return this.description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public Integer getCounter() {
|
||||
return this.counter;
|
||||
}
|
||||
|
||||
public void setCounter(Integer counter) {
|
||||
this.counter = counter;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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.configurationsample.incremental;
|
||||
|
||||
import org.springframework.boot.configurationsample.ConfigurationProperties;
|
||||
|
||||
@ConfigurationProperties("foo")
|
||||
public class FooProperties {
|
||||
|
||||
private String name;
|
||||
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* A nice counter description.
|
||||
*/
|
||||
private Integer counter = 0;
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return this.description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public Integer getCounter() {
|
||||
return this.counter;
|
||||
}
|
||||
|
||||
public void setCounter(Integer counter) {
|
||||
this.counter = counter;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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.configurationsample.incremental;
|
||||
|
||||
import org.springframework.boot.configurationsample.ConfigurationProperties;
|
||||
|
||||
@ConfigurationProperties("bar")
|
||||
public class RenamedBarProperties {
|
||||
|
||||
private String name;
|
||||
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* A nice counter description.
|
||||
*/
|
||||
private Integer counter = 0;
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return this.description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public Integer getCounter() {
|
||||
return this.counter;
|
||||
}
|
||||
|
||||
public void setCounter(Integer counter) {
|
||||
this.counter = counter;
|
||||
}
|
||||
}
|
||||
@@ -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