diff --git a/src/main/java/com/google/api/generator/gapic/composer/ResourceNameHelperClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/ResourceNameHelperClassComposer.java index 28739e3ecf..30b8f838f7 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/ResourceNameHelperClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/ResourceNameHelperClassComposer.java @@ -18,6 +18,7 @@ import com.google.api.generator.engine.ast.AnnotationNode; import com.google.api.generator.engine.ast.AssignmentExpr; import com.google.api.generator.engine.ast.AssignmentOperationExpr; +import com.google.api.generator.engine.ast.CastExpr; import com.google.api.generator.engine.ast.ClassDefinition; import com.google.api.generator.engine.ast.CommentStatement; import com.google.api.generator.engine.ast.ConcreteReference; @@ -33,6 +34,7 @@ import com.google.api.generator.engine.ast.NullObjectValue; import com.google.api.generator.engine.ast.PrimitiveValue; import com.google.api.generator.engine.ast.Reference; +import com.google.api.generator.engine.ast.RelationalOperationExpr; import com.google.api.generator.engine.ast.ReturnExpr; import com.google.api.generator.engine.ast.ScopeNode; import com.google.api.generator.engine.ast.Statement; @@ -59,6 +61,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; @@ -271,6 +274,7 @@ private static List createClassMethods( createFieldValueGetterMethods(resourceName, patternTokenVarExprs, tokenHierarchies, types)); javaMethods.add( createToStringMethod(templateFinalVarExprs, patternTokenVarExprs, tokenHierarchies)); + javaMethods.add(createEqualsMethod(resourceName, tokenHierarchies, types)); javaMethods.add(createHashCodeMethod(tokenHierarchies)); return javaMethods; } @@ -1143,6 +1147,103 @@ private static MethodDefinition createToStringMethod( .build(); } + private static MethodDefinition createEqualsMethod( + ResourceName resourceName, List> tokenHierarchies, Map types) { + // Create method definition variables. + Variable oVariable = Variable.builder().setType(TypeNode.OBJECT).setName("o").build(); + VariableExpr argVarExpr = + VariableExpr.builder().setIsDecl(false).setVariable(oVariable).build(); + TypeNode thisClassType = types.get(getThisClassName(resourceName)); + ValueExpr thisValueExpr = ValueExpr.withValue(ThisObjectValue.withType(thisClassType)); + ValueExpr trueValueExpr = + ValueExpr.withValue( + PrimitiveValue.builder().setType(TypeNode.BOOLEAN).setValue("true").build()); + + // Create first if statement's return expression + ReturnExpr returnTrueExpr = ReturnExpr.withExpr(trueValueExpr); + + // Create second if statement's condition expression + RelationalOperationExpr oEqualsThisExpr = + RelationalOperationExpr.equalToWithExprs(argVarExpr, thisValueExpr); + RelationalOperationExpr oNotEqualsNullExpr = + RelationalOperationExpr.notEqualToWithExprs( + argVarExpr, ValueExpr.withValue(NullObjectValue.create())); + MethodInvocationExpr getClassMethodInvocationExpr = + MethodInvocationExpr.builder().setMethodName("getClass").build(); + RelationalOperationExpr getClassEqualsExpr = + RelationalOperationExpr.equalToWithExprs( + getClassMethodInvocationExpr, + getClassMethodInvocationExpr.toBuilder().setExprReferenceExpr(argVarExpr).build()); + LogicalOperationExpr orLogicalExpr = + LogicalOperationExpr.logicalOrWithExprs(oNotEqualsNullExpr, getClassEqualsExpr); + + // Create second if statement's body assignment expression. + Variable thatVariable = Variable.builder().setName("that").setType(thisClassType).build(); + VariableExpr thatVariableExpr = + VariableExpr.builder().setIsDecl(false).setVariable(thatVariable).build(); + CastExpr oCastExpr = CastExpr.builder().setExpr(argVarExpr).setType(thisClassType).build(); + AssignmentExpr thatAssignmentExpr = + AssignmentExpr.builder() + .setVariableExpr(thatVariableExpr.toBuilder().setIsDecl(true).build()) + .setValueExpr(oCastExpr) + .build(); + + // Create return expression in the second if statement's body. + Set tokenSet = getTokenSet(tokenHierarchies); + Iterator itToken = tokenSet.iterator(); + Expr curTokenExpr = + createObjectsEqualsForTokenMethodEpxr( + thisValueExpr, + thatVariableExpr, + Variable.builder() + .setType(TypeNode.STRING) + .setName(JavaStyle.toLowerCamelCase(itToken.next())) + .build()); + while (itToken.hasNext()) { + Expr nextTokenExpr = + createObjectsEqualsForTokenMethodEpxr( + thisValueExpr, + thatVariableExpr, + Variable.builder() + .setType(TypeNode.STRING) + .setName(JavaStyle.toLowerCamelCase(itToken.next())) + .build()); + curTokenExpr = LogicalOperationExpr.logicalAndWithExprs(curTokenExpr, nextTokenExpr); + } + ReturnExpr secondIfReturnExpr = ReturnExpr.withExpr(curTokenExpr); + + // Code: if (o == this) { return true;} + IfStatement firstIfStatement = + IfStatement.builder() + .setConditionExpr(oEqualsThisExpr) + .setBody(Arrays.asList(ExprStatement.withExpr(returnTrueExpr))) + .build(); + // Code: if (o != null || getClass() == o.getClass()) { FoobarName that = ((FoobarName) o); + // return ..} + IfStatement secondIfStatement = + IfStatement.builder() + .setConditionExpr(orLogicalExpr) + .setBody( + Arrays.asList( + ExprStatement.withExpr(thatAssignmentExpr), + ExprStatement.withExpr(secondIfReturnExpr))) + .build(); + + // Create method's return expression. + ValueExpr falseValueExpr = + ValueExpr.withValue( + PrimitiveValue.builder().setType(TypeNode.BOOLEAN).setValue("false").build()); + + return MethodDefinition.builder() + .setIsOverride(true) + .setScope(ScopeNode.PUBLIC) + .setReturnType(TypeNode.INT) + .setName("hashCode") + .setBody(asgmtBody) + .setReturnExpr(hVarExpr) + .build(); + } + private static MethodDefinition createHashCodeMethod(List> tokenHierarchies) { List asgmtBody = new ArrayList<>(); // code: int h = 1; @@ -1190,17 +1291,22 @@ private static MethodDefinition createHashCodeMethod(List> tokenHie AssignmentOperationExpr.xorAssignmentWithExprs( hVarExpr, createObjectsHashCodeForVarMethod(tokenVarExpr)))); }); + } - return MethodDefinition.builder() - .setIsOverride(true) - .setScope(ScopeNode.PUBLIC) - .setReturnType(TypeNode.INT) - .setName("hashCode") - .setBody(asgmtBody) - .setReturnExpr(hVarExpr) + private static MethodInvocationExpr createObjectsEqualsForTokenMethodEpxr( + Expr thisExpr, Expr thatExpr, Variable tokenVar) { + VariableExpr varThisExpr = + VariableExpr.builder().setVariable(tokenVar).setExprReferenceExpr(thisExpr).build(); + VariableExpr varThatExpr = + VariableExpr.builder().setVariable(tokenVar).setExprReferenceExpr(thatExpr).build(); + return MethodInvocationExpr.builder() + .setStaticReferenceType(STATIC_TYPES.get("Objects")) + .setMethodName("equals") + .setArguments(Arrays.asList(varThisExpr, varThatExpr)) + .setReturnType(TypeNode.BOOLEAN) .build(); } - + private static MethodInvocationExpr createObjectsHashCodeForVarMethod(VariableExpr varExpr) { // code: Objects.hashCode(varExpr) return MethodInvocationExpr.builder() @@ -1208,6 +1314,11 @@ private static MethodInvocationExpr createObjectsHashCodeForVarMethod(VariableEx .setStaticReferenceType(STATIC_TYPES.get("Objects")) .setArguments(varExpr) .setReturnType(TypeNode.INT) + .setArguments(argVarExpr.toBuilder().setIsDecl(true).build()) + .setReturnType(TypeNode.BOOLEAN) + .setName("equals") + .setReturnExpr(falseValueExpr) + .setBody(Arrays.asList(firstIfStatement, secondIfStatement)) .build(); } diff --git a/src/test/java/com/google/api/generator/gapic/composer/goldens/FoobarName.golden b/src/test/java/com/google/api/generator/gapic/composer/goldens/FoobarName.golden index dc6ec7ee84..57acf0e8a1 100644 --- a/src/test/java/com/google/api/generator/gapic/composer/goldens/FoobarName.golden +++ b/src/test/java/com/google/api/generator/gapic/composer/goldens/FoobarName.golden @@ -264,6 +264,21 @@ public class FoobarName implements ResourceName { h ^= Objects.hashCode(barFoo); return h; } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (o != null || getClass() == o.getClass()) { + FoobarName that = ((FoobarName) o); + return Objects.equals(this.project, that.project) + && Objects.equals(this.foobar, that.foobar) + && Objects.equals(this.variant, that.variant) + && Objects.equals(this.barFoo, that.barFoo); + } + return false; + } /** Builder for projects/{project}/foobars/{foobar}. */ public static class Builder { diff --git a/src/test/java/com/google/api/generator/gapic/composer/goldens/SessionName.golden b/src/test/java/com/google/api/generator/gapic/composer/goldens/SessionName.golden index 11636587bf..0c37e2e2ee 100644 --- a/src/test/java/com/google/api/generator/gapic/composer/goldens/SessionName.golden +++ b/src/test/java/com/google/api/generator/gapic/composer/goldens/SessionName.golden @@ -108,6 +108,18 @@ public class SessionName implements ResourceName { h ^= Objects.hashCode(session); return h; } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (o != null || getClass() == o.getClass()) { + SessionName that = ((SessionName) o); + return Objects.equals(this.session, that.session); + } + return false; + } /** Builder for sessions/{session}. */ public static class Builder {