Commit 643dea18 authored by Stephane Nicoll's avatar Stephane Nicoll

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
parent a2e74994
...@@ -294,7 +294,8 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor ...@@ -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());
} }
} }
......
/* /*
* 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 @@ ...@@ -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; ...@@ -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;
......
/* /*
* 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 { ...@@ -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) {
......
/* /*
* 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; ...@@ -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> { ...@@ -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; ...@@ -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 { ...@@ -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",
......
/* /*
* 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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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,
......
/*
* 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;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment