Skip to content

Commit

Permalink
Improve build method API + small improvements (#151)
Browse files Browse the repository at this point in the history
  • Loading branch information
dstepanov authored Oct 2, 2024
1 parent 7f95f19 commit ab3251b
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 63 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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))
Expand All @@ -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(
Expand All @@ -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)
)));
Expand All @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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() + "="))
Expand Down Expand Up @@ -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)
Expand All @@ -199,24 +198,23 @@ 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;
}
Optional<MethodElement> readMethod = beanProperty.getReadMethod();
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
Expand Down Expand Up @@ -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<StatementDef> 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)))));
Expand All @@ -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
Expand Down Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
))
Expand Down Expand Up @@ -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()));
}
Expand All @@ -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()
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,8 +186,11 @@ public MethodDef build() {
return build((self, parameterDefs) -> null);
}

public MethodDef build(BiFunction<VariableDef.This, List<ParameterDef>, StatementDef> bodyBuilder) {
StatementDef statement = bodyBuilder.apply(new VariableDef.This(TypeDef.THIS), parameters);
public MethodDef build(BiFunction<VariableDef.This, List<VariableDef.MethodParameter>, StatementDef> bodyBuilder) {
List<VariableDef.MethodParameter> 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()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand All @@ -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);
}
Expand Down Expand Up @@ -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() {
Expand All @@ -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));
}

/**
Expand All @@ -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 {
}
}

Expand Down
Loading

0 comments on commit ab3251b

Please sign in to comment.