Merge branch 'gh-2313'
commit
afe3bc0938
@ -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();
|
||||||
|
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
Loading…
Reference in New Issue