From ab3251bdf32d80d4c8ba99c929bf2f48575cfcf0 Mon Sep 17 00:00:00 2001 From: Denis Stepanov Date: Wed, 2 Oct 2024 20:08:07 +0200 Subject: [PATCH] Improve build method API + small improvements (#151) --- .../javapoet/write/ExpressionWriteTest.java | 8 ++++ .../visitors/BuilderAnnotationVisitor.java | 14 +++--- .../visitors/ObjectAnnotationVisitor.java | 30 ++++++------ .../visitors/WitherAnnotationVisitor.java | 6 +-- .../micronaut/sourcegen/model/MethodDef.java | 7 ++- .../sourcegen/model/ParameterDef.java | 2 +- .../io/micronaut/sourcegen/model/TypeDef.java | 46 +++++++++---------- .../custom/visitor/GenerateSwitchVisitor.java | 22 ++++----- 8 files changed, 72 insertions(+), 63 deletions(-) diff --git a/sourcegen-generator-java/src/test/java/io/micronaut/sourcegen/javapoet/write/ExpressionWriteTest.java b/sourcegen-generator-java/src/test/java/io/micronaut/sourcegen/javapoet/write/ExpressionWriteTest.java index 1d095659..e2632671 100644 --- a/sourcegen-generator-java/src/test/java/io/micronaut/sourcegen/javapoet/write/ExpressionWriteTest.java +++ b/sourcegen-generator-java/src/test/java/io/micronaut/sourcegen/javapoet/write/ExpressionWriteTest.java @@ -163,4 +163,12 @@ public void returnPrimitiveInitialization() throws IOException { assertEquals("0", result); } + + @Test + public void returnPrimitiveInitialization2() throws IOException { + ExpressionDef intExpression = TypeDef.Primitive.INT.initialize(0); + String result = writeMethodWithExpression(intExpression); + + assertEquals("0", result); + } } diff --git a/sourcegen-generator/src/main/java/io/micronaut/sourcegen/generator/visitors/BuilderAnnotationVisitor.java b/sourcegen-generator/src/main/java/io/micronaut/sourcegen/generator/visitors/BuilderAnnotationVisitor.java index 32880ae9..929cba1a 100644 --- a/sourcegen-generator/src/main/java/io/micronaut/sourcegen/generator/visitors/BuilderAnnotationVisitor.java +++ b/sourcegen-generator/src/main/java/io/micronaut/sourcegen/generator/visitors/BuilderAnnotationVisitor.java @@ -301,13 +301,13 @@ private static void createSingularPropertyMethods(ClassDef.ClassDefBuilder class .addModifiers(Modifier.PUBLIC) .addParameter(propertyName, TypeDef.parameterized(Collection.class, singularTypeDef)) .build((self, parameterDefs) -> StatementDef.multi( - parameterDefs.get(0).asExpression().isNull().asConditionIf( + parameterDefs.get(0).isNull().asConditionIf( ClassTypeDef.of(NullPointerException.class).doThrow(ExpressionDef.constant(propertyName + " cannot be null")) ), self.field(field).isNull().asConditionIf( self.field(field).assign(ClassTypeDef.of(ArrayList.class).instantiate()) ), - self.field(field).invoke("addAll", TypeDef.primitive(boolean.class), parameterDefs.get(0).asExpression()), + self.field(field).invoke("addAll", TypeDef.primitive(boolean.class), parameterDefs.get(0)), returningExpressionProvider.apply(self) ))); classBuilder.addMethod(MethodDef.builder(singularName) @@ -317,7 +317,7 @@ private static void createSingularPropertyMethods(ClassDef.ClassDefBuilder class self.field(field).isNull().asConditionIf( self.field(field).assign(ClassTypeDef.of(ArrayList.class).instantiate()) ), - self.field(field).invoke("add", TypeDef.of(boolean.class), parameterDefs.get(0).asExpression()), + self.field(field).invoke("add", TypeDef.of(boolean.class), parameterDefs.get(0)), returningExpressionProvider.apply(self) ))); classBuilder.addMethod(MethodDef.builder("clear" + StringUtils.capitalize(propertyName)) @@ -343,7 +343,7 @@ private static void createSingularPropertyMethods(ClassDef.ClassDefBuilder class .addModifiers(Modifier.PUBLIC) .addParameter(propertyName, TypeDef.parameterized(Map.class, keyType, valueType)) .build((self, parameterDefs) -> StatementDef.multi( - parameterDefs.get(0).asExpression().isNull().asConditionIf( + parameterDefs.get(0).isNull().asConditionIf( ClassTypeDef.of(NullPointerException.class).doThrow(ExpressionDef.constant(propertyName + " cannot be null")) ), self.field(field).isNull().asConditionIf( @@ -352,7 +352,7 @@ private static void createSingularPropertyMethods(ClassDef.ClassDefBuilder class self.field(field).invoke( "addAll", TypeDef.primitive(boolean.class), - parameterDefs.get(0).asExpression().invoke("entrySet", ClassTypeDef.of(Set.class)) + parameterDefs.get(0).invoke("entrySet", ClassTypeDef.of(Set.class)) ), returningExpressionProvider.apply(self) ))); @@ -370,8 +370,8 @@ private static void createSingularPropertyMethods(ClassDef.ClassDefBuilder class ClassTypeDef.of(Map.class).invokeStatic( "entry", ClassTypeDef.of(Map.Entry.class), - parameterDefs.get(0).asExpression(), - parameterDefs.get(1).asExpression() + parameterDefs.get(0), + parameterDefs.get(1) ) ), returningExpressionProvider.apply(self) diff --git a/sourcegen-generator/src/main/java/io/micronaut/sourcegen/generator/visitors/ObjectAnnotationVisitor.java b/sourcegen-generator/src/main/java/io/micronaut/sourcegen/generator/visitors/ObjectAnnotationVisitor.java index 5bb09050..fc779664 100644 --- a/sourcegen-generator/src/main/java/io/micronaut/sourcegen/generator/visitors/ObjectAnnotationVisitor.java +++ b/sourcegen-generator/src/main/java/io/micronaut/sourcegen/generator/visitors/ObjectAnnotationVisitor.java @@ -157,8 +157,7 @@ private static void createToStringMethod(ClassDef.ClassDefBuilder classDefBuilde if (readMethod.isEmpty()) { continue; } - ExpressionDef propertyValue = parameterDef.get(0).asVariable() - .invoke(readMethod.get(), List.of()); + ExpressionDef propertyValue = parameterDef.get(0).invoke(readMethod.get()); exp = exp.invoke("append", variableDef.type(), ExpressionDef.constant(beanProperty.getName() + "=")) @@ -186,8 +185,8 @@ private static void createEqualsMethod(ClassDef.ClassDefBuilder classDefBuilder, .addParameter("instance", selfType) .addParameter("o", TypeDef.OBJECT) .build((self, parameterDef) -> { - VariableDef instance = parameterDef.get(0).asVariable(); - VariableDef o = parameterDef.get(1).asVariable(); + VariableDef instance = parameterDef.get(0); + VariableDef o = parameterDef.get(1); return StatementDef.multi( instance.asCondition(" == ", o) @@ -199,7 +198,6 @@ private static void createEqualsMethod(ClassDef.ClassDefBuilder classDefBuilder, o.cast(selfType).newLocal("other", variableDef -> { ExpressionDef exp = null; for (PropertyElement beanProperty : properties) { - TypeDef propertyTypeDef = TypeDef.of(beanProperty.getType()); if (beanProperty.hasAnnotation(EqualsAndHashCode.Exclude.class)) { continue; } @@ -207,16 +205,16 @@ private static void createEqualsMethod(ClassDef.ClassDefBuilder classDefBuilder, if (readMethod.isEmpty()) { continue; } - var firstProperty = instance.invoke(readMethod.get(), List.of()); - var secondProperty = variableDef.invoke(readMethod.get(), List.of()); + var firstProperty = instance.invoke(readMethod.get()); + var secondProperty = variableDef.invoke(readMethod.get()); ExpressionDef newEqualsExpression = firstProperty.asCondition(" == ", secondProperty); - if (!propertyTypeDef.isPrimitive()) { + if (!beanProperty.isPrimitive() || beanProperty.isArray()) { // Object.equals for objects ExpressionDef equalsMethod = firstProperty.invoke("equals", TypeDef.Primitive.BOOLEAN, secondProperty); - if (propertyTypeDef.isArray()) { + if (beanProperty.isArray()) { // Arrays.equals or Arrays.deepEquals for Array - String methodName = (((TypeDef.Array) propertyTypeDef).dimensions() > 1) ? "deepEquals" : "equals"; + String methodName = beanProperty.getArrayDimensions() > 1 ? "deepEquals" : "equals"; equalsMethod = ClassTypeDef.of(Arrays.class).invokeStatic(methodName, TypeDef.Primitive.BOOLEAN, firstProperty, secondProperty); } newEqualsExpression = newEqualsExpression @@ -246,13 +244,13 @@ private static void createHashCodeMethod(ClassDef.ClassDefBuilder classDefBuilde .addParameter("instance", selfType) .returns(TypeDef.Primitive.INT) .build((self, parameterDef) -> StatementDef.multi( - parameterDef.get(0).asExpression().isNull().asConditionIf(ExpressionDef.constant(0).returning()), - TypeDef.Primitive.INT.initialize(ExpressionDef.constant(1)).newLocal("hashValue", hashValue -> { + parameterDef.get(0).isNull().asConditionIf(ExpressionDef.constant(0).returning()), + TypeDef.Primitive.INT.initialize(1).newLocal("hashValue", hashValue -> { List hashUpdates = new ArrayList<>(); properties.stream().filter(beanProperty -> !beanProperty.hasAnnotation(EqualsAndHashCode.Exclude.class) && beanProperty.getReadMethod().isPresent()) .forEach(property -> { - ExpressionDef propertyGetter = parameterDef.get(0).asVariable() - .invoke(property.getReadMethod().get(), List.of()); + ExpressionDef propertyGetter = parameterDef.get(0) + .invoke(property.getReadMethod().get()); hashUpdates.add(hashValue.assign( hashValue.asCondition(" * ", ExpressionDef.constant(HASH_MULTIPLIER) .asCondition(" + ", getPropertyHashValue(TypeDef.of(property.getType()), propertyGetter))))); @@ -265,7 +263,7 @@ private static void createHashCodeMethod(ClassDef.ClassDefBuilder classDefBuilde classDefBuilder.addMethod(method); } - /** Calculate property hash value according to its type + /** Calculate property hash value according to its type. * * @param propertyTypeDef TypeDef of the property * @param propertyGetter the expression that gets the value of the property @@ -301,7 +299,7 @@ private static ExpressionDef getPropertyHashValue(TypeDef propertyTypeDef, Expre } else { // OBJECT propertyHashCalculation = propertyGetter.isNull().asConditionIfElse( ExpressionDef.constant(NULL_HASH_VALUE), - propertyGetter.invoke("hashCode", TypeDef.Primitive.INT, List.of()) + propertyGetter.invoke("hashCode", TypeDef.Primitive.INT) ); } return propertyHashCalculation.cast(TypeDef.Primitive.INT); diff --git a/sourcegen-generator/src/main/java/io/micronaut/sourcegen/generator/visitors/WitherAnnotationVisitor.java b/sourcegen-generator/src/main/java/io/micronaut/sourcegen/generator/visitors/WitherAnnotationVisitor.java index e3d049fa..820e17c4 100644 --- a/sourcegen-generator/src/main/java/io/micronaut/sourcegen/generator/visitors/WitherAnnotationVisitor.java +++ b/sourcegen-generator/src/main/java/io/micronaut/sourcegen/generator/visitors/WitherAnnotationVisitor.java @@ -153,7 +153,7 @@ private MethodDef createWithConsumerMethod(ClassTypeDef recordType, ClassTypeDef .addParameter("consumer", consumableType) .returns(recordType).build((self, parameterDefs) -> self.invoke(withMethod).newLocal("builder", builderVar -> - parameterDefs.get(0).asExpression().invoke("accept", TypeDef.VOID, builderVar) + parameterDefs.get(0).invoke("accept", TypeDef.VOID, builderVar) .after( builderVar.invoke("build", recordType).returning() )) @@ -187,7 +187,7 @@ private MethodDef withMethod(ClassElement recordElement, PropertyElement beanPro for (ParameterElement parameter : recordElement.getPrimaryConstructor().orElseThrow().getParameters()) { ExpressionDef exp; if (parameter.getName().equals(beanProperty.getName())) { - exp = parameterDefs.get(0).asExpression(); + exp = parameterDefs.get(0); } else { exp = self.invoke(propertyAccessMethods.get(parameter.getName())); } @@ -198,7 +198,7 @@ private MethodDef withMethod(ClassElement recordElement, PropertyElement beanPro ClassTypeDef.of(Objects.class).invokeStatic( "requireNonNull", ClassTypeDef.OBJECT, - parameterDefs.get(0).asExpression() + parameterDefs.get(0) ), recordType.instantiate(values).returning() ); diff --git a/sourcegen-model/src/main/java/io/micronaut/sourcegen/model/MethodDef.java b/sourcegen-model/src/main/java/io/micronaut/sourcegen/model/MethodDef.java index b1885e85..c397c238 100644 --- a/sourcegen-model/src/main/java/io/micronaut/sourcegen/model/MethodDef.java +++ b/sourcegen-model/src/main/java/io/micronaut/sourcegen/model/MethodDef.java @@ -186,8 +186,11 @@ public MethodDef build() { return build((self, parameterDefs) -> null); } - public MethodDef build(BiFunction, StatementDef> bodyBuilder) { - StatementDef statement = bodyBuilder.apply(new VariableDef.This(TypeDef.THIS), parameters); + public MethodDef build(BiFunction, StatementDef> bodyBuilder) { + List variables = parameters.stream() + .map(ParameterDef::asVariable) + .toList(); + StatementDef statement = bodyBuilder.apply(new VariableDef.This(TypeDef.THIS), variables); if (statement != null) { addStatement(statement); if (returnType == null && !statements.isEmpty()) { diff --git a/sourcegen-model/src/main/java/io/micronaut/sourcegen/model/ParameterDef.java b/sourcegen-model/src/main/java/io/micronaut/sourcegen/model/ParameterDef.java index f988025a..d8f10530 100644 --- a/sourcegen-model/src/main/java/io/micronaut/sourcegen/model/ParameterDef.java +++ b/sourcegen-model/src/main/java/io/micronaut/sourcegen/model/ParameterDef.java @@ -60,7 +60,7 @@ public VariableDef asExpression() { * @return Return the parameter as a variable * @since 1.2 */ - public VariableDef asVariable() { + public VariableDef.MethodParameter asVariable() { return new VariableDef.MethodParameter(name, type); } diff --git a/sourcegen-model/src/main/java/io/micronaut/sourcegen/model/TypeDef.java b/sourcegen-model/src/main/java/io/micronaut/sourcegen/model/TypeDef.java index dfdb4ada..d107ad71 100644 --- a/sourcegen-model/src/main/java/io/micronaut/sourcegen/model/TypeDef.java +++ b/sourcegen-model/src/main/java/io/micronaut/sourcegen/model/TypeDef.java @@ -87,7 +87,7 @@ default ExpressionDef instantiateArray(ExpressionDef... expressions) { * @param name The primitive type name * @return a new type definition */ - static TypeDef primitive(String name) { + static Primitive primitive(String name) { return new Primitive(name); } @@ -97,7 +97,7 @@ static TypeDef primitive(String name) { * @param type The primitive type * @return a new type definition */ - static TypeDef primitive(Class type) { + static Primitive primitive(Class type) { if (!type.isPrimitive()) { throw new IllegalStateException("Expected a primitive type got: " + type); } @@ -280,14 +280,14 @@ default TypeDef makeNullable() { @Experimental record Primitive(String name) implements TypeDef { - public static final TypeDef.Primitive INT = (Primitive) of(int.class); - public static final TypeDef.Primitive BOOLEAN = (Primitive) of(boolean.class); - public static final TypeDef.Primitive LONG = (Primitive) of(long.class); - public static final TypeDef.Primitive CHAR = (Primitive) of(char.class); - public static final TypeDef.Primitive BYTE = (Primitive) of(byte.class); - public static final TypeDef.Primitive SHORT = (Primitive) of(short.class); - public static final TypeDef.Primitive DOUBLE = (Primitive) of(double.class); - public static final TypeDef.Primitive FLOAT = (Primitive) of(float.class); + public static final TypeDef.Primitive INT = primitive(int.class); + public static final TypeDef.Primitive BOOLEAN = primitive(boolean.class); + public static final TypeDef.Primitive LONG = primitive(long.class); + public static final TypeDef.Primitive CHAR = primitive(char.class); + public static final TypeDef.Primitive BYTE = primitive(byte.class); + public static final TypeDef.Primitive SHORT = primitive(short.class); + public static final TypeDef.Primitive DOUBLE = primitive(double.class); + public static final TypeDef.Primitive FLOAT = primitive(float.class); @Override public boolean isPrimitive() { @@ -312,27 +312,27 @@ public ClassTypeDef wrapperType() { } /** - * Instantiate this class. + * The new instance expression for primitives. * - * @param value The expression giving the initial value - * @return The instantiate expression + * @param value The initial value + * @return The new instance + * @since 1.3 */ - public ExpressionDef initialize(ExpressionDef value) { - return initialize(this, value); + @Experimental + public PrimitiveInstance initialize(ExpressionDef value) { + return new PrimitiveInstance(this, value); } - /** * The new instance expression for primitives. * - * @param type The type - * @param value The initial value + * @param constant The constant * @return The new instance + * @since 1.3 */ @Experimental - public static PrimitiveInstance initialize(TypeDef type, - ExpressionDef value) { - return new PrimitiveInstance(type, value); + public PrimitiveInstance initialize(Object constant) { + return new PrimitiveInstance(this, new ExpressionDef.Constant(this, constant)); } /** @@ -344,8 +344,8 @@ public static PrimitiveInstance initialize(TypeDef type, * @since 1.3 */ @Experimental - public record PrimitiveInstance(TypeDef type, - ExpressionDef value) implements ExpressionDef { + public record PrimitiveInstance(TypeDef.Primitive type, + ExpressionDef value) implements ExpressionDef { } } diff --git a/test-suite-custom-generators/src/main/java/io/micronaut/sourcegen/custom/visitor/GenerateSwitchVisitor.java b/test-suite-custom-generators/src/main/java/io/micronaut/sourcegen/custom/visitor/GenerateSwitchVisitor.java index a265d170..d7ba48d1 100644 --- a/test-suite-custom-generators/src/main/java/io/micronaut/sourcegen/custom/visitor/GenerateSwitchVisitor.java +++ b/test-suite-custom-generators/src/main/java/io/micronaut/sourcegen/custom/visitor/GenerateSwitchVisitor.java @@ -55,7 +55,7 @@ public void visitClass(ClassElement element, VisitorContext context) { .addModifiers(Modifier.PUBLIC) .returns(resultType1) .build((self, parameterDefs) -> - parameterDefs.get(0).asExpression().asExpressionSwitch( + parameterDefs.get(0).asExpressionSwitch( resultType1, Map.of( ExpressionDef.constant("abc"), ExpressionDef.constant(1), @@ -74,7 +74,7 @@ public void visitClass(ClassElement element, VisitorContext context) { .addModifiers(Modifier.PUBLIC) .returns(resultType2) .build((self, parameterDefs) -> - parameterDefs.get(0).asExpression().asExpressionSwitch( + parameterDefs.get(0).asExpressionSwitch( resultType2, Map.of( ExpressionDef.constant("abc"), ExpressionDef.constant(TimeUnit.SECONDS), @@ -95,10 +95,10 @@ public void visitClass(ClassElement element, VisitorContext context) { .addModifiers(Modifier.PUBLIC) .returns(resultType3) .build((self, parameterDefs) -> - parameterDefs.get(0).asExpression().asExpressionSwitch( + parameterDefs.get(0).asExpressionSwitch( resultType3, Map.of( - ExpressionDef.constant("abc"), parameterDefs.get(1).asExpression().asExpressionSwitch( + ExpressionDef.constant("abc"), parameterDefs.get(1).asExpressionSwitch( resultType3, Map.of( ExpressionDef.constant(1), ExpressionDef.constant(TimeUnit.MILLISECONDS), @@ -121,7 +121,7 @@ public void visitClass(ClassElement element, VisitorContext context) { .addModifiers(Modifier.PUBLIC) .returns(resultType4) .build((self, parameterDefs) -> - parameterDefs.get(0).asExpression().asStatementSwitch( + parameterDefs.get(0).asStatementSwitch( resultType4, Map.of( ExpressionDef.constant("abc"), ExpressionDef.constant(1).returning(), @@ -140,7 +140,7 @@ public void visitClass(ClassElement element, VisitorContext context) { .addModifiers(Modifier.PUBLIC) .returns(resultType5) .build((self, parameterDefs) -> - parameterDefs.get(0).asExpression().asStatementSwitch( + parameterDefs.get(0).asStatementSwitch( resultType5, Map.of( ExpressionDef.constant("abc"), ExpressionDef.constant(TimeUnit.SECONDS).returning(), @@ -161,10 +161,10 @@ public void visitClass(ClassElement element, VisitorContext context) { .addModifiers(Modifier.PUBLIC) .returns(resultType6) .build((self, parameterDefs) -> - parameterDefs.get(0).asExpression().asStatementSwitch( + parameterDefs.get(0).asStatementSwitch( resultType6, Map.of( - ExpressionDef.constant("abc"), parameterDefs.get(1).asExpression().asStatementSwitch( + ExpressionDef.constant("abc"), parameterDefs.get(1).asStatementSwitch( resultType6, Map.of( ExpressionDef.constant(1), ExpressionDef.constant(TimeUnit.MILLISECONDS).returning(), @@ -189,10 +189,10 @@ public void visitClass(ClassElement element, VisitorContext context) { .addModifiers(Modifier.PUBLIC) .returns(resultType7) .build((self, parameterDefs) -> - parameterDefs.get(0).asExpression().asExpressionSwitch( + parameterDefs.get(0).asExpressionSwitch( resultType7, Map.of( - ExpressionDef.constant("abc"), parameterDefs.get(1).asExpression().asExpressionSwitch( + ExpressionDef.constant("abc"), parameterDefs.get(1).asExpressionSwitch( resultType7, Map.of( ExpressionDef.constant(1), ExpressionDef.constant(TimeUnit.MILLISECONDS), @@ -218,7 +218,7 @@ public void visitClass(ClassElement element, VisitorContext context) { .addModifiers(Modifier.PUBLIC) .returns(resultType8) .build((self, parameterDefs) -> - parameterDefs.get(0).asExpression().asExpressionSwitch( + parameterDefs.get(0).asExpressionSwitch( resultType8, Map.of( ExpressionDef.constant("abc"), ExpressionDef.constant(TimeUnit.SECONDS),