Skip to content

Commit

Permalink
Merge branch '2.3.x'
Browse files Browse the repository at this point in the history
Closes gh-24059
  • Loading branch information
snicoll committed Nov 5, 2020
2 parents 38821c1 + 4a8646b commit 946be4e
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 25 deletions.
Expand Up @@ -100,10 +100,12 @@ Stream<PropertyDescriptor<?>> resolveJavaBeanProperties(TypeElement type, Execut
TypeElementMembers members) {
// First check if we have regular java bean properties there
Map<String, PropertyDescriptor<?>> candidates = new LinkedHashMap<>();
members.getPublicGetters().forEach((name, getter) -> {
members.getPublicGetters().forEach((name, getters) -> {
VariableElement field = members.getFields().get(name);
ExecutableElement getter = findMatchingGetter(members, getters, field);
TypeMirror propertyType = getter.getReturnType();
register(candidates, new JavaBeanPropertyDescriptor(type, factoryMethod, getter, name, propertyType,
members.getFields().get(name), members.getPublicSetter(name, propertyType)));
register(candidates, new JavaBeanPropertyDescriptor(type, factoryMethod, getter, name, propertyType, field,
members.getPublicSetter(name, propertyType)));
});
// Then check for Lombok ones
members.getFields().forEach((name, field) -> {
Expand All @@ -116,6 +118,14 @@ Stream<PropertyDescriptor<?>> resolveJavaBeanProperties(TypeElement type, Execut
return candidates.values().stream();
}

private ExecutableElement findMatchingGetter(TypeElementMembers members, List<ExecutableElement> candidates,
VariableElement field) {
if (candidates.size() > 1 && field != null) {
return members.getMatchingGetter(candidates, field.asType());
}
return candidates.get(0);
}

private void register(Map<String, PropertyDescriptor<?>> candidates, PropertyDescriptor<?> descriptor) {
if (!candidates.containsKey(descriptor.getName()) && isCandidate(descriptor)) {
candidates.put(descriptor.getName(), descriptor);
Expand Down
Expand Up @@ -22,6 +22,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;

import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
Expand All @@ -48,7 +49,7 @@ class TypeElementMembers {

private final Map<String, VariableElement> fields = new LinkedHashMap<>();

private final Map<String, ExecutableElement> publicGetters = new LinkedHashMap<>();
private final Map<String, List<ExecutableElement>> publicGetters = new LinkedHashMap<>();

private final Map<String, List<ExecutableElement>> publicSetters = new LinkedHashMap<>();

Expand All @@ -74,8 +75,14 @@ private void process(TypeElement element) {
private void processMethod(ExecutableElement method) {
if (isPublic(method)) {
String name = method.getSimpleName().toString();
if (isGetter(method) && !this.publicGetters.containsKey(getAccessorName(name))) {
this.publicGetters.put(getAccessorName(name), method);
if (isGetter(method)) {
String propertyName = getAccessorName(name);
List<ExecutableElement> matchingGetters = this.publicGetters.computeIfAbsent(propertyName,
(k) -> new ArrayList<>());
TypeMirror returnType = method.getReturnType();
if (getMatchingGetter(matchingGetters, returnType) == null) {
matchingGetters.add(method);
}
}
else if (isSetter(method)) {
String propertyName = getAccessorName(name);
Expand All @@ -95,10 +102,19 @@ private boolean isPublic(ExecutableElement method) {
&& !modifiers.contains(Modifier.STATIC);
}

ExecutableElement getMatchingGetter(List<ExecutableElement> candidates, TypeMirror type) {
return getMatchingAccessor(candidates, type, ExecutableElement::getReturnType);
}

private ExecutableElement getMatchingSetter(List<ExecutableElement> candidates, TypeMirror type) {
return getMatchingAccessor(candidates, type, (candidate) -> candidate.getParameters().get(0).asType());
}

private ExecutableElement getMatchingAccessor(List<ExecutableElement> candidates, TypeMirror type,
Function<ExecutableElement, TypeMirror> typeExtractor) {
for (ExecutableElement candidate : candidates) {
TypeMirror paramType = candidate.getParameters().get(0).asType();
if (this.env.getTypeUtils().isSameType(paramType, type)) {
TypeMirror candidateType = typeExtractor.apply(candidate);
if (this.env.getTypeUtils().isSameType(candidateType, type)) {
return candidate;
}
}
Expand Down Expand Up @@ -151,35 +167,30 @@ Map<String, VariableElement> getFields() {
return Collections.unmodifiableMap(this.fields);
}

Map<String, ExecutableElement> getPublicGetters() {
Map<String, List<ExecutableElement>> getPublicGetters() {
return Collections.unmodifiableMap(this.publicGetters);
}

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.env.getTypeUtils().getWrapperOrPrimitiveFor(type);
if (alternative != null && this.env.getTypeUtils().isSameType(returnType, alternative)) {
return candidate;
}
}
return null;
List<ExecutableElement> candidates = this.publicGetters.get(name);
return getPublicAccessor(candidates, type, (specificType) -> getMatchingGetter(candidates, specificType));
}

ExecutableElement getPublicSetter(String name, TypeMirror type) {
List<ExecutableElement> candidates = this.publicSetters.get(name);
return getPublicAccessor(candidates, type, (specificType) -> getMatchingSetter(candidates, specificType));
}

private ExecutableElement getPublicAccessor(List<ExecutableElement> candidates, TypeMirror type,
Function<TypeMirror, ExecutableElement> matchingAccessorExtractor) {
if (candidates != null) {
ExecutableElement matching = getMatchingSetter(candidates, type);
ExecutableElement matching = matchingAccessorExtractor.apply(type);
if (matching != null) {
return matching;
}
TypeMirror alternative = this.env.getTypeUtils().getWrapperOrPrimitiveFor(type);
if (alternative != null) {
return getMatchingSetter(candidates, alternative);
return matchingAccessorExtractor.apply(alternative);
}
}
return null;
Expand Down
Expand Up @@ -38,6 +38,7 @@
import org.springframework.boot.configurationsample.specific.AnnotatedGetter;
import org.springframework.boot.configurationsample.specific.BoxingPojo;
import org.springframework.boot.configurationsample.specific.BuilderPojo;
import org.springframework.boot.configurationsample.specific.DeprecatedLessPreciseTypePojo;
import org.springframework.boot.configurationsample.specific.DeprecatedUnrelatedMethodPojo;
import org.springframework.boot.configurationsample.specific.DoubleRegistrationProperties;
import org.springframework.boot.configurationsample.specific.EmptyDefaultValueProperties;
Expand Down Expand Up @@ -200,12 +201,22 @@ void deprecatedOnUnrelatedSetter() {
}

@Test
void boxingOnSetter() {
void deprecatedWithLessPreciseType() {
Class<?> type = DeprecatedLessPreciseTypePojo.class;
ConfigurationMetadata metadata = compile(type);
assertThat(metadata).has(Metadata.withGroup("not.deprecated").fromSource(type));
assertThat(metadata).has(Metadata.withProperty("not.deprecated.flag", Boolean.class).withDefaultValue(false)
.withNoDeprecation().fromSource(type));
}

@Test
void typBoxing() {
Class<?> type = BoxingPojo.class;
ConfigurationMetadata metadata = compile(type);
assertThat(metadata).has(Metadata.withGroup("boxing").fromSource(type));
assertThat(metadata)
.has(Metadata.withProperty("boxing.flag", Boolean.class).withDefaultValue(false).fromSource(type));
assertThat(metadata).has(Metadata.withProperty("boxing.another-flag", Boolean.class).fromSource(type));
assertThat(metadata).has(Metadata.withProperty("boxing.counter", Integer.class).fromSource(type));
}

Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2020 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.
Expand Down Expand Up @@ -29,6 +29,8 @@ public class BoxingPojo {

private boolean flag;

private Boolean anotherFlag;

private Integer counter;

public boolean isFlag() {
Expand All @@ -40,6 +42,14 @@ public void setFlag(Boolean flag) {
this.flag = flag;
}

public boolean isAnotherFlag() {
return Boolean.TRUE.equals(this.anotherFlag);
}

public void setAnotherFlag(boolean anotherFlag) {
this.anotherFlag = anotherFlag;
}

public Integer getCounter() {
return this.counter;
}
Expand Down
@@ -0,0 +1,50 @@
/*
* Copyright 2012-2020 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
*
* https://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 org.springframework.boot.configurationsample.ConfigurationProperties;

/**
* Demonstrate that deprecating accessor with not the same type is not taken into account
* to detect the deprecated flag.
*
* @author Stephane Nicoll
*/
@ConfigurationProperties("not.deprecated")
public class DeprecatedLessPreciseTypePojo {

private boolean flag;

@Deprecated
public Boolean getFlag() {
return this.flag;
}

public boolean isFlag() {
return this.flag;
}

public void setFlag(boolean flag) {
this.flag = flag;
}

@Deprecated
public void setFlag(Boolean flag) {
this.flag = flag;
}

}

0 comments on commit 946be4e

Please sign in to comment.