Compare commits
9 Commits
record-bui
...
record-bui
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d112a1b352 | ||
|
|
86093b6bad | ||
|
|
7b6ad4d7ba | ||
|
|
cd059f1207 | ||
|
|
642dd01421 | ||
|
|
efd1a6b0d4 | ||
|
|
b525eddc76 | ||
|
|
d3828eda74 | ||
|
|
fef69af183 |
24
pom.xml
24
pom.xml
@@ -5,7 +5,7 @@
|
||||
<groupId>io.soabase.record-builder</groupId>
|
||||
<artifactId>record-builder</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<version>32</version>
|
||||
<version>33</version>
|
||||
|
||||
<modules>
|
||||
<module>record-builder-core</module>
|
||||
@@ -32,6 +32,9 @@
|
||||
<maven-shade-plugin-version>3.2.1</maven-shade-plugin-version>
|
||||
<maven-release-plugin-version>2.5.3</maven-release-plugin-version>
|
||||
<maven-jar-plugin-version>3.2.0</maven-jar-plugin-version>
|
||||
<maven-surefire-plugin-version>3.0.0-M5</maven-surefire-plugin-version>
|
||||
|
||||
<jacoco-maven-plugin-version>0.8.7</jacoco-maven-plugin-version>
|
||||
|
||||
<license-file-path>src/etc/header.txt</license-file-path>
|
||||
|
||||
@@ -77,7 +80,7 @@
|
||||
<url>https://github.com/randgalt/record-builder</url>
|
||||
<connection>scm:git:https://github.com/randgalt/record-builder.git</connection>
|
||||
<developerConnection>scm:git:git@github.com:randgalt/record-builder.git</developerConnection>
|
||||
<tag>record-builder-32</tag>
|
||||
<tag>record-builder-33</tag>
|
||||
</scm>
|
||||
|
||||
<issueManagement>
|
||||
@@ -153,6 +156,12 @@
|
||||
<build>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>${maven-surefire-plugin-version}</version>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
@@ -319,6 +328,12 @@
|
||||
<artifactId>maven-gpg-plugin</artifactId>
|
||||
<version>${maven-gpg-plugin-version}</version>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<version>${jacoco-maven-plugin-version}</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
|
||||
@@ -352,6 +367,11 @@
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-release-plugin</artifactId>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>io.soabase.record-builder</groupId>
|
||||
<artifactId>record-builder</artifactId>
|
||||
<version>32</version>
|
||||
<version>33</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -99,6 +99,11 @@ public @interface RecordBuilder {
|
||||
*/
|
||||
String componentsMethodName() default "stream";
|
||||
|
||||
/**
|
||||
* If true, a "With" interface is generated and an associated static factory
|
||||
*/
|
||||
boolean enableWither() default true;
|
||||
|
||||
/**
|
||||
* The name to use for the nested With class
|
||||
*/
|
||||
@@ -139,6 +144,11 @@ public @interface RecordBuilder {
|
||||
*/
|
||||
boolean emptyDefaultForOptional() default true;
|
||||
|
||||
/**
|
||||
* Add non-optional setter methods for optional record components.
|
||||
*/
|
||||
boolean addConcreteSettersForOptional() default false;
|
||||
|
||||
/**
|
||||
* Add not-null checks for record components annotated with any annotation named either "NotNull",
|
||||
* "NoNull", or "NonNull" (see {@link #interpretNotNullsPattern()} for the actual regex matching pattern).
|
||||
@@ -195,6 +205,11 @@ public @interface RecordBuilder {
|
||||
*/
|
||||
String setterPrefix() default "";
|
||||
|
||||
/**
|
||||
* If true, getters will be generated for the Builder class.
|
||||
*/
|
||||
boolean enableGetters() default true;
|
||||
|
||||
/**
|
||||
* If set, all builder getter methods will be prefixed with this string. Camel-casing will
|
||||
* still be enforced, so if this option is set to "get", a field named "myField" will get
|
||||
@@ -219,6 +234,24 @@ public @interface RecordBuilder {
|
||||
* this option does nothing.
|
||||
*/
|
||||
String beanClassName() default "";
|
||||
|
||||
/**
|
||||
* If true, generated classes are annotated with {@code RecordBuilderGenerated} which has a retention
|
||||
* policy of {@code CLASS}. This ensures that analyzers such as Jacoco will ignore the generated class.
|
||||
*/
|
||||
boolean addClassRetainedGenerated() default false;
|
||||
|
||||
/**
|
||||
* The {@link #fromMethodName} method instantiates an internal private class. This is the
|
||||
* name of that class.
|
||||
*/
|
||||
String fromWithClassName() default "_FromWith";
|
||||
|
||||
/**
|
||||
* If true, a functional-style builder is added so that record instances can be instantiated
|
||||
* without {@code new}.
|
||||
*/
|
||||
boolean addStaticBuilder() default true;
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.CLASS)
|
||||
|
||||
@@ -21,7 +21,8 @@ import java.lang.annotation.*;
|
||||
interpretNotNulls = true,
|
||||
useImmutableCollections = true,
|
||||
addSingleItemCollectionBuilders = true,
|
||||
addFunctionalMethodsToWith = true
|
||||
addFunctionalMethodsToWith = true,
|
||||
addClassRetainedGenerated = true
|
||||
))
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@Target(ElementType.TYPE)
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright 2019 Jordan Zimmerman
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 io.soabase.recordbuilder.core;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
|
||||
/**
|
||||
* Jacoco ignores classes and methods annotated with `*Generated`
|
||||
*/
|
||||
@Target({PACKAGE, TYPE, METHOD, CONSTRUCTOR, FIELD, LOCAL_VARIABLE, PARAMETER})
|
||||
@Retention(RetentionPolicy.CLASS)
|
||||
public @interface RecordBuilderGenerated {
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>io.soabase.record-builder</groupId>
|
||||
<artifactId>record-builder</artifactId>
|
||||
<version>32</version>
|
||||
<version>33</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -109,6 +109,10 @@ class CollectionBuilderUtils {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
boolean isImmutableCollection(RecordClassType component) {
|
||||
return useImmutableCollections && (isList(component) || isMap(component) || isSet(component) || component.rawTypeName().equals(collectionType));
|
||||
}
|
||||
|
||||
boolean isList(RecordClassType component) {
|
||||
return component.rawTypeName().equals(listType);
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import javax.lang.model.element.*;
|
||||
import java.util.*;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
@@ -32,6 +33,7 @@ import static io.soabase.recordbuilder.processor.CollectionBuilderUtils.SingleIt
|
||||
import static io.soabase.recordbuilder.processor.ElementUtils.getBuilderName;
|
||||
import static io.soabase.recordbuilder.processor.ElementUtils.getWithMethodName;
|
||||
import static io.soabase.recordbuilder.processor.RecordBuilderProcessor.generatedRecordBuilderAnnotation;
|
||||
import static io.soabase.recordbuilder.processor.RecordBuilderProcessor.recordBuilderGeneratedAnnotation;
|
||||
|
||||
class InternalRecordBuilderProcessor {
|
||||
private final RecordBuilder.Options metaData;
|
||||
@@ -47,10 +49,7 @@ class InternalRecordBuilderProcessor {
|
||||
private final CollectionBuilderUtils collectionBuilderUtils;
|
||||
|
||||
private static final TypeName overrideType = TypeName.get(Override.class);
|
||||
private static final TypeName optionalType = TypeName.get(Optional.class);
|
||||
private static final TypeName optionalIntType = TypeName.get(OptionalInt.class);
|
||||
private static final TypeName optionalLongType = TypeName.get(OptionalLong.class);
|
||||
private static final TypeName optionalDoubleType = TypeName.get(OptionalDouble.class);
|
||||
private static final TypeName validType = ClassName.get("javax.validation", "Valid");
|
||||
private static final TypeName validatorTypeName = ClassName.get("io.soabase.recordbuilder.validator", "RecordBuilderValidator");
|
||||
private static final TypeVariableName rType = TypeVariableName.get("R");
|
||||
private final ProcessingEnvironment processingEnv;
|
||||
@@ -71,19 +70,28 @@ class InternalRecordBuilderProcessor {
|
||||
builder = TypeSpec.classBuilder(builderClassType.name())
|
||||
.addAnnotation(generatedRecordBuilderAnnotation)
|
||||
.addTypeVariables(typeVariables);
|
||||
if (metaData.addClassRetainedGenerated()) {
|
||||
builder.addAnnotation(recordBuilderGeneratedAnnotation);
|
||||
}
|
||||
addVisibility(recordActualPackage.equals(packageName), record.getModifiers());
|
||||
addWithNestedClass();
|
||||
if (metaData.enableWither()) {
|
||||
addWithNestedClass();
|
||||
}
|
||||
if (!metaData.beanClassName().isEmpty()) {
|
||||
addBeanNestedClass();
|
||||
}
|
||||
addDefaultConstructor();
|
||||
addStaticBuilder();
|
||||
if (metaData.addStaticBuilder()) {
|
||||
addStaticBuilder();
|
||||
}
|
||||
if (recordComponents.size() > 0) {
|
||||
addAllArgsConstructor();
|
||||
}
|
||||
addStaticDefaultBuilderMethod();
|
||||
addStaticCopyBuilderMethod();
|
||||
addStaticFromWithMethod();
|
||||
if (metaData.enableWither()) {
|
||||
addStaticFromWithMethod();
|
||||
}
|
||||
addStaticComponentsMethod();
|
||||
addBuildMethod();
|
||||
addToStringMethod();
|
||||
@@ -92,7 +100,12 @@ class InternalRecordBuilderProcessor {
|
||||
recordComponents.forEach(component -> {
|
||||
add1Field(component);
|
||||
add1SetterMethod(component);
|
||||
add1GetterMethod(component);
|
||||
if (metaData.enableGetters()) {
|
||||
add1GetterMethod(component);
|
||||
}
|
||||
if (metaData.addConcreteSettersForOptional()) {
|
||||
add1ConcreteOptionalSetterMethod(component);
|
||||
}
|
||||
var collectionMetaData = collectionBuilderUtils.singleItemsMetaData(component, EXCLUDE_WILDCARD_TYPES);
|
||||
collectionMetaData.ifPresent(meta -> add1CollectionBuilders(meta, component));
|
||||
});
|
||||
@@ -151,6 +164,9 @@ class InternalRecordBuilderProcessor {
|
||||
.addJavadoc("Add withers to {@code $L}\n", recordClassType.name())
|
||||
.addModifiers(Modifier.PUBLIC)
|
||||
.addTypeVariables(typeVariables);
|
||||
if (metaData.addClassRetainedGenerated()) {
|
||||
classBuilder.addAnnotation(recordBuilderGeneratedAnnotation);
|
||||
}
|
||||
recordComponents.forEach(component -> addNestedGetterMethod(classBuilder, component, prefixedName(component, true)));
|
||||
addWithBuilderMethod(classBuilder);
|
||||
addWithSuppliedBuilderMethod(classBuilder);
|
||||
@@ -225,7 +241,7 @@ class InternalRecordBuilderProcessor {
|
||||
}
|
||||
*/
|
||||
var codeBlockBuilder = CodeBlock.builder()
|
||||
.add("return new $L(", builderClassType.name());
|
||||
.add("return new $L$L(", builderClassType.name(), typeVariables.isEmpty() ? "" : "<>");
|
||||
addComponentCallsAsArguments(-1, codeBlockBuilder);
|
||||
codeBlockBuilder.add(");");
|
||||
var methodSpec = MethodSpec.methodBuilder(metaData.withClassMethodPrefix())
|
||||
@@ -371,8 +387,10 @@ class InternalRecordBuilderProcessor {
|
||||
private void addNullCheckCodeBlock(CodeBlock.Builder builder, int index) {
|
||||
if (metaData.interpretNotNulls()) {
|
||||
var component = recordComponents.get(index);
|
||||
if (!component.typeName().isPrimitive() && isNullAnnotated(component)) {
|
||||
builder.addStatement("$T.requireNonNull($L, $S)", Objects.class, component.name(), component.name() + " is required");
|
||||
if (!collectionBuilderUtils.isImmutableCollection(component)) {
|
||||
if (!component.typeName().isPrimitive() && isNullAnnotated(component)) {
|
||||
builder.addStatement("$T.requireNonNull($L, $S)", Objects.class, component.name(), component.name() + " is required");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -474,7 +492,12 @@ class InternalRecordBuilderProcessor {
|
||||
*/
|
||||
var codeBuilder = CodeBlock.builder();
|
||||
codeBuilder.add("return (this == o) || (");
|
||||
codeBuilder.add("(o instanceof $L $L)", builderClassType.name(), uniqueVarName);
|
||||
if (typeVariables.isEmpty()) {
|
||||
codeBuilder.add("(o instanceof $L $L)", builderClassType.name(), uniqueVarName);
|
||||
} else {
|
||||
String wildcardList = typeVariables.stream().map(__ -> "?").collect(Collectors.joining(","));
|
||||
codeBuilder.add("(o instanceof $L<$L> $L)", builderClassType.name(), wildcardList, uniqueVarName);
|
||||
}
|
||||
recordComponents.forEach(recordComponent -> {
|
||||
String name = recordComponent.name();
|
||||
if (recordComponent.typeName().isPrimitive()) {
|
||||
@@ -521,6 +544,16 @@ class InternalRecordBuilderProcessor {
|
||||
*/
|
||||
|
||||
var codeBuilder = CodeBlock.builder();
|
||||
|
||||
IntStream.range(0, recordComponents.size()).forEach(index -> {
|
||||
var recordComponent = recordComponents.get(index);
|
||||
if (collectionBuilderUtils.isImmutableCollection(recordComponent)) {
|
||||
codeBuilder.add("$[$L = ", recordComponent.name());
|
||||
collectionBuilderUtils.add(codeBuilder, recordComponents.get(index));
|
||||
codeBuilder.add(";\n$]");
|
||||
}
|
||||
});
|
||||
|
||||
addNullCheckCodeBlock(codeBuilder);
|
||||
codeBuilder.add("$[return ");
|
||||
if (metaData.useValidationApi()) {
|
||||
@@ -531,7 +564,7 @@ class InternalRecordBuilderProcessor {
|
||||
if (index > 0) {
|
||||
codeBuilder.add(", ");
|
||||
}
|
||||
collectionBuilderUtils.add(codeBuilder, recordComponents.get(index));
|
||||
codeBuilder.add("$L", recordComponents.get(index).name());
|
||||
});
|
||||
codeBuilder.add(")");
|
||||
if (metaData.useValidationApi()) {
|
||||
@@ -541,63 +574,83 @@ class InternalRecordBuilderProcessor {
|
||||
return codeBuilder.build();
|
||||
}
|
||||
|
||||
private TypeName buildWithTypeName()
|
||||
{
|
||||
ClassName rawTypeName = ClassName.get(packageName, builderClassType.name() + "." + metaData.withClassName());
|
||||
if (typeVariables.isEmpty()) {
|
||||
return rawTypeName;
|
||||
}
|
||||
return ParameterizedTypeName.get(rawTypeName, typeVariables.toArray(new TypeName[]{}));
|
||||
}
|
||||
|
||||
private void addFromWithClass() {
|
||||
/*
|
||||
Adds static private class that implements/proxies the Wither
|
||||
|
||||
private static final class _FromWith implements MyRecordBuilder.With {
|
||||
private final MyRecord from;
|
||||
|
||||
@Override
|
||||
public String p1() {
|
||||
return from.p1();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String p2() {
|
||||
return from.p2();
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
var fromWithClassBuilder = TypeSpec.classBuilder(metaData.fromWithClassName())
|
||||
.addModifiers(Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL)
|
||||
.addAnnotation(generatedRecordBuilderAnnotation)
|
||||
.addTypeVariables(typeVariables)
|
||||
.addSuperinterface(buildWithTypeName());
|
||||
if (metaData.addClassRetainedGenerated()) {
|
||||
fromWithClassBuilder.addAnnotation(recordBuilderGeneratedAnnotation);
|
||||
}
|
||||
|
||||
fromWithClassBuilder.addField(recordClassType.typeName(), "from", Modifier.PRIVATE, Modifier.FINAL);
|
||||
MethodSpec constructorSpec = MethodSpec.constructorBuilder()
|
||||
.addParameter(recordClassType.typeName(), "from")
|
||||
.addStatement("this.from = from")
|
||||
.addModifiers(Modifier.PRIVATE)
|
||||
.build();
|
||||
fromWithClassBuilder.addMethod(constructorSpec);
|
||||
|
||||
IntStream.range(0, recordComponents.size()).forEach(index -> {
|
||||
var component = recordComponents.get(index);
|
||||
MethodSpec methodSpec = MethodSpec.methodBuilder(prefixedName(component, true))
|
||||
.returns(component.typeName())
|
||||
.addAnnotation(Override.class)
|
||||
.addModifiers(Modifier.PUBLIC)
|
||||
.addStatement("return from.$L()", component.name())
|
||||
.build();
|
||||
fromWithClassBuilder.addMethod(methodSpec);
|
||||
});
|
||||
this.builder.addType(fromWithClassBuilder.build());
|
||||
}
|
||||
|
||||
private void addStaticFromWithMethod() {
|
||||
/*
|
||||
Adds static method that returns a "with"er view of an existing record.
|
||||
|
||||
public static With from(MyRecord from) {
|
||||
return new MyRecordBuilder.With() {
|
||||
@Override
|
||||
public String p1() {
|
||||
return from.p1();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String p2() {
|
||||
return from.p2();
|
||||
}
|
||||
};
|
||||
return new _FromWith(from);
|
||||
}
|
||||
*/
|
||||
var witherClassNameBuilder = CodeBlock.builder()
|
||||
.add("$L.$L", builderClassType.name(), metaData.withClassName());
|
||||
if (!typeVariables.isEmpty()) {
|
||||
witherClassNameBuilder.add("<");
|
||||
IntStream.range(0, typeVariables.size()).forEach(index -> {
|
||||
if (index > 0) {
|
||||
witherClassNameBuilder.add(", ");
|
||||
}
|
||||
witherClassNameBuilder.add(typeVariables.get(index).name);
|
||||
});
|
||||
witherClassNameBuilder.add(">");
|
||||
}
|
||||
var witherClassName = witherClassNameBuilder.build().toString();
|
||||
var codeBuilder = CodeBlock.builder()
|
||||
.add("return new $L", witherClassName)
|
||||
.add("() {\n").indent();
|
||||
IntStream.range(0, recordComponents.size()).forEach(index -> {
|
||||
var component = recordComponents.get(index);
|
||||
if (index > 0) {
|
||||
codeBuilder.add("\n");
|
||||
}
|
||||
codeBuilder.add("@Override\n")
|
||||
.add("public $T $L() {\n", component.typeName(), prefixedName(component, true))
|
||||
.indent()
|
||||
.addStatement("return from.$L()", component.name())
|
||||
.unindent()
|
||||
.add("}\n");
|
||||
});
|
||||
codeBuilder.unindent().addStatement("}");
|
||||
|
||||
var withType = ClassName.get("", witherClassName);
|
||||
var methodSpec = MethodSpec.methodBuilder("from")//metaData.copyMethodName())
|
||||
addFromWithClass();
|
||||
|
||||
var methodSpec = MethodSpec.methodBuilder(metaData.fromMethodName())
|
||||
.addJavadoc("Return a \"with\"er for an existing record instance\n")
|
||||
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
|
||||
.addAnnotation(generatedRecordBuilderAnnotation)
|
||||
.addTypeVariables(typeVariables)
|
||||
.addParameter(recordClassType.typeName(), metaData.fromMethodName())
|
||||
.returns(withType)
|
||||
.addCode(codeBuilder.build())
|
||||
.returns(buildWithTypeName())
|
||||
.addStatement("return new $L$L(from)", metaData.fromWithClassName(), typeVariables.isEmpty() ? "" : "<>")
|
||||
.build();
|
||||
builder.addMethod(methodSpec);
|
||||
}
|
||||
@@ -690,31 +743,17 @@ class InternalRecordBuilderProcessor {
|
||||
*/
|
||||
var fieldSpecBuilder = FieldSpec.builder(component.typeName(), component.name(), Modifier.PRIVATE);
|
||||
if (metaData.emptyDefaultForOptional()) {
|
||||
TypeName thisOptionalType = null;
|
||||
if (isOptional(component)) {
|
||||
thisOptionalType = optionalType;
|
||||
} else if (component.typeName().equals(optionalIntType)) {
|
||||
thisOptionalType = optionalIntType;
|
||||
} else if (component.typeName().equals(optionalLongType)) {
|
||||
thisOptionalType = optionalLongType;
|
||||
} else if (component.typeName().equals(optionalDoubleType)) {
|
||||
thisOptionalType = optionalDoubleType;
|
||||
}
|
||||
if (thisOptionalType != null) {
|
||||
var codeBlock = CodeBlock.builder().add("$T.empty()", thisOptionalType).build();
|
||||
Optional<OptionalType> thisOptionalType = OptionalType.fromClassType(component);
|
||||
if (thisOptionalType.isPresent()) {
|
||||
var codeBlock = CodeBlock.builder()
|
||||
.add("$T.empty()", thisOptionalType.get().typeName())
|
||||
.build();
|
||||
fieldSpecBuilder.initializer(codeBlock);
|
||||
}
|
||||
}
|
||||
builder.addField(fieldSpecBuilder.build());
|
||||
}
|
||||
|
||||
private boolean isOptional(ClassType component) {
|
||||
if (component.typeName().equals(optionalType)) {
|
||||
return true;
|
||||
}
|
||||
return (component.typeName() instanceof ParameterizedTypeName parameterizedTypeName) && parameterizedTypeName.rawType.equals(optionalType);
|
||||
}
|
||||
|
||||
private void addNestedGetterMethod(TypeSpec.Builder classBuilder, RecordClassType component, String methodName) {
|
||||
/*
|
||||
For a single record component, add a getter similar to:
|
||||
@@ -726,7 +765,7 @@ class InternalRecordBuilderProcessor {
|
||||
.addModifiers(Modifier.ABSTRACT, Modifier.PUBLIC)
|
||||
.addAnnotation(generatedRecordBuilderAnnotation)
|
||||
.returns(component.typeName());
|
||||
addAccessorAnnotations(component, methodSpecBuilder);
|
||||
addAccessorAnnotations(component, methodSpecBuilder, this::filterOutValid);
|
||||
classBuilder.addMethod(methodSpecBuilder.build());
|
||||
}
|
||||
|
||||
@@ -734,6 +773,10 @@ class InternalRecordBuilderProcessor {
|
||||
return !annotationSpec.type.equals(overrideType);
|
||||
}
|
||||
|
||||
private boolean filterOutValid(AnnotationSpec annotationSpec) {
|
||||
return !annotationSpec.type.equals(validType);
|
||||
}
|
||||
|
||||
private void addConstructorAnnotations(RecordClassType component, ParameterSpec.Builder parameterSpecBuilder) {
|
||||
if (metaData.inheritComponentAnnotations()) {
|
||||
component.getCanonicalConstructorAnnotations()
|
||||
@@ -744,12 +787,13 @@ class InternalRecordBuilderProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
private void addAccessorAnnotations(RecordClassType component, MethodSpec.Builder methodSpecBuilder) {
|
||||
private void addAccessorAnnotations(RecordClassType component, MethodSpec.Builder methodSpecBuilder, Predicate<AnnotationSpec> additionalFilter) {
|
||||
if (metaData.inheritComponentAnnotations()) {
|
||||
component.getAccessorAnnotations()
|
||||
.stream()
|
||||
.map(AnnotationSpec::get)
|
||||
.filter(this::filterOutOverride)
|
||||
.filter(additionalFilter)
|
||||
.forEach(methodSpecBuilder::addAnnotation);
|
||||
}
|
||||
}
|
||||
@@ -891,7 +935,7 @@ class InternalRecordBuilderProcessor {
|
||||
.addAnnotation(generatedRecordBuilderAnnotation)
|
||||
.returns(component.typeName())
|
||||
.addStatement("return $L", component.name());
|
||||
addAccessorAnnotations(component, methodSpecBuilder);
|
||||
addAccessorAnnotations(component, methodSpecBuilder, __ -> true);
|
||||
builder.addMethod(methodSpecBuilder.build());
|
||||
}
|
||||
|
||||
@@ -926,6 +970,33 @@ class InternalRecordBuilderProcessor {
|
||||
builder.addMethod(methodSpec.build());
|
||||
}
|
||||
|
||||
private void add1ConcreteOptionalSetterMethod(RecordClassType component) {
|
||||
/*
|
||||
For a single optional record component, add a concrete setter similar to:
|
||||
|
||||
public MyRecordBuilder p(T p) {
|
||||
this.p = p;
|
||||
return this;
|
||||
}
|
||||
*/
|
||||
var optionalType = OptionalType.fromClassType(component);
|
||||
if (optionalType.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
var type = optionalType.get();
|
||||
var methodSpec = MethodSpec.methodBuilder(prefixedName(component, false))
|
||||
.addModifiers(Modifier.PUBLIC)
|
||||
.addAnnotation(generatedRecordBuilderAnnotation)
|
||||
.returns(builderClassType.typeName());
|
||||
|
||||
var parameterSpecBuilder = ParameterSpec.builder(type.valueType(), component.name());
|
||||
methodSpec.addJavadoc("Set a new value for the {@code $L} record component in the builder\n", component.name())
|
||||
.addStatement("this.$L = $T.of($L)", component.name(), type.typeName(), component.name());
|
||||
addConstructorAnnotations(component, parameterSpecBuilder);
|
||||
methodSpec.addStatement("return this").addParameter(parameterSpecBuilder.build());
|
||||
builder.addMethod(methodSpec.build());
|
||||
}
|
||||
|
||||
private List<TypeVariableName> typeVariablesWithReturn() {
|
||||
var variables = new ArrayList<TypeVariableName>();
|
||||
variables.add(rType);
|
||||
@@ -993,7 +1064,7 @@ class InternalRecordBuilderProcessor {
|
||||
|
||||
private String prefixedName(RecordClassType component, boolean isGetter) {
|
||||
BiFunction<String, String, String> prefixer = (p, s) -> p.isEmpty()
|
||||
? s : p + Character.toUpperCase(s.charAt(0)) + s.substring(1);
|
||||
? s : p + Character.toUpperCase(s.charAt(0)) + s.substring(1);
|
||||
boolean isBool = component.typeName().toString().toLowerCase(Locale.ROOT).equals("boolean");
|
||||
if (isGetter) {
|
||||
if (isBool) {
|
||||
|
||||
@@ -33,6 +33,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
import static io.soabase.recordbuilder.processor.ElementUtils.getBuilderName;
|
||||
import static io.soabase.recordbuilder.processor.RecordBuilderProcessor.generatedRecordInterfaceAnnotation;
|
||||
import static io.soabase.recordbuilder.processor.RecordBuilderProcessor.recordBuilderGeneratedAnnotation;
|
||||
|
||||
class InternalRecordInterfaceProcessor {
|
||||
private final ProcessingEnvironment processingEnv;
|
||||
@@ -68,6 +69,9 @@ class InternalRecordInterfaceProcessor {
|
||||
.addModifiers(Modifier.PUBLIC)
|
||||
.addAnnotation(generatedRecordInterfaceAnnotation)
|
||||
.addTypeVariables(typeVariables);
|
||||
if (metaData.addClassRetainedGenerated()) {
|
||||
builder.addAnnotation(recordBuilderGeneratedAnnotation);
|
||||
}
|
||||
|
||||
if (addRecordBuilder) {
|
||||
ClassType builderClassType = ElementUtils.getClassType(packageName, getBuilderName(iface, metaData, recordClassType, metaData.suffix()) + "." + metaData.withClassName(), iface.getTypeParameters());
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* Copyright 2019 Jordan Zimmerman
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 io.soabase.recordbuilder.processor;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.OptionalDouble;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.OptionalLong;
|
||||
import com.squareup.javapoet.ParameterizedTypeName;
|
||||
import com.squareup.javapoet.TypeName;
|
||||
|
||||
public record OptionalType(TypeName typeName, TypeName valueType) {
|
||||
|
||||
private static final TypeName optionalType = TypeName.get(Optional.class);
|
||||
private static final TypeName optionalIntType = TypeName.get(OptionalInt.class);
|
||||
private static final TypeName optionalLongType = TypeName.get(OptionalLong.class);
|
||||
private static final TypeName optionalDoubleType = TypeName.get(OptionalDouble.class);
|
||||
|
||||
private static boolean isOptional(ClassType component) {
|
||||
if (component.typeName().equals(optionalType)) {
|
||||
return true;
|
||||
}
|
||||
return (component.typeName() instanceof ParameterizedTypeName parameterizedTypeName)
|
||||
&& parameterizedTypeName.rawType.equals(optionalType);
|
||||
}
|
||||
|
||||
static Optional<OptionalType> fromClassType(final ClassType component) {
|
||||
if (isOptional(component)) {
|
||||
if (!(component.typeName() instanceof ParameterizedTypeName parameterizedType)) {
|
||||
return Optional.of(new OptionalType(optionalType, TypeName.get(Object.class)));
|
||||
}
|
||||
final TypeName containingType = parameterizedType.typeArguments.isEmpty()
|
||||
? TypeName.get(Object.class)
|
||||
: parameterizedType.typeArguments.get(0);
|
||||
return Optional.of(new OptionalType(optionalType, containingType));
|
||||
}
|
||||
if (component.typeName().equals(optionalIntType)) {
|
||||
return Optional.of(new OptionalType(optionalIntType, TypeName.get(int.class)));
|
||||
}
|
||||
if (component.typeName().equals(optionalLongType)) {
|
||||
return Optional.of(new OptionalType(optionalLongType, TypeName.get(long.class)));
|
||||
}
|
||||
if (component.typeName().equals(optionalDoubleType)) {
|
||||
return Optional.of(new OptionalType(optionalDoubleType, TypeName.get(double.class)));
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ import com.squareup.javapoet.AnnotationSpec;
|
||||
import com.squareup.javapoet.JavaFile;
|
||||
import com.squareup.javapoet.TypeSpec;
|
||||
import io.soabase.recordbuilder.core.RecordBuilder;
|
||||
import io.soabase.recordbuilder.core.RecordBuilderGenerated;
|
||||
import io.soabase.recordbuilder.core.RecordInterface;
|
||||
|
||||
import javax.annotation.processing.AbstractProcessor;
|
||||
@@ -46,6 +47,7 @@ public class RecordBuilderProcessor
|
||||
|
||||
static final AnnotationSpec generatedRecordBuilderAnnotation = AnnotationSpec.builder(Generated.class).addMember("value", "$S", RecordBuilder.class.getName()).build();
|
||||
static final AnnotationSpec generatedRecordInterfaceAnnotation = AnnotationSpec.builder(Generated.class).addMember("value", "$S", RecordInterface.class.getName()).build();
|
||||
static final AnnotationSpec recordBuilderGeneratedAnnotation = AnnotationSpec.builder(RecordBuilderGenerated.class).build();
|
||||
|
||||
@Override
|
||||
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>io.soabase.record-builder</groupId>
|
||||
<artifactId>record-builder</artifactId>
|
||||
<version>32</version>
|
||||
<version>33</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -66,6 +66,48 @@
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>default-prepare-agent</id>
|
||||
<goals>
|
||||
<goal>prepare-agent</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>default-report</id>
|
||||
<goals>
|
||||
<goal>report</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>default-check</id>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<includes>
|
||||
<include>io/soabase/recordbuilder/test/jacoco/*</include>
|
||||
</includes>
|
||||
<rules>
|
||||
<rule>
|
||||
<element>BUNDLE</element>
|
||||
<limits>
|
||||
<limit>
|
||||
<counter>COMPLEXITY</counter>
|
||||
<value>COVEREDRATIO</value>
|
||||
<minimum>0.60</minimum>
|
||||
</limit>
|
||||
</limits>
|
||||
</rule>
|
||||
</rules>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
||||
@@ -22,5 +22,5 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RecordBuilderFull
|
||||
public record FullRecord(@NotNull List<Number> numbers, @NotNull Map<Number, FullRecord> fullRecords) {
|
||||
public record FullRecord(@NotNull List<Number> numbers, @NotNull Map<Number, FullRecord> fullRecords, @NotNull String justAString) {
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package io.soabase.recordbuilder.test;
|
||||
|
||||
import io.soabase.recordbuilder.core.RecordBuilder;
|
||||
|
||||
/**
|
||||
* Copyright 2019 Jordan Zimmerman
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
@RecordBuilder.Options(addStaticBuilder = false)
|
||||
@RecordBuilder
|
||||
public record NoStaticBuilder(String foo) {
|
||||
}
|
||||
@@ -22,6 +22,6 @@ import java.util.OptionalDouble;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.OptionalLong;
|
||||
|
||||
@RecordBuilder.Options(emptyDefaultForOptional = true)
|
||||
@RecordBuilder.Options(emptyDefaultForOptional = true, addConcreteSettersForOptional = true)
|
||||
@RecordBuilder
|
||||
public record RecordWithOptional(Optional<String> value, Optional raw, OptionalInt i, OptionalLong l, OptionalDouble d) {}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copyright 2019 Jordan Zimmerman
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 io.soabase.recordbuilder.test;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.OptionalDouble;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.OptionalLong;
|
||||
import io.soabase.recordbuilder.core.RecordBuilder;
|
||||
|
||||
@RecordBuilder.Options(emptyDefaultForOptional = true)
|
||||
@RecordBuilder
|
||||
public record RecordWithOptional2(Optional<String> value, Optional raw, OptionalInt i, OptionalLong l, OptionalDouble d) {}
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright 2019 Jordan Zimmerman
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 io.soabase.recordbuilder.test;
|
||||
|
||||
import io.soabase.recordbuilder.core.RecordBuilder;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@RecordBuilder
|
||||
@RecordBuilder.Options(useValidationApi = true)
|
||||
public record RequestWithValid(@NotNull @Valid Part part) implements RequestWithValidBuilder.With {
|
||||
public record Part(@NotBlank String name) {}
|
||||
}
|
||||
@@ -18,8 +18,9 @@ package io.soabase.recordbuilder.test;
|
||||
import io.soabase.recordbuilder.core.RecordBuilder;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.List;
|
||||
|
||||
@RecordBuilder.Options(interpretNotNulls = true)
|
||||
@RecordBuilder
|
||||
public record RequiredRecord(@NotNull String hey, @NotNull int i) implements RequiredRecordBuilder.With {
|
||||
public record RequiredRecord(@NotNull String hey, @NotNull int i, @NotNull List<String> l) implements RequiredRecordBuilder.With {
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Copyright 2019 Jordan Zimmerman
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 io.soabase.recordbuilder.test;
|
||||
|
||||
import io.soabase.recordbuilder.core.RecordBuilder;
|
||||
|
||||
@RecordBuilder
|
||||
@RecordBuilder.Options(
|
||||
enableGetters = false,
|
||||
enableWither = false
|
||||
)
|
||||
public record StrippedFeaturesRecord(int aField) {}
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright 2019 Jordan Zimmerman
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 io.soabase.recordbuilder.test.jacoco;
|
||||
|
||||
import io.soabase.recordbuilder.core.RecordBuilderFull;
|
||||
import io.soabase.recordbuilder.core.RecordBuilderGenerated;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RecordBuilderFull
|
||||
@RecordBuilderGenerated
|
||||
public record FullRecordForJacoco(@NotNull List<Number> numbers, @NotNull Map<Number, FullRecordForJacoco> fullRecords, @NotNull String justAString) {
|
||||
}
|
||||
@@ -33,4 +33,36 @@ class TestOptional {
|
||||
Assertions.assertEquals(OptionalLong.empty(), record.l());
|
||||
Assertions.assertEquals(OptionalDouble.empty(), record.d());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRawSetters() {
|
||||
var record = RecordWithOptionalBuilder.builder()
|
||||
.value("value")
|
||||
.raw("rawValue")
|
||||
.i(42)
|
||||
.l(424242L)
|
||||
.d(42.42)
|
||||
.build();
|
||||
Assertions.assertEquals(Optional.of("value"), record.value());
|
||||
Assertions.assertEquals(Optional.of("rawValue"), record.raw());
|
||||
Assertions.assertEquals(OptionalInt.of(42), record.i());
|
||||
Assertions.assertEquals(OptionalLong.of(424242L), record.l());
|
||||
Assertions.assertEquals(OptionalDouble.of(42.42), record.d());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testOptionalSetters() {
|
||||
var record = RecordWithOptional2Builder.builder()
|
||||
.value(Optional.of("value"))
|
||||
.raw(Optional.of("rawValue"))
|
||||
.i(OptionalInt.of(42))
|
||||
.l(OptionalLong.of(424242L))
|
||||
.d(OptionalDouble.of(42.42))
|
||||
.build();
|
||||
Assertions.assertEquals(Optional.of("value"), record.value());
|
||||
Assertions.assertEquals(Optional.of("rawValue"), record.raw());
|
||||
Assertions.assertEquals(OptionalInt.of(42), record.i());
|
||||
Assertions.assertEquals(OptionalLong.of(424242L), record.l());
|
||||
Assertions.assertEquals(OptionalDouble.of(42.42), record.d());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,11 +20,15 @@ import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
class TestRecordBuilderFull {
|
||||
@Test
|
||||
void testNonNull() {
|
||||
Assertions.assertThrows(NullPointerException.class, () -> FullRecordBuilder.builder().build());
|
||||
var record = FullRecordBuilder.builder().justAString("").build();
|
||||
Assertions.assertEquals(List.of(), record.numbers());
|
||||
Assertions.assertEquals(Map.of(), record.fullRecords());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -32,6 +36,7 @@ class TestRecordBuilderFull {
|
||||
var record = FullRecordBuilder.builder()
|
||||
.fullRecords(new HashMap<>())
|
||||
.numbers(new ArrayList<>())
|
||||
.justAString("")
|
||||
.build();
|
||||
Assertions.assertThrows(UnsupportedOperationException.class, () -> record.fullRecords().put(1, record));
|
||||
Assertions.assertThrows(UnsupportedOperationException.class, () -> record.numbers().add(1));
|
||||
|
||||
@@ -19,6 +19,7 @@ import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import javax.validation.ValidationException;
|
||||
import java.util.List;
|
||||
|
||||
class TestValidation {
|
||||
@Test
|
||||
@@ -33,7 +34,7 @@ class TestValidation {
|
||||
|
||||
@Test
|
||||
void testNotNullsWithNewProperty() {
|
||||
var valid = RequiredRecordBuilder.builder().hey("hey").i(1).build();
|
||||
var valid = RequiredRecordBuilder.builder().hey("hey").i(1).l(List.of()).build();
|
||||
Assertions.assertThrows(NullPointerException.class, () -> valid.withHey(null));
|
||||
}
|
||||
|
||||
@@ -42,4 +43,14 @@ class TestValidation {
|
||||
var valid = RequiredRecord2Builder.builder().hey("hey").i(1).build();
|
||||
Assertions.assertThrows(ValidationException.class, () -> valid.withHey(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRequestWithValid() {
|
||||
Assertions.assertDoesNotThrow(() -> RequestWithValidBuilder.builder()
|
||||
.part(new RequestWithValid.Part("jsfjsf"))
|
||||
.build());
|
||||
Assertions.assertThrows(ValidationException.class, () -> RequestWithValidBuilder.builder()
|
||||
.part(new RequestWithValid.Part(""))
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,13 +15,14 @@
|
||||
*/
|
||||
package io.soabase.recordbuilder.test;
|
||||
|
||||
import java.util.List;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class TestCustomMethodNames {
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class TestVariousOptions {
|
||||
|
||||
@Test
|
||||
public void builderGetsCustomSetterAndGetterNames() {
|
||||
@@ -54,4 +55,15 @@ public class TestCustomMethodNames {
|
||||
assertEquals(List.of(2), obj.getTheList());
|
||||
assertTrue(obj.isTheBoolean());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noStaticBuilder() {
|
||||
boolean hasStaticBuilder = Stream.of(NoStaticBuilderBuilder.class.getDeclaredMethods())
|
||||
.anyMatch(method -> method.getName().equals("NoStaticBuilder"));
|
||||
assertFalse(hasStaticBuilder);
|
||||
|
||||
hasStaticBuilder = Stream.of(SimpleRecordBuilder.class.getDeclaredMethods())
|
||||
.anyMatch(method -> method.getName().equals("SimpleRecord"));
|
||||
assertTrue(hasStaticBuilder);
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>io.soabase.record-builder</groupId>
|
||||
<artifactId>record-builder</artifactId>
|
||||
<version>32</version>
|
||||
<version>33</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user