Merge branch '1.3.x' into 1.4.x
This commit is contained in:
		
						commit
						7f8849c62b
					
				|  | @ -164,12 +164,13 @@ The JSON object contained in the `properties` array can contain the following at | |||
| 
 | ||||
| |`type` | ||||
| | String | ||||
| | The class name of the data type of the property. For example, `java.lang.String`. This | ||||
|   attribute can be used to guide the user as to the types of values that they can enter. | ||||
|   For consistency, the type of a primitive is specified using its wrapper counterpart, | ||||
|   i.e. `boolean` becomes `java.lang.Boolean`. Note that this class may be a complex type | ||||
|   that gets converted from a String as values are bound. May be omitted if the type is | ||||
|   not known. | ||||
| | The full signature of the data type of the property. For example, `java.lang.String` | ||||
|   but also a full generic type such as `java.util.Map<java.util.String,acme.MyEnum>`. | ||||
|   This attribute can be used to guide the user as to the types of values that they can | ||||
|   enter. For consistency, the type of a primitive is specified using its wrapper | ||||
|   counterpart, i.e. `boolean` becomes `java.lang.Boolean`. Note that this class may be | ||||
|   a complex type that gets converted from a String as values are bound. May be omitted | ||||
|   if the type is not known. | ||||
| 
 | ||||
| |`description` | ||||
| | String | ||||
|  |  | |||
|  | @ -161,7 +161,7 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor | |||
| 	} | ||||
| 
 | ||||
| 	private void processAnnotatedTypeElement(String prefix, TypeElement element) { | ||||
| 		String type = this.typeUtils.getType(element); | ||||
| 		String type = this.typeUtils.getQualifiedName(element); | ||||
| 		this.metadataCollector.add(ItemMetadata.newGroup(prefix, type, type, null)); | ||||
| 		processTypeElement(prefix, element); | ||||
| 	} | ||||
|  | @ -173,8 +173,8 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor | |||
| 					.asElement(element.getReturnType()); | ||||
| 			if (returns instanceof TypeElement) { | ||||
| 				ItemMetadata group = ItemMetadata.newGroup(prefix, | ||||
| 						this.typeUtils.getType(returns), | ||||
| 						this.typeUtils.getType(element.getEnclosingElement()), | ||||
| 						this.typeUtils.getQualifiedName(returns), | ||||
| 						this.typeUtils.getQualifiedName(element.getEnclosingElement()), | ||||
| 						element.toString()); | ||||
| 				if (this.metadataCollector.hasSimilarGroup(group)) { | ||||
| 					this.processingEnv.getMessager().printMessage(Kind.ERROR, | ||||
|  | @ -224,7 +224,7 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor | |||
| 			boolean isCollection = this.typeUtils.isCollectionOrMap(returnType); | ||||
| 			if (!isExcluded && !isNested && (setter != null || isCollection)) { | ||||
| 				String dataType = this.typeUtils.getType(returnType); | ||||
| 				String sourceType = this.typeUtils.getType(element); | ||||
| 				String sourceType = this.typeUtils.getQualifiedName(element); | ||||
| 				String description = this.typeUtils.getJavaDoc(field); | ||||
| 				Object defaultValue = fieldValues.get(name); | ||||
| 				boolean deprecated = isDeprecated(getter) || isDeprecated(setter) | ||||
|  | @ -267,7 +267,7 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor | |||
| 			boolean hasSetter = hasLombokSetter(field, element); | ||||
| 			if (!isExcluded && !isNested && (hasSetter || isCollection)) { | ||||
| 				String dataType = this.typeUtils.getType(returnType); | ||||
| 				String sourceType = this.typeUtils.getType(element); | ||||
| 				String sourceType = this.typeUtils.getQualifiedName(element); | ||||
| 				String description = this.typeUtils.getJavaDoc(field); | ||||
| 				Object defaultValue = fieldValues.get(name); | ||||
| 				boolean deprecated = isDeprecated(field) || isDeprecated(element); | ||||
|  | @ -324,8 +324,8 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor | |||
| 				&& annotation == null && isNested) { | ||||
| 			String nestedPrefix = ConfigurationMetadata.nestedPrefix(prefix, name); | ||||
| 			this.metadataCollector.add(ItemMetadata.newGroup(nestedPrefix, | ||||
| 					this.typeUtils.getType(returnElement), | ||||
| 					this.typeUtils.getType(element), | ||||
| 					this.typeUtils.getQualifiedName(returnElement), | ||||
| 					this.typeUtils.getQualifiedName(element), | ||||
| 					(getter == null ? null : getter.toString()))); | ||||
| 			processTypeElement(nestedPrefix, (TypeElement) returnElement); | ||||
| 		} | ||||
|  |  | |||
|  | @ -69,7 +69,7 @@ public class MetadataCollector { | |||
| 
 | ||||
| 	private void markAsProcessed(Element element) { | ||||
| 		if (element instanceof TypeElement) { | ||||
| 			this.processedSourceTypes.add(this.typeUtils.getType(element)); | ||||
| 			this.processedSourceTypes.add(this.typeUtils.getQualifiedName(element)); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
|  | @ -93,10 +93,34 @@ class TypeUtils { | |||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	public String getType(Element element) { | ||||
| 		return getType(element == null ? null : element.asType()); | ||||
| 	/** | ||||
| 	 * Return the qualified name of the specified element. | ||||
| 	 * @param element the element to handle | ||||
| 	 * @return the fully qualified name of the element, suitable for a call | ||||
| 	 * to {@link Class#forName(String)} | ||||
| 	 */ | ||||
| 	public String getQualifiedName(Element element) { | ||||
| 		if (element == null) { | ||||
| 			return null; | ||||
| 		} | ||||
| 		TypeElement enclosingElement = getEnclosingTypeElement(element.asType()); | ||||
| 		if (enclosingElement != null) { | ||||
| 			return getQualifiedName(enclosingElement) + "$" | ||||
| 					+ ((DeclaredType) element.asType()).asElement().getSimpleName().toString(); | ||||
| 		} | ||||
| 		if (element instanceof TypeElement) { | ||||
| 			return ((TypeElement) element).getQualifiedName().toString(); | ||||
| 		} | ||||
| 		throw new IllegalStateException("Could not extract qualified name from " | ||||
| 				+ element); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Return the type of the specified {@link TypeMirror} including all its generic | ||||
| 	 * information. | ||||
| 	 * @param type  the type to handle | ||||
| 	 * @return a representation of the type including all its generic information | ||||
| 	 */ | ||||
| 	public String getType(TypeMirror type) { | ||||
| 		if (type == null) { | ||||
| 			return null; | ||||
|  | @ -105,15 +129,23 @@ class TypeUtils { | |||
| 		if (wrapper != null) { | ||||
| 			return wrapper.getName(); | ||||
| 		} | ||||
| 		TypeElement enclosingElement = getEnclosingTypeElement(type); | ||||
| 		if (enclosingElement != null) { | ||||
| 			return getQualifiedName(enclosingElement) + "$" | ||||
| 					+ ((DeclaredType) type).asElement().getSimpleName().toString(); | ||||
| 		} | ||||
| 		return type.toString(); | ||||
| 	} | ||||
| 
 | ||||
| 	private TypeElement getEnclosingTypeElement(TypeMirror type) { | ||||
| 		if (type instanceof DeclaredType) { | ||||
| 			DeclaredType declaredType = (DeclaredType) type; | ||||
| 			Element enclosingElement = declaredType.asElement().getEnclosingElement(); | ||||
| 			if (enclosingElement != null && enclosingElement instanceof TypeElement) { | ||||
| 				return getType(enclosingElement) + "$" | ||||
| 						+ declaredType.asElement().getSimpleName().toString(); | ||||
| 				return (TypeElement) enclosingElement; | ||||
| 			} | ||||
| 		} | ||||
| 		return type.toString(); | ||||
| 		return null; | ||||
| 	} | ||||
| 
 | ||||
| 	public boolean isCollectionOrMap(TypeMirror type) { | ||||
|  |  | |||
|  | @ -58,6 +58,7 @@ import org.springframework.boot.configurationsample.specific.BuilderPojo; | |||
| import org.springframework.boot.configurationsample.specific.DeprecatedUnrelatedMethodPojo; | ||||
| import org.springframework.boot.configurationsample.specific.DoubleRegistrationProperties; | ||||
| import org.springframework.boot.configurationsample.specific.ExcludedTypesPojo; | ||||
| import org.springframework.boot.configurationsample.specific.GenericConfig; | ||||
| import org.springframework.boot.configurationsample.specific.InnerClassAnnotatedGetterConfig; | ||||
| import org.springframework.boot.configurationsample.specific.InnerClassProperties; | ||||
| import org.springframework.boot.configurationsample.specific.InnerClassRootConfig; | ||||
|  | @ -361,6 +362,35 @@ public class ConfigurationMetadataAnnotationProcessorTests { | |||
| 		compile(InvalidDoubleRegistrationProperties.class); | ||||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	public void genericTypes() throws IOException { | ||||
| 		ConfigurationMetadata metadata = compile(GenericConfig.class); | ||||
| 		assertThat(metadata).has(Metadata.withGroup("generic").ofType( | ||||
| 				"org.springframework.boot.configurationsample.specific.GenericConfig")); | ||||
| 		assertThat(metadata).has(Metadata.withGroup("generic.foo").ofType( | ||||
| 				"org.springframework.boot.configurationsample.specific.GenericConfig$Foo")); | ||||
| 		assertThat(metadata).has(Metadata.withGroup("generic.foo.bar").ofType( | ||||
| 				"org.springframework.boot.configurationsample.specific.GenericConfig$Bar")); | ||||
| 		assertThat(metadata).has(Metadata.withGroup("generic.foo.bar.biz").ofType( | ||||
| 				"org.springframework.boot.configurationsample.specific.GenericConfig$Bar$Biz")); | ||||
| 		assertThat(metadata).has(Metadata.withProperty("generic.foo.name") | ||||
| 				.ofType(String.class) | ||||
| 				.fromSource(GenericConfig.Foo.class)); | ||||
| 		assertThat(metadata).has(Metadata.withProperty("generic.foo.string-to-bar") | ||||
| 				.ofType("java.util.Map<java.lang.String,org.springframework.boot.configurationsample.specific.GenericConfig.Bar<java.lang.Integer>>") | ||||
| 				.fromSource(GenericConfig.Foo.class)); | ||||
| 		assertThat(metadata).has(Metadata.withProperty("generic.foo.string-to-integer") | ||||
| 				.ofType("java.util.Map<java.lang.String,java.lang.Integer>") | ||||
| 				.fromSource(GenericConfig.Foo.class)); | ||||
| 		assertThat(metadata).has(Metadata.withProperty("generic.foo.bar.name") | ||||
| 				.ofType("java.lang.String") | ||||
| 				.fromSource(GenericConfig.Bar.class)); | ||||
| 		assertThat(metadata).has(Metadata.withProperty("generic.foo.bar.biz.name") | ||||
| 				.ofType("java.lang.String") | ||||
| 				.fromSource(GenericConfig.Bar.Biz.class)); | ||||
| 		assertThat(metadata.getItems()).hasSize(9); | ||||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	public void lombokDataProperties() throws Exception { | ||||
| 		ConfigurationMetadata metadata = compile(LombokSimpleDataProperties.class); | ||||
|  |  | |||
|  | @ -0,0 +1,107 @@ | |||
| /* | ||||
|  * Copyright 2012-2016 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.specific; | ||||
| 
 | ||||
| import java.util.HashMap; | ||||
| import java.util.Map; | ||||
| 
 | ||||
| import org.springframework.boot.configurationsample.ConfigurationProperties; | ||||
| import org.springframework.boot.configurationsample.NestedConfigurationProperty; | ||||
| 
 | ||||
| /** | ||||
|  * Demonstrate that only relevant generics are stored in the metadata. | ||||
|  * | ||||
|  * @author Stephane Nicoll | ||||
|  */ | ||||
| @ConfigurationProperties("generic") | ||||
| public class GenericConfig<T> { | ||||
| 
 | ||||
| 	private final Foo foo = new Foo(); | ||||
| 
 | ||||
| 	public Foo getFoo() { | ||||
| 		return this.foo; | ||||
| 	} | ||||
| 
 | ||||
| 	public static class Foo { | ||||
| 
 | ||||
| 		private String name; | ||||
| 
 | ||||
| 		@NestedConfigurationProperty | ||||
| 		private final Bar<String> bar = new Bar<String>(); | ||||
| 
 | ||||
| 		private final Map<String, Bar<Integer>> stringToBar = | ||||
| 				new HashMap<String, Bar<Integer>>(); | ||||
| 
 | ||||
| 		private final Map<String, Integer> stringToInteger = | ||||
| 				new HashMap<String, Integer>(); | ||||
| 
 | ||||
| 		public String getName() { | ||||
| 			return this.name; | ||||
| 		} | ||||
| 
 | ||||
| 		public void setName(String name) { | ||||
| 			this.name = name; | ||||
| 		} | ||||
| 
 | ||||
| 		public Bar<String> getBar() { | ||||
| 			return this.bar; | ||||
| 		} | ||||
| 
 | ||||
| 		public Map<String, Bar<Integer>> getStringToBar() { | ||||
| 			return this.stringToBar; | ||||
| 		} | ||||
| 
 | ||||
| 		public Map<String, Integer> getStringToInteger() { | ||||
| 			return this.stringToInteger; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	public static class Bar<U> { | ||||
| 
 | ||||
| 		private String name; | ||||
| 
 | ||||
| 		@NestedConfigurationProperty | ||||
| 		private final Biz<String> biz = new Biz<String>(); | ||||
| 
 | ||||
| 		public String getName() { | ||||
| 			return this.name; | ||||
| 		} | ||||
| 
 | ||||
| 		public void setName(String name) { | ||||
| 			this.name = name; | ||||
| 		} | ||||
| 
 | ||||
| 		public Biz<String> getBiz() { | ||||
| 			return this.biz; | ||||
| 		} | ||||
| 
 | ||||
| 		public static class Biz<V> { | ||||
| 
 | ||||
| 			private String name; | ||||
| 
 | ||||
| 			public String getName() { | ||||
| 				return this.name; | ||||
| 			} | ||||
| 
 | ||||
| 			public void setName(String name) { | ||||
| 				this.name = name; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
		Loading…
	
		Reference in New Issue