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
pull/9239/head
Stephane Nicoll 8 years ago
parent a2e749940e
commit 643dea18ee

@ -294,7 +294,8 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor
String name = entry.getKey();
VariableElement field = entry.getValue();
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());
}
}

@ -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");
* you may not use this file except in compliance with the License.
@ -16,8 +16,8 @@
package org.springframework.boot.configurationprocessor;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
@ -39,7 +39,7 @@ import org.springframework.boot.configurationprocessor.metadata.ItemMetadata;
*/
public class MetadataCollector {
private final List<ItemMetadata> metadataItems = new ArrayList<ItemMetadata>();
private final Set<ItemMetadata> metadataItems = new LinkedHashSet<ItemMetadata>();
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");
* you may not use this file except in compliance with the License.
@ -171,6 +171,22 @@ class TypeElementMembers {
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) {
List<ExecutableElement> candidates = this.publicSetters.get(name);
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");
* 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
* @see ConfigurationMetadata
*/
public class ItemMetadata implements Comparable<ItemMetadata> {
public final class ItemMetadata implements Comparable<ItemMetadata> {
private ItemType itemType;
@ -143,13 +143,59 @@ public class ItemMetadata implements Comparable<ItemMetadata> {
return string.toString();
}
protected final void buildToStringProperty(StringBuilder string, String property,
protected void buildToStringProperty(StringBuilder string, String property,
Object value) {
if (value != null) {
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
public int compareTo(ItemMetadata o) {
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.lombok.LombokExplicitProperties;
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.LombokSimpleProperties;
import org.springframework.boot.configurationsample.lombok.SimpleLombokPojo;
@ -487,6 +488,20 @@ public class ConfigurationMetadataAnnotationProcessorTests {
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
public void mergingOfAdditionalProperty() throws Exception {
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");
* 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 String sourceMethod;
private final String description;
private final Object defaultValue;
@ -87,16 +89,17 @@ public final class Metadata {
private final ItemDeprecation deprecation;
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,
Class<?> sourceType, String description, Object defaultValue,
ItemDeprecation deprecation) {
Class<?> sourceType, String sourceMethod, String description,
Object defaultValue, ItemDeprecation deprecation) {
this.itemType = itemType;
this.name = name;
this.type = type;
this.sourceType = sourceType;
this.sourceMethod = sourceMethod;
this.description = description;
this.defaultValue = defaultValue;
this.deprecation = deprecation;
@ -112,6 +115,9 @@ public final class Metadata {
if (this.sourceType != null) {
description.append(" with sourceType:").append(this.sourceType);
}
if (this.sourceMethod != null) {
description.append(" with sourceMethod:").append(this.sourceMethod);
}
if (this.defaultValue != null) {
description.append(" with defaultValue:").append(this.defaultValue);
}
@ -137,6 +143,10 @@ public final class Metadata {
&& !this.sourceType.getName().equals(itemMetadata.getSourceType())) {
return false;
}
if (this.sourceMethod != null
&& !this.sourceMethod.equals(itemMetadata.getSourceMethod())) {
return false;
}
if (this.defaultValue != null && !ObjectUtils
.nullSafeEquals(this.defaultValue, itemMetadata.getDefaultValue())) {
return false;
@ -157,40 +167,50 @@ public final class Metadata {
public MetadataItemCondition ofType(Class<?> dataType) {
return new MetadataItemCondition(this.itemType, this.name, dataType.getName(),
this.sourceType, this.description, this.defaultValue,
this.deprecation);
this.sourceType, this.sourceMethod, this.description,
this.defaultValue, this.deprecation);
}
public MetadataItemCondition ofType(String dataType) {
return new MetadataItemCondition(this.itemType, this.name, dataType,
this.sourceType, this.description, this.defaultValue,
this.deprecation);
this.sourceType, this.sourceMethod, this.description,
this.defaultValue, this.deprecation);
}
public MetadataItemCondition fromSource(Class<?> sourceType) {
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) {
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) {
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) {
return new MetadataItemCondition(this.itemType, this.name, this.type,
this.sourceType, this.description, this.defaultValue,
new ItemDeprecation(reason, replacement));
this.sourceType, this.sourceMethod, this.description,
this.defaultValue, new ItemDeprecation(reason, replacement));
}
public MetadataItemCondition withNoDeprecation() {
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,

@ -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…
Cancel
Save