Add @NestedConfigurationProperty meta-data support
Add a @NestedConfigurationProperty annotation which can be used to customize how configuration mete-data is generated. Prior to this commit only inner-classes where considered nested (see Tomcat in ServerProperties). Using this new annotation, the Ssl property in ServerProperties can be detected as well. See gh-1001
This commit is contained in:
parent
fbf8f56a97
commit
a46396f691
|
|
@ -38,6 +38,7 @@ import org.springframework.boot.context.embedded.tomcat.TomcatConnectorCustomize
|
|||
import org.springframework.boot.context.embedded.tomcat.TomcatContextCustomizer;
|
||||
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
|
|
@ -60,6 +61,7 @@ public class ServerProperties implements EmbeddedServletContainerCustomizer {
|
|||
|
||||
private String contextPath;
|
||||
|
||||
@NestedConfigurationProperty
|
||||
private Ssl ssl;
|
||||
|
||||
@NotNull
|
||||
|
|
|
|||
|
|
@ -64,6 +64,9 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor
|
|||
static final String CONFIGURATION_PROPERTIES_ANNOTATION = "org.springframework.boot."
|
||||
+ "context.properties.ConfigurationProperties";
|
||||
|
||||
static final String NESTED_CONFIGURATION_PROPERTY_ANNOTATION = "org.springframework.boot."
|
||||
+ "context.properties.NestedConfigurationProperty";
|
||||
|
||||
private ConfigurationMetadata metadata;
|
||||
|
||||
private TypeUtils typeUtils;
|
||||
|
|
@ -74,6 +77,10 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor
|
|||
return CONFIGURATION_PROPERTIES_ANNOTATION;
|
||||
}
|
||||
|
||||
protected String nestedConfigurationPropertyAnnotation() {
|
||||
return NESTED_CONFIGURATION_PROPERTY_ANNOTATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void init(ProcessingEnvironment env) {
|
||||
super.init(env);
|
||||
|
|
@ -166,8 +173,11 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor
|
|||
ExecutableElement getter = entry.getValue();
|
||||
ExecutableElement setter = members.getPublicSetters().get(name);
|
||||
VariableElement field = members.getFields().get(name);
|
||||
if (setter != null
|
||||
|| this.typeUtils.isCollectionOrMap(getter.getReturnType())) {
|
||||
boolean isNested = getAnnotation(field,
|
||||
nestedConfigurationPropertyAnnotation()) != null;
|
||||
boolean isCollection = this.typeUtils.isCollectionOrMap(getter
|
||||
.getReturnType());
|
||||
if (!isNested && (setter != null || isCollection)) {
|
||||
String dataType = this.typeUtils.getType(getter.getReturnType());
|
||||
String sourceType = this.typeUtils.getType(element);
|
||||
String description = this.typeUtils.getJavaDoc(field);
|
||||
|
|
@ -182,17 +192,21 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor
|
|||
TypeElementMembers members) {
|
||||
for (Map.Entry<String, ExecutableElement> entry : members.getPublicGetters()
|
||||
.entrySet()) {
|
||||
String name = entry.getKey();
|
||||
ExecutableElement getter = entry.getValue();
|
||||
VariableElement field = members.getFields().get(name);
|
||||
Element returnType = this.processingEnv.getTypeUtils().asElement(
|
||||
getter.getReturnType());
|
||||
AnnotationMirror annotation = getAnnotation(getter,
|
||||
configurationPropertiesAnnotation());
|
||||
boolean isNested = getAnnotation(field,
|
||||
nestedConfigurationPropertyAnnotation()) != null;
|
||||
if (returnType != null && returnType instanceof TypeElement
|
||||
&& annotation == null) {
|
||||
TypeElement returns = (TypeElement) returnType;
|
||||
if (this.typeUtils.isEnclosedIn(returnType, element)) {
|
||||
String nestedPrefix = ConfigurationMetadata.nestedPrefix(prefix,
|
||||
entry.getKey());
|
||||
if (this.typeUtils.isEnclosedIn(returnType, element) || isNested) {
|
||||
String nestedPrefix = ConfigurationMetadata
|
||||
.nestedPrefix(prefix, name);
|
||||
this.metadata.add(ItemMetadata.newGroup(nestedPrefix,
|
||||
this.typeUtils.getType(returns),
|
||||
this.typeUtils.getType(element), getter.toString()));
|
||||
|
|
@ -203,9 +217,11 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor
|
|||
}
|
||||
|
||||
private AnnotationMirror getAnnotation(Element element, String type) {
|
||||
for (AnnotationMirror annotation : element.getAnnotationMirrors()) {
|
||||
if (type.equals(annotation.getAnnotationType().toString())) {
|
||||
return annotation;
|
||||
if (element != null) {
|
||||
for (AnnotationMirror annotation : element.getAnnotationMirrors()) {
|
||||
if (type.equals(annotation.getAnnotationType().toString())) {
|
||||
return annotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ import org.springframework.boot.configurationsample.simple.SimpleTypeProperties;
|
|||
import org.springframework.boot.configurationsample.specific.InnerClassAnnotatedGetterConfig;
|
||||
import org.springframework.boot.configurationsample.specific.InnerClassProperties;
|
||||
import org.springframework.boot.configurationsample.specific.InnerClassRootConfig;
|
||||
import org.springframework.boot.configurationsample.specific.SimplePojo;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
|
|
@ -238,11 +239,8 @@ public class ConfigurationMetadataAnnotationProcessorTests {
|
|||
.fromSource(InnerClassProperties.class));
|
||||
assertThat(metadata, containsProperty("config.the-second.name"));
|
||||
assertThat(metadata, containsProperty("config.the-second.bar.name"));
|
||||
assertThat(
|
||||
metadata,
|
||||
containsGroup("config.third").ofType(
|
||||
InnerClassProperties.SimplePojo.class).fromSource(
|
||||
InnerClassProperties.class));
|
||||
assertThat(metadata, containsGroup("config.third").ofType(SimplePojo.class)
|
||||
.fromSource(InnerClassProperties.class));
|
||||
assertThat(metadata, containsProperty("config.third.value"));
|
||||
}
|
||||
|
||||
|
|
@ -267,6 +265,8 @@ public class ConfigurationMetadataAnnotationProcessorTests {
|
|||
|
||||
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
|
||||
|
|
@ -274,6 +274,11 @@ public class ConfigurationMetadataAnnotationProcessorTests {
|
|||
return CONFIGURATION_PROPERTIES_ANNOTATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String nestedConfigurationPropertyAnnotation() {
|
||||
return NESTED_CONFIGURATION_PROPERTY_ANNOTATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeMetaData(ConfigurationMetadata metadata) {
|
||||
this.metadata = metadata;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* 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.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;
|
||||
|
||||
/**
|
||||
* Alternative to Spring Boot's {@code @NestedConfigurationProperty} for testing (removes
|
||||
* the need for a dependency on the real annotation).
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Phillip Webb
|
||||
* @since 1.2.0
|
||||
*/
|
||||
@Target(ElementType.FIELD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface NestedConfigurationProperty {
|
||||
|
||||
}
|
||||
|
|
@ -17,6 +17,7 @@
|
|||
package org.springframework.boot.configurationsample.specific;
|
||||
|
||||
import org.springframework.boot.configurationsample.ConfigurationProperties;
|
||||
import org.springframework.boot.configurationsample.NestedConfigurationProperty;
|
||||
|
||||
/**
|
||||
* Demonstrate the auto-detection of a inner config classes.
|
||||
|
|
@ -30,6 +31,7 @@ public class InnerClassProperties {
|
|||
|
||||
private Foo second = new Foo();
|
||||
|
||||
@NestedConfigurationProperty
|
||||
private final SimplePojo third = new SimplePojo();
|
||||
|
||||
public Foo getFirst() {
|
||||
|
|
@ -81,9 +83,4 @@ public class InnerClassProperties {
|
|||
|
||||
}
|
||||
|
||||
public static class SimplePojo extends
|
||||
org.springframework.boot.configurationsample.specific.SimplePojo {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* 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.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 field in a {@link ConfigurationProperties} object should be treated as
|
||||
* if it were a nested type. This annotation has no bearing on the actual binding
|
||||
* processes, but it is used by the {@code spring-boot-configuration-processor} as a hint
|
||||
* that a field is not bound as a single value.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Phillip Webb
|
||||
* @since 1.2.0
|
||||
*/
|
||||
@Target(ElementType.FIELD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface NestedConfigurationProperty {
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue