Added a component stream method

This commit is contained in:
randgalt
2019-12-24 12:34:02 -05:00
parent 41f1e5fa7e
commit e9a6e79e79
3 changed files with 72 additions and 17 deletions

View File

@@ -67,23 +67,6 @@ public class NameAndAgeBuilder {
return new NameAndAge(name, age);
}
@Override
public String toString() {
return "NameAndAgeBuilder[name=" + name + ", age=" + age + "]";
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public boolean equals(Object o) {
return (this == o) || ((o instanceof NameAndAgeBuilder b)
&& Objects.equals(name, b.name)
&& (age == b.age));
}
/**
* Set a new value for the {@code name} record component in the builder
*/
@@ -113,6 +96,31 @@ public class NameAndAgeBuilder {
public int age() {
return age;
}
/**
* Return a stream of the record components as map entries keyed with the component name and the value as the component value
*/
public static Stream<Map.Entry<String, Object>> stream(NameAndAge record) {
return Stream.of(new AbstractMap.SimpleEntry<>("name", record.name()),
new AbstractMap.SimpleEntry<>("age", record.age()));
}
@Override
public String toString() {
return "NameAndAgeBuilder[name=" + name + ", age=" + age + "]";
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public boolean equals(Object o) {
return (this == o) || ((o instanceof NameAndAgeBuilder b)
&& Objects.equals(name, b.name)
&& (age == b.age));
}
}
```

View File

@@ -68,6 +68,15 @@ public interface RecordBuilderMetaData {
return "build";
}
/**
* The name to use for the method that returns the record components as a stream
*
* @return build method
*/
default String componentsMethodName() {
return "stream";
}
/**
* Return the comment to place at the top of generated files. Return null or an empty string for no comment.
*

View File

@@ -22,10 +22,13 @@ import javax.annotation.processing.Generated;
import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import java.util.AbstractMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
class InternalProcessor {
private static final AnnotationSpec generatedAnnotation = AnnotationSpec.builder(Generated.class).addMember("value", "$S", RecordBuilderProcessor.NAME).build();
@@ -55,6 +58,7 @@ class InternalProcessor {
addAllArgsConstructor();
addStaticDefaultBuilderMethod();
addStaticCopyBuilderMethod();
addStaticComponentsMethod();
addBuildMethod();
addToStringMethod();
addHashCodeMethod();
@@ -296,6 +300,40 @@ class InternalProcessor {
builder.addMethod(methodSpec);
}
private void addStaticComponentsMethod() {
/*
Adds a static method that converts a record instance into a stream of its component parts
public static Stream<Map.Entry<String, Object>> stream(MyRecord record) {
return Stream.of(
new AbstractMap.SimpleEntry<>("p1", record.p1()),
new AbstractMap.SimpleEntry<>("p2", record.p2())
);
}
*/
var codeBuilder = CodeBlock.builder().add("return $T.of(", Stream.class);
IntStream.range(0, recordComponents.size()).forEach(index -> {
if (index > 0) {
codeBuilder.add(",\n ");
}
var name = recordComponents.get(index).name();
codeBuilder.add("new $T<>($S, record.$L())", AbstractMap.SimpleEntry.class, name, name);
});
codeBuilder.add(")");
var mapEntryTypeVariables = ParameterizedTypeName.get(Map.Entry.class, String.class, Object.class);
var mapEntryType = ParameterizedTypeName.get(ClassName.get(Stream.class), mapEntryTypeVariables);
var methodSpec = MethodSpec.methodBuilder(metaData.componentsMethodName())
.addJavadoc("Return a stream of the record components as map entries keyed with the component name and the value as the component value\n")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.addParameter(recordClassType.typeName(), "record")
.addAnnotation(generatedAnnotation)
.addTypeVariables(typeVariables)
.returns(mapEntryType)
.addStatement(codeBuilder.build())
.build();
builder.addMethod(methodSpec);
}
private void add1Field(ClassType component) {
/*
For a single record component, add a field similar to: