Accommodate with Lombok generation ordering
Previously, if lombok was running before the configuration metadata annotation processor, duplicated keys were created as both the getter/setter and the special lombok handling applied. This commit makes sure to be lenient by removing duplicate metadata entries. This commit also makes sure to identify the getter of a nested group if present. That way, the sourceMethod is set consistently and avoid the creation of a duplicate group. Closes gh-8886
This commit is contained in:
parent
a2e749940e
commit
643dea18ee
|
|
@ -294,7 +294,8 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor
|
||||||
String name = entry.getKey();
|
String name = entry.getKey();
|
||||||
VariableElement field = entry.getValue();
|
VariableElement field = entry.getValue();
|
||||||
if (isLombokField(field, element)) {
|
if (isLombokField(field, element)) {
|
||||||
processNestedType(prefix, element, source, name, null, field,
|
ExecutableElement getter = members.getPublicGetter(name, field.asType());
|
||||||
|
processNestedType(prefix, element, source, name, getter, field,
|
||||||
field.asType());
|
field.asType());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2016 the original author or authors.
|
* Copyright 2012-2017 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -16,8 +16,8 @@
|
||||||
|
|
||||||
package org.springframework.boot.configurationprocessor;
|
package org.springframework.boot.configurationprocessor;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
|
@ -39,7 +39,7 @@ import org.springframework.boot.configurationprocessor.metadata.ItemMetadata;
|
||||||
*/
|
*/
|
||||||
public class MetadataCollector {
|
public class MetadataCollector {
|
||||||
|
|
||||||
private final List<ItemMetadata> metadataItems = new ArrayList<ItemMetadata>();
|
private final Set<ItemMetadata> metadataItems = new LinkedHashSet<ItemMetadata>();
|
||||||
|
|
||||||
private final ProcessingEnvironment processingEnvironment;
|
private final ProcessingEnvironment processingEnvironment;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2016 the original author or authors.
|
* Copyright 2012-2017 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -171,6 +171,22 @@ class TypeElementMembers {
|
||||||
return Collections.unmodifiableMap(this.publicGetters);
|
return Collections.unmodifiableMap(this.publicGetters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ExecutableElement getPublicGetter(String name, TypeMirror type) {
|
||||||
|
ExecutableElement candidate = this.publicGetters.get(name);
|
||||||
|
if (candidate != null) {
|
||||||
|
TypeMirror returnType = candidate.getReturnType();
|
||||||
|
if (this.env.getTypeUtils().isSameType(returnType, type)) {
|
||||||
|
return candidate;
|
||||||
|
}
|
||||||
|
TypeMirror alternative = this.typeUtils.getWrapperOrPrimitiveFor(type);
|
||||||
|
if (alternative != null &&
|
||||||
|
this.env.getTypeUtils().isSameType(returnType, alternative)) {
|
||||||
|
return candidate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public ExecutableElement getPublicSetter(String name, TypeMirror type) {
|
public ExecutableElement getPublicSetter(String name, TypeMirror type) {
|
||||||
List<ExecutableElement> candidates = this.publicSetters.get(name);
|
List<ExecutableElement> candidates = this.publicSetters.get(name);
|
||||||
if (candidates != null) {
|
if (candidates != null) {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2014 the original author or authors.
|
* Copyright 2012-2017 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -24,7 +24,7 @@ package org.springframework.boot.configurationprocessor.metadata;
|
||||||
* @since 1.2.0
|
* @since 1.2.0
|
||||||
* @see ConfigurationMetadata
|
* @see ConfigurationMetadata
|
||||||
*/
|
*/
|
||||||
public class ItemMetadata implements Comparable<ItemMetadata> {
|
public final class ItemMetadata implements Comparable<ItemMetadata> {
|
||||||
|
|
||||||
private ItemType itemType;
|
private ItemType itemType;
|
||||||
|
|
||||||
|
|
@ -143,13 +143,59 @@ public class ItemMetadata implements Comparable<ItemMetadata> {
|
||||||
return string.toString();
|
return string.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final void buildToStringProperty(StringBuilder string, String property,
|
protected void buildToStringProperty(StringBuilder string, String property,
|
||||||
Object value) {
|
Object value) {
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
string.append(" ").append(property).append(":").append(value);
|
string.append(" ").append(property).append(":").append(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (o == null || getClass() != o.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ItemMetadata other = (ItemMetadata) o;
|
||||||
|
return nullSafeEquals(this.itemType, other.itemType)
|
||||||
|
&& nullSafeEquals(this.name, other.name)
|
||||||
|
&& nullSafeEquals(this.type, other.type)
|
||||||
|
&& nullSafeEquals(this.description, other.description)
|
||||||
|
&& nullSafeEquals(this.sourceType, other.sourceType)
|
||||||
|
&& nullSafeEquals(this.sourceMethod, other.sourceMethod)
|
||||||
|
&& nullSafeEquals(this.defaultValue, other.defaultValue)
|
||||||
|
&& nullSafeEquals(this.deprecation, other.deprecation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = nullSafeHashCode(this.itemType);
|
||||||
|
result = 31 * result + nullSafeHashCode(this.name);
|
||||||
|
result = 31 * result + nullSafeHashCode(this.type);
|
||||||
|
result = 31 * result + nullSafeHashCode(this.description);
|
||||||
|
result = 31 * result + nullSafeHashCode(this.sourceType);
|
||||||
|
result = 31 * result + nullSafeHashCode(this.sourceMethod);
|
||||||
|
result = 31 * result + nullSafeHashCode(this.defaultValue);
|
||||||
|
result = 31 * result + nullSafeHashCode(this.deprecation);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean nullSafeEquals(Object o1, Object o2) {
|
||||||
|
if (o1 == o2) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (o1 == null || o2 == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return o1.equals(o2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int nullSafeHashCode(Object o) {
|
||||||
|
return (o == null ? 0 : o.hashCode());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(ItemMetadata o) {
|
public int compareTo(ItemMetadata o) {
|
||||||
return getName().compareTo(o.getName());
|
return getName().compareTo(o.getName());
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ import org.springframework.boot.configurationsample.incremental.FooProperties;
|
||||||
import org.springframework.boot.configurationsample.incremental.RenamedBarProperties;
|
import org.springframework.boot.configurationsample.incremental.RenamedBarProperties;
|
||||||
import org.springframework.boot.configurationsample.lombok.LombokExplicitProperties;
|
import org.springframework.boot.configurationsample.lombok.LombokExplicitProperties;
|
||||||
import org.springframework.boot.configurationsample.lombok.LombokInnerClassProperties;
|
import org.springframework.boot.configurationsample.lombok.LombokInnerClassProperties;
|
||||||
|
import org.springframework.boot.configurationsample.lombok.LombokInnerClassWithGetterProperties;
|
||||||
import org.springframework.boot.configurationsample.lombok.LombokSimpleDataProperties;
|
import org.springframework.boot.configurationsample.lombok.LombokSimpleDataProperties;
|
||||||
import org.springframework.boot.configurationsample.lombok.LombokSimpleProperties;
|
import org.springframework.boot.configurationsample.lombok.LombokSimpleProperties;
|
||||||
import org.springframework.boot.configurationsample.lombok.SimpleLombokPojo;
|
import org.springframework.boot.configurationsample.lombok.SimpleLombokPojo;
|
||||||
|
|
@ -487,6 +488,20 @@ public class ConfigurationMetadataAnnotationProcessorTests {
|
||||||
assertThat(metadata).isNotEqualTo(Metadata.withGroup("config.fourth"));
|
assertThat(metadata).isNotEqualTo(Metadata.withGroup("config.fourth"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void lombokInnerClassWithGetterProperties() throws IOException {
|
||||||
|
ConfigurationMetadata metadata =
|
||||||
|
compile(LombokInnerClassWithGetterProperties.class);
|
||||||
|
assertThat(metadata).has(Metadata.withGroup("config")
|
||||||
|
.fromSource(LombokInnerClassWithGetterProperties.class));
|
||||||
|
assertThat(metadata).has(Metadata.withGroup("config.first")
|
||||||
|
.ofType(LombokInnerClassWithGetterProperties.Foo.class)
|
||||||
|
.fromSourceMethod("getFirst()")
|
||||||
|
.fromSource(LombokInnerClassWithGetterProperties.class));
|
||||||
|
assertThat(metadata).has(Metadata.withProperty("config.first.name"));
|
||||||
|
assertThat(metadata.getItems()).hasSize(3);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void mergingOfAdditionalProperty() throws Exception {
|
public void mergingOfAdditionalProperty() throws Exception {
|
||||||
ItemMetadata property = ItemMetadata.newProperty(null, "foo", "java.lang.String",
|
ItemMetadata property = ItemMetadata.newProperty(null, "foo", "java.lang.String",
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2016 the original author or authors.
|
* Copyright 2012-2017 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -80,6 +80,8 @@ public final class Metadata {
|
||||||
|
|
||||||
private final Class<?> sourceType;
|
private final Class<?> sourceType;
|
||||||
|
|
||||||
|
private final String sourceMethod;
|
||||||
|
|
||||||
private final String description;
|
private final String description;
|
||||||
|
|
||||||
private final Object defaultValue;
|
private final Object defaultValue;
|
||||||
|
|
@ -87,16 +89,17 @@ public final class Metadata {
|
||||||
private final ItemDeprecation deprecation;
|
private final ItemDeprecation deprecation;
|
||||||
|
|
||||||
public MetadataItemCondition(ItemType itemType, String name) {
|
public MetadataItemCondition(ItemType itemType, String name) {
|
||||||
this(itemType, name, null, null, null, null, null);
|
this(itemType, name, null, null, null, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MetadataItemCondition(ItemType itemType, String name, String type,
|
public MetadataItemCondition(ItemType itemType, String name, String type,
|
||||||
Class<?> sourceType, String description, Object defaultValue,
|
Class<?> sourceType, String sourceMethod, String description,
|
||||||
ItemDeprecation deprecation) {
|
Object defaultValue, ItemDeprecation deprecation) {
|
||||||
this.itemType = itemType;
|
this.itemType = itemType;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.sourceType = sourceType;
|
this.sourceType = sourceType;
|
||||||
|
this.sourceMethod = sourceMethod;
|
||||||
this.description = description;
|
this.description = description;
|
||||||
this.defaultValue = defaultValue;
|
this.defaultValue = defaultValue;
|
||||||
this.deprecation = deprecation;
|
this.deprecation = deprecation;
|
||||||
|
|
@ -112,6 +115,9 @@ public final class Metadata {
|
||||||
if (this.sourceType != null) {
|
if (this.sourceType != null) {
|
||||||
description.append(" with sourceType:").append(this.sourceType);
|
description.append(" with sourceType:").append(this.sourceType);
|
||||||
}
|
}
|
||||||
|
if (this.sourceMethod != null) {
|
||||||
|
description.append(" with sourceMethod:").append(this.sourceMethod);
|
||||||
|
}
|
||||||
if (this.defaultValue != null) {
|
if (this.defaultValue != null) {
|
||||||
description.append(" with defaultValue:").append(this.defaultValue);
|
description.append(" with defaultValue:").append(this.defaultValue);
|
||||||
}
|
}
|
||||||
|
|
@ -137,6 +143,10 @@ public final class Metadata {
|
||||||
&& !this.sourceType.getName().equals(itemMetadata.getSourceType())) {
|
&& !this.sourceType.getName().equals(itemMetadata.getSourceType())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (this.sourceMethod != null
|
||||||
|
&& !this.sourceMethod.equals(itemMetadata.getSourceMethod())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (this.defaultValue != null && !ObjectUtils
|
if (this.defaultValue != null && !ObjectUtils
|
||||||
.nullSafeEquals(this.defaultValue, itemMetadata.getDefaultValue())) {
|
.nullSafeEquals(this.defaultValue, itemMetadata.getDefaultValue())) {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -157,40 +167,50 @@ public final class Metadata {
|
||||||
|
|
||||||
public MetadataItemCondition ofType(Class<?> dataType) {
|
public MetadataItemCondition ofType(Class<?> dataType) {
|
||||||
return new MetadataItemCondition(this.itemType, this.name, dataType.getName(),
|
return new MetadataItemCondition(this.itemType, this.name, dataType.getName(),
|
||||||
this.sourceType, this.description, this.defaultValue,
|
this.sourceType, this.sourceMethod, this.description,
|
||||||
this.deprecation);
|
this.defaultValue, this.deprecation);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MetadataItemCondition ofType(String dataType) {
|
public MetadataItemCondition ofType(String dataType) {
|
||||||
return new MetadataItemCondition(this.itemType, this.name, dataType,
|
return new MetadataItemCondition(this.itemType, this.name, dataType,
|
||||||
this.sourceType, this.description, this.defaultValue,
|
this.sourceType, this.sourceMethod, this.description,
|
||||||
this.deprecation);
|
this.defaultValue, this.deprecation);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MetadataItemCondition fromSource(Class<?> sourceType) {
|
public MetadataItemCondition fromSource(Class<?> sourceType) {
|
||||||
return new MetadataItemCondition(this.itemType, this.name, this.type,
|
return new MetadataItemCondition(this.itemType, this.name, this.type,
|
||||||
sourceType, this.description, this.defaultValue, this.deprecation);
|
sourceType, this.sourceMethod, this.description, this.defaultValue,
|
||||||
|
this.deprecation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MetadataItemCondition fromSourceMethod(String sourceMethod) {
|
||||||
|
return new MetadataItemCondition(this.itemType, this.name, this.type,
|
||||||
|
this.sourceType, sourceMethod, this.description, this.defaultValue,
|
||||||
|
this.deprecation);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MetadataItemCondition withDescription(String description) {
|
public MetadataItemCondition withDescription(String description) {
|
||||||
return new MetadataItemCondition(this.itemType, this.name, this.type,
|
return new MetadataItemCondition(this.itemType, this.name, this.type,
|
||||||
this.sourceType, description, this.defaultValue, this.deprecation);
|
this.sourceType, this.sourceMethod, description, this.defaultValue,
|
||||||
|
this.deprecation);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MetadataItemCondition withDefaultValue(Object defaultValue) {
|
public MetadataItemCondition withDefaultValue(Object defaultValue) {
|
||||||
return new MetadataItemCondition(this.itemType, this.name, this.type,
|
return new MetadataItemCondition(this.itemType, this.name, this.type,
|
||||||
this.sourceType, this.description, defaultValue, this.deprecation);
|
this.sourceType, this.sourceMethod, this.description, defaultValue,
|
||||||
|
this.deprecation);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MetadataItemCondition withDeprecation(String reason, String replacement) {
|
public MetadataItemCondition withDeprecation(String reason, String replacement) {
|
||||||
return new MetadataItemCondition(this.itemType, this.name, this.type,
|
return new MetadataItemCondition(this.itemType, this.name, this.type,
|
||||||
this.sourceType, this.description, this.defaultValue,
|
this.sourceType, this.sourceMethod, this.description,
|
||||||
new ItemDeprecation(reason, replacement));
|
this.defaultValue, new ItemDeprecation(reason, replacement));
|
||||||
}
|
}
|
||||||
|
|
||||||
public MetadataItemCondition withNoDeprecation() {
|
public MetadataItemCondition withNoDeprecation() {
|
||||||
return new MetadataItemCondition(this.itemType, this.name, this.type,
|
return new MetadataItemCondition(this.itemType, this.name, this.type,
|
||||||
this.sourceType, this.description, this.defaultValue, null);
|
this.sourceType, this.sourceMethod, this.description,
|
||||||
|
this.defaultValue, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ItemMetadata getFirstItemWithName(ConfigurationMetadata metadata,
|
private ItemMetadata getFirstItemWithName(ConfigurationMetadata metadata,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2017 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.lombok;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import org.springframework.boot.configurationsample.ConfigurationProperties;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ConfigurationProperties(prefix = "config")
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public class LombokInnerClassWithGetterProperties {
|
||||||
|
|
||||||
|
private final Foo first = new Foo();
|
||||||
|
|
||||||
|
public Foo getFirst() {
|
||||||
|
return this.first;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class Foo {
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue