Skip to content

Commit

Permalink
Fix setter detection in configprops endpoint
Browse files Browse the repository at this point in the history
Previously, the setter of a property whose second letter is upper-case (
such as `oAuth2Uri`) was not detected properly. The JavaBean spec states
that, in such a case, the first letter should not be capitalized (i.e.
the setter should be `setoAuth2Uri` rather than `setOAuth2Uri`).

This commit makes sure that Jackson uses standard bean names and fixes
the setter detection algorithm to take this case into account.

Closes gh-13878
  • Loading branch information
snicoll committed Aug 8, 2018
1 parent 9e4ccbd commit fbf3c48
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 3 deletions.
Expand Up @@ -26,6 +26,7 @@
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.SerializationFeature;
Expand Down Expand Up @@ -172,6 +173,7 @@ private Map<String, Object> safeSerialize(ObjectMapper mapper, Object bean,
*/
protected void configureObjectMapper(ObjectMapper mapper) {
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
mapper.configure(MapperFeature.USE_STD_BEAN_NAMING, true);
mapper.setSerializationInclusion(Include.NON_NULL);
applyConfigurationPropertiesFilter(mapper);
applySerializationModifier(mapper);
Expand Down Expand Up @@ -375,7 +377,7 @@ private boolean isReadable(BeanDescription beanDesc, BeanPropertyWriter writer)

private AnnotatedMethod findSetter(BeanDescription beanDesc,
BeanPropertyWriter writer) {
String name = "set" + StringUtils.capitalize(writer.getName());
String name = "set" + determineAccessorSuffix(writer.getName());
Class<?> type = writer.getType().getRawClass();
AnnotatedMethod setter = beanDesc.findMethod(name, new Class<?>[] { type });
// The enabled property of endpoints returns a boolean primitive but is set
Expand All @@ -386,6 +388,23 @@ private AnnotatedMethod findSetter(BeanDescription beanDesc,
return setter;
}

/**
* Determine the accessor suffix of the specified {@code propertyName}, see
* section 8.8 "Capitalization of inferred names" of the JavaBean specs for more
* details.
* @param propertyName the property name to turn into an accessor suffix
* @return the accessor suffix for {@code propertyName}
*/
private String determineAccessorSuffix(String propertyName) {
if (propertyName.length() > 1
&& Character.isUpperCase(propertyName.charAt(1))) {
return propertyName;
}
else {
return StringUtils.capitalize(propertyName);
}
}

}

/**
Expand Down
Expand Up @@ -44,6 +44,7 @@
*
* @author Dave Syer
* @author Andy Wilkinson
* @author Stephane Nicoll
*/
public class ConfigurationPropertiesReportEndpointTests {

Expand Down Expand Up @@ -120,6 +121,24 @@ public void keySanitizationWithCustomPatternUsingCompositeKeys() {
});
}

@Test
public void nonCamelCaseProperty() {
load((context, properties) -> {
Map<String, Object> nestedProperties = properties.getBeans()
.get("testProperties").getProperties();
assertThat(nestedProperties.get("myURL")).isEqualTo("https://example.com");
});
}

@Test
public void simpleBoolean() {
load((context, properties) -> {
Map<String, Object> nestedProperties = properties.getBeans()
.get("testProperties").getProperties();
assertThat(nestedProperties.get("simpleBoolean")).isEqualTo(true);
});
}

@Test
public void mixedBoolean() {
load((context, properties) -> {
Expand All @@ -129,6 +148,24 @@ public void mixedBoolean() {
});
}

@Test
public void mixedCase() {
load((context, properties) -> {
Map<String, Object> nestedProperties = properties.getBeans()
.get("testProperties").getProperties();
assertThat(nestedProperties.get("mIxedCase")).isEqualTo("mixed");
});
}

@Test
public void singleLetterProperty() {
load((context, properties) -> {
Map<String, Object> nestedProperties = properties.getBeans()
.get("testProperties").getProperties();
assertThat(nestedProperties.get("z")).isEqualTo("zzz");
});
}

@Test
@SuppressWarnings("unchecked")
public void listsAreSanitized() {
Expand Down Expand Up @@ -219,8 +256,16 @@ public static class TestProperties {

private String myTestProperty = "654321";

private String myURL = "https://example.com";

private boolean simpleBoolean = true;

private Boolean mixedBoolean = true;

private String mIxedCase = "mixed";

private String z = "zzz";

private Map<String, Object> secrets = new HashMap<>();

private Hidden hidden = new Hidden();
Expand Down Expand Up @@ -254,14 +299,46 @@ public void setMyTestProperty(String myTestProperty) {
this.myTestProperty = myTestProperty;
}

public boolean isMixedBoolean() {
return (this.mixedBoolean != null) ? this.mixedBoolean : false;
public String getMyURL() {
return this.myURL;
}

public void setMyURL(String myURL) {
this.myURL = myURL;
}

public boolean isSimpleBoolean() {
return this.simpleBoolean;
}

public void setSimpleBoolean(boolean simpleBoolean) {
this.simpleBoolean = simpleBoolean;
}

public void setMixedBoolean(Boolean mixedBoolean) {
this.mixedBoolean = mixedBoolean;
}

public boolean isMixedBoolean() {
return (this.mixedBoolean != null) ? this.mixedBoolean : false;
}

public String getmIxedCase() {
return this.mIxedCase;
}

public void setmIxedCase(String mIxedCase) {
this.mIxedCase = mIxedCase;
}

public String getZ() {
return this.z;
}

public void setZ(String z) {
this.z = z;
}

public Map<String, Object> getSecrets() {
return this.secrets;
}
Expand Down

0 comments on commit fbf3c48

Please sign in to comment.