Skip to content

Commit

Permalink
Fluent accessor support for pojo config classes (#203)
Browse files Browse the repository at this point in the history
  • Loading branch information
Squiry committed Jul 18, 2023
1 parent b259e4f commit ea32188
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -151,12 +151,14 @@ class FieldAndAccessors {
equals = method;
} else if (name.equals("hashCode") && method.getParameters().isEmpty()) {
hashCode = method;
} else {
} else if (method.getParameters().isEmpty()) {
if (name.startsWith("get")) {
fieldsWithAccessors.computeIfAbsent(CommonUtils.decapitalize(name.substring(3)), n -> new FieldAndAccessors()).getter = method;
} else if (name.startsWith("set")) {
fieldsWithAccessors.computeIfAbsent(CommonUtils.decapitalize(name.substring(3)), n -> new FieldAndAccessors()).setter = method;
} else {
fieldsWithAccessors.computeIfAbsent(name, n -> new FieldAndAccessors()).getter = method;
}
} else if (method.getParameters().size() == 1 && name.startsWith("set")) {
fieldsWithAccessors.computeIfAbsent(CommonUtils.decapitalize(name.substring(3)), n -> new FieldAndAccessors()).setter = method;
}
}
}
Expand All @@ -167,24 +169,27 @@ class FieldAndAccessors {
var constructors = CommonUtils.findConstructors(te, m -> m.contains(Modifier.PUBLIC));
var emptyConstructor = constructors.stream().filter(e -> e.getParameters().isEmpty()).findFirst().orElse(null);
var nonEmptyConstructor = constructors.stream().filter(e -> !e.getParameters().isEmpty()).findFirst().orElse(null);
var constructorParams = nonEmptyConstructor == null ? Set.of() : nonEmptyConstructor.getParameters().stream().map(VariableElement::getSimpleName).map(Objects::toString).collect(Collectors.toSet());
var constructorParams = nonEmptyConstructor == null ? Map.of() : nonEmptyConstructor.getParameters().stream().collect(Collectors.toMap(
p -> p.getSimpleName().toString(),
p -> p
));

var seen = new HashSet<String>();
var fields = new ArrayList<ConfigField>();
for (var fieldWithAccessors : fieldsWithAccessors.entrySet()) {
var name = fieldWithAccessors.getKey();
var value = fieldWithAccessors.getValue();
if (value.getter == null) {
if (value.getter == null || value.field == null) {
continue;
}
if (value.setter == null && !constructorParams.contains(value.field.getSimpleName().toString())) {
if (value.setter == null && !constructorParams.containsKey(value.field.getSimpleName().toString())) {
continue;
}
var fieldType = types.asMemberOf(typeMirror, value.field);
if (seen.add(name)) {
var isNullable = CommonUtils.isNullable(value.field) && !fieldType.getKind().isPrimitive();
var mapping = CommonUtils.parseMapping(value.field).getMapping(ConfigClassNames.configValueExtractor);
var hasDefault = emptyConstructor != null || !constructorParams.contains(value.field.getSimpleName().toString());
var hasDefault = emptyConstructor != null || !constructorParams.containsKey(value.field.getSimpleName().toString());
fields.add(new ConfigUtils.ConfigField(
name, TypeName.get(fieldType), isNullable, hasDefault, mapping
));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,11 @@ public boolean equals(Object obj) {
}
public int hashCode() { return java.util.Objects.hashCode(value); }
@Override
public String toString() {
return "TestConfig[%s]".formatted(value);
}
}
""");

Expand Down Expand Up @@ -343,4 +348,46 @@ public String toString() {
.isEqualTo(expected);
}

@Test
public void testPojoWithFluent() {
var extractor = this.compileConfig(List.of(), """
@ru.tinkoff.kora.config.common.annotation.ConfigValueExtractor
public class TestConfig {
@Nullable
private final String value1;
@Nullable
private final String value2;
public TestConfig(String value1, String value2) {
this.value1 = value1;
this.value2 = value2;
}
public String value1() {
return this.value1;
}
public String value2() {
return this.value2;
}
@Override
public boolean equals(Object obj) {
return obj instanceof TestConfig that && java.util.Objects.equals(this.value1, that.value1) && java.util.Objects.equals(this.value2, that.value2);
}
public int hashCode() { return java.util.Objects.hash(value1, value2); }
public String toString() {
return "TestConfig(value1=%s, value2=%s)".formatted(this.value1, this.value2);
}
}
""");

var expected = newObject("TestConfig", "test", null);

assertThat(extractor.extract(MapConfigFactory.fromMap(Map.of("value1", "test")).root()))
.isEqualTo(expected);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ object ConfigUtils {
}
var equals: KSFunctionDeclaration? = null
var hashCode: KSFunctionDeclaration? = null

class FieldAndAccessors(var property: KSPropertyDeclaration? = null, var getter: KSFunctionDeclaration? = null, var setter: KSFunctionDeclaration? = null)

val propertyMap = hashMapOf<String, FieldAndAccessors>()
for (function in typeDecl.getDeclaredFunctions()) {
val name = function.simpleName.asString()
Expand All @@ -58,16 +60,17 @@ object ConfigUtils {
} else {
if (name.startsWith("get")) {
val propertyName = name.substring(3).replaceFirstChar { it.lowercaseChar() }
propertyMap.computeIfAbsent(propertyName) {FieldAndAccessors()}.getter = function
}
if (name.startsWith("set")) {
propertyMap.computeIfAbsent(propertyName) { FieldAndAccessors() }.getter = function
} else if (name.startsWith("set")) {
val propertyName = name.substring(3).replaceFirstChar { it.lowercaseChar() }
propertyMap.computeIfAbsent(propertyName) {FieldAndAccessors()}.setter = function
propertyMap.computeIfAbsent(propertyName) { FieldAndAccessors() }.setter = function
} else {
propertyMap.computeIfAbsent(name) { FieldAndAccessors() }.getter = function
}
}
}
for (property in typeDecl.getAllProperties()) {
propertyMap.computeIfAbsent(property.simpleName.asString()) {FieldAndAccessors()}.property = property
propertyMap.computeIfAbsent(property.simpleName.asString()) { FieldAndAccessors() }.property = property
}
val properties = propertyMap.values.asSequence().filter { it.setter != null && it.getter != null && it.property != null }.map { it.property!! }.toList()
if (equals == null || hashCode == null) {
Expand Down

0 comments on commit ea32188

Please sign in to comment.