mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-08-29 03:06:45 +08:00
Merge branch '2.3.x'
Closes gh-24059
This commit is contained in:
commit
946be4eab6
@ -100,10 +100,12 @@ class PropertyDescriptorResolver {
|
||||
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) -> {
|
||||
@ -116,6 +118,14 @@ class PropertyDescriptorResolver {
|
||||
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);
|
||||
|
@ -22,6 +22,7 @@ import java.util.LinkedHashMap;
|
||||
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;
|
||||
@ -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<>();
|
||||
|
||||
@ -74,8 +75,14 @@ class TypeElementMembers {
|
||||
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);
|
||||
@ -95,10 +102,19 @@ class TypeElementMembers {
|
||||
&& !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;
|
||||
}
|
||||
}
|
||||
@ -151,35 +167,30 @@ class TypeElementMembers {
|
||||
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;
|
||||
|
@ -38,6 +38,7 @@ import org.springframework.boot.configurationsample.simple.SimpleTypeProperties;
|
||||
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;
|
||||
@ -200,12 +201,22 @@ class ConfigurationMetadataAnnotationProcessorTests extends AbstractMetadataGene
|
||||
}
|
||||
|
||||
@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));
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
@ -29,6 +29,8 @@ public class BoxingPojo {
|
||||
|
||||
private boolean flag;
|
||||
|
||||
private Boolean anotherFlag;
|
||||
|
||||
private Integer counter;
|
||||
|
||||
public boolean isFlag() {
|
||||
@ -40,6 +42,14 @@ public class BoxingPojo {
|
||||
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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user