From e9d252e05c372b446abba3bec23dc75d1dc0a138 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Fri, 17 Jul 2015 14:13:11 -0700 Subject: [PATCH] Add @DeprecatedConfigurationProperties annotation Add a new @DeprecatedConfigurationProperties annotation which can be used by the `ConfigurationMetadataAnnotationProcessor` to generating meta-data deprecated blocks. Fixes gh-3543 --- ...figurationMetadataAnnotationProcessor.java | 36 ++++++++++--- ...ationMetadataAnnotationProcessorTests.java | 12 +++++ ...figurationMetadataAnnotationProcessor.java | 9 +++- .../DeprecatedConfigurationProperty.java | 52 +++++++++++++++++++ .../simple/DeprecatedProperties.java | 4 +- .../simple/DeprecatedSingleProperty.java | 51 ++++++++++++++++++ .../DeprecatedConfigurationProperty.java | 52 +++++++++++++++++++ 7 files changed, 205 insertions(+), 11 deletions(-) create mode 100644 spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/DeprecatedConfigurationProperty.java create mode 100644 spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/simple/DeprecatedSingleProperty.java create mode 100644 spring-boot/src/main/java/org/springframework/boot/context/properties/DeprecatedConfigurationProperty.java 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 634a4a7fb15..c31fed21ac6 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 @@ -69,6 +69,9 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor static final String NESTED_CONFIGURATION_PROPERTY_ANNOTATION = "org.springframework.boot." + "context.properties.NestedConfigurationProperty"; + static final String DEPRECATED_CONFIGURATION_PROPERTY_ANNOTATION = "org.springframework.boot." + + "context.properties.DeprecatedConfigurationProperty"; + static final String LOMBOK_DATA_ANNOTATION = "lombok.Data"; static final String LOMBOK_GETTER_ANNOTATION = "lombok.Getter"; @@ -93,6 +96,10 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor return NESTED_CONFIGURATION_PROPERTY_ANNOTATION; } + protected String deprecatedConfigurationPropertyAnnotation() { + return DEPRECATED_CONFIGURATION_PROPERTY_ANNOTATION; + } + @Override public SourceVersion getSupportedSourceVersion() { return SourceVersion.latestSupported(); @@ -207,16 +214,29 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor String sourceType = this.typeUtils.getType(element); String description = this.typeUtils.getJavaDoc(field); Object defaultValue = fieldValues.get(name); - boolean deprecated = hasDeprecateAnnotation(getter) - || hasDeprecateAnnotation(setter) - || hasDeprecateAnnotation(element); + boolean deprecated = isDeprecated(getter) || isDeprecated(setter) + || isDeprecated(element); this.metadataCollector.add(ItemMetadata.newProperty(prefix, name, dataType, sourceType, null, description, defaultValue, - (deprecated ? new ItemDeprecation() : null))); + (deprecated ? getItemDeprecation(getter) : null))); } } } + private ItemDeprecation getItemDeprecation(ExecutableElement getter) { + AnnotationMirror annotation = getAnnotation(getter, + deprecatedConfigurationPropertyAnnotation()); + String reason = null; + String replacement = null; + if (annotation != null) { + Map elementValues = getAnnotationElementValues(annotation); + reason = (String) elementValues.get("reason"); + replacement = (String) elementValues.get("replacement"); + } + return new ItemDeprecation(("".equals(reason) ? null : reason), + ("".equals(replacement) ? null : replacement)); + } + private void processLombokTypes(String prefix, TypeElement element, TypeElementMembers members, Map fieldValues) { for (Map.Entry entry : members.getFields().entrySet()) { @@ -237,8 +257,7 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor String sourceType = this.typeUtils.getType(element); String description = this.typeUtils.getJavaDoc(field); Object defaultValue = fieldValues.get(name); - boolean deprecated = hasDeprecateAnnotation(field) - || hasDeprecateAnnotation(element); + boolean deprecated = isDeprecated(field) || isDeprecated(element); this.metadataCollector.add(ItemMetadata.newProperty(prefix, name, dataType, sourceType, null, description, defaultValue, (deprecated ? new ItemDeprecation() : null))); @@ -291,8 +310,9 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor && returnType.getKind() != ElementKind.ENUM; } - private boolean hasDeprecateAnnotation(Element element) { - return hasAnnotation(element, "java.lang.Deprecated"); + private boolean isDeprecated(Element element) { + return hasAnnotation(element, "java.lang.Deprecated") + || hasAnnotation(element, deprecatedConfigurationPropertyAnnotation()); } private boolean hasAnnotation(Element element, String type) { 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 bd552c79b90..1cd2205b561 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 @@ -43,6 +43,7 @@ import org.springframework.boot.configurationsample.method.EmptyTypeMethodConfig import org.springframework.boot.configurationsample.method.InvalidMethodConfig; import org.springframework.boot.configurationsample.method.MethodAndClassConfig; import org.springframework.boot.configurationsample.method.SimpleMethodConfig; +import org.springframework.boot.configurationsample.simple.DeprecatedSingleProperty; import org.springframework.boot.configurationsample.simple.HierarchicalProperties; import org.springframework.boot.configurationsample.simple.NotAnnotated; import org.springframework.boot.configurationsample.simple.SimpleCollectionProperties; @@ -188,6 +189,17 @@ public class ConfigurationMetadataAnnotationProcessorTests { .fromSource(type).withDeprecation(null, null)); } + @Test + public void singleDeprecatedProprety() throws Exception { + Class type = DeprecatedSingleProperty.class; + ConfigurationMetadata metadata = compile(type); + assertThat(metadata, containsGroup("singledeprecated").fromSource(type)); + assertThat(metadata, containsProperty("singledeprecated.new-name", String.class) + .fromSource(type)); + assertThat(metadata, containsProperty("singledeprecated.name", String.class) + .fromSource(type).withDeprecation("renamed", "singledeprecated.new-name")); + } + @Test public void parseCollectionConfig() throws Exception { ConfigurationMetadata metadata = compile(SimpleCollectionProperties.class); 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 6ed037db896..5c48b3b8bfd 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 @@ -41,6 +41,8 @@ public class TestConfigurationMetadataAnnotationProcessor extends static final String NESTED_CONFIGURATION_PROPERTY_ANNOTATION = "org.springframework.boot.configurationsample.NestedConfigurationProperty"; + static final String DEPRECATED_CONFIGURATION_PROPERTY_ANNOTATION = "org.springframework.boot.configurationsample.DeprecatedConfigurationProperty"; + private ConfigurationMetadata metadata; private final File outputLocation; @@ -59,6 +61,11 @@ public class TestConfigurationMetadataAnnotationProcessor extends return NESTED_CONFIGURATION_PROPERTY_ANNOTATION; } + @Override + protected String deprecatedConfigurationPropertyAnnotation() { + return DEPRECATED_CONFIGURATION_PROPERTY_ANNOTATION; + } + @Override protected ConfigurationMetadata writeMetaData() { super.writeMetaData(); @@ -83,4 +90,4 @@ public class TestConfigurationMetadataAnnotationProcessor extends return this.metadata; } -} \ No newline at end of file +} diff --git a/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/DeprecatedConfigurationProperty.java b/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/DeprecatedConfigurationProperty.java new file mode 100644 index 00000000000..06e5e9a7fa0 --- /dev/null +++ b/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/DeprecatedConfigurationProperty.java @@ -0,0 +1,52 @@ +/* + * 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; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Indicates that a getter in a {@link ConfigurationProperties} object is deprecated. This + * annotation has no bearing on the actual binding processes, but it is used by the + * {@code spring-boot-configuration-processor} to add deprecation meta-data. + *

+ * This annotation must be used on the getter of the deprecated element. + * + * @author Phillip Webb + * @since 1.3.0 + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface DeprecatedConfigurationProperty { + + /** + * The reason for the deprecation. + * @return the deprecation reason + */ + String reason() default ""; + + /** + * The field that should be used instead (if any). + * @return the replacement field + */ + String replacement() default ""; + +} diff --git a/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/simple/DeprecatedProperties.java b/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/simple/DeprecatedProperties.java index 86c8cf87772..589c1901e8f 100644 --- a/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/simple/DeprecatedProperties.java +++ b/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/simple/DeprecatedProperties.java @@ -32,7 +32,7 @@ public class DeprecatedProperties { private String description; public String getName() { - return name; + return this.name; } public void setName(String name) { @@ -40,7 +40,7 @@ public class DeprecatedProperties { } public String getDescription() { - return description; + return this.description; } public void setDescription(String description) { diff --git a/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/simple/DeprecatedSingleProperty.java b/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/simple/DeprecatedSingleProperty.java new file mode 100644 index 00000000000..cfbbfed7365 --- /dev/null +++ b/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/simple/DeprecatedSingleProperty.java @@ -0,0 +1,51 @@ +/* + * 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.simple; + +import org.springframework.boot.configurationsample.ConfigurationProperties; +import org.springframework.boot.configurationsample.DeprecatedConfigurationProperty; + +/** + * Configuration properties with a single deprecated element. + * + * @author Phillip Webb + */ +@ConfigurationProperties("singledeprecated") +public class DeprecatedSingleProperty { + + private String newName; + + @Deprecated + @DeprecatedConfigurationProperty(reason = "renamed", replacement = "singledeprecated.new-name") + public String getName() { + return getNewName(); + } + + @Deprecated + public void setName(String name) { + setNewName(name); + } + + public String getNewName() { + return this.newName; + } + + public void setNewName(String newName) { + this.newName = newName; + } + +} diff --git a/spring-boot/src/main/java/org/springframework/boot/context/properties/DeprecatedConfigurationProperty.java b/spring-boot/src/main/java/org/springframework/boot/context/properties/DeprecatedConfigurationProperty.java new file mode 100644 index 00000000000..d9b2a2369e3 --- /dev/null +++ b/spring-boot/src/main/java/org/springframework/boot/context/properties/DeprecatedConfigurationProperty.java @@ -0,0 +1,52 @@ +/* + * 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.context.properties; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Indicates that a getter in a {@link ConfigurationProperties} object is deprecated. This + * annotation has no bearing on the actual binding processes, but it is used by the + * {@code spring-boot-configuration-processor} to add deprecation meta-data. + *

+ * This annotation must be used on the getter of the deprecated element. + * + * @author Phillip Webb + * @since 1.3.0 + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface DeprecatedConfigurationProperty { + + /** + * The reason for the deprecation. + * @return the deprecation reason + */ + String reason() default ""; + + /** + * The field that should be used instead (if any). + * @return the replacement field + */ + String replacement() default ""; + +}