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 2ae659617b..5594ffb16a 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 @@ -17,6 +17,7 @@ import com.google.api.core.BetaApi; 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; @@ -274,6 +275,7 @@ private static List createClassMethods( javaMethods.add( createToStringMethod(templateFinalVarExprs, patternTokenVarExprs, tokenHierarchies)); javaMethods.add(createEqualsMethod(resourceName, tokenHierarchies, types)); + javaMethods.add(createHashCodeMethod(tokenHierarchies)); return javaMethods; } @@ -1257,6 +1259,74 @@ private static MethodInvocationExpr createObjectsEqualsForTokenMethodEpxr( .build(); } + private static MethodDefinition createHashCodeMethod(List> tokenHierarchies) { + List asgmtBody = new ArrayList<>(); + // code: int h = 1; + Variable hVar = Variable.builder().setType(TypeNode.INT).setName("h").build(); + VariableExpr hVarExpr = VariableExpr.builder().setVariable(hVar).build(); + ValueExpr hValueExpr = + ValueExpr.withValue(PrimitiveValue.builder().setType(TypeNode.INT).setValue("1").build()); + AssignmentExpr hAssignmentExpr = + AssignmentExpr.builder() + .setVariableExpr(hVarExpr.toBuilder().setIsDecl(true).build()) + .setValueExpr(hValueExpr) + .build(); + asgmtBody.add(ExprStatement.withExpr(hAssignmentExpr)); + // code: h *= 1000003; + // code: h ^= Objects.hashCode(...); + ValueExpr numValueExpr = + ValueExpr.withValue( + PrimitiveValue.builder().setType(TypeNode.INT).setValue("1000003").build()); + AssignmentOperationExpr multiplyAsgmtOpExpr = + AssignmentOperationExpr.multiplyAssignmentWithExprs(hVarExpr, numValueExpr); + // If it has variants, add the multiply and xor assignment operation exprs for fixedValue. + boolean hasVariants = tokenHierarchies.size() > 1; + if (hasVariants) { + VariableExpr fixedValueVarExpr = FIXED_CLASS_VARS.get("fixedValue"); + asgmtBody.add(ExprStatement.withExpr(multiplyAsgmtOpExpr)); + asgmtBody.add( + ExprStatement.withExpr( + AssignmentOperationExpr.xorAssignmentWithExprs( + hVarExpr, createObjectsHashCodeForVarMethod(fixedValueVarExpr)))); + } + // Add the multiply and xor assignment operation exprs for tokens. + Set tokenSet = getTokenSet(tokenHierarchies); + tokenSet.stream() + .forEach( + token -> { + VariableExpr tokenVarExpr = + VariableExpr.withVariable( + Variable.builder() + .setName(JavaStyle.toLowerCamelCase(token)) + .setType(TypeNode.STRING) + .build()); + asgmtBody.add(ExprStatement.withExpr(multiplyAsgmtOpExpr)); + asgmtBody.add( + ExprStatement.withExpr( + AssignmentOperationExpr.xorAssignmentWithExprs( + hVarExpr, createObjectsHashCodeForVarMethod(tokenVarExpr)))); + }); + + return MethodDefinition.builder() + .setIsOverride(true) + .setScope(ScopeNode.PUBLIC) + .setReturnType(TypeNode.INT) + .setName("hashCode") + .setBody(asgmtBody) + .setReturnExpr(hVarExpr) + .build(); + } + + private static MethodInvocationExpr createObjectsHashCodeForVarMethod(VariableExpr varExpr) { + // code: Objects.hashCode(varExpr) + return MethodInvocationExpr.builder() + .setMethodName("hashCode") + .setStaticReferenceType(STATIC_TYPES.get("Objects")) + .setArguments(varExpr) + .setReturnType(TypeNode.INT) + .build(); + } + private static List createNestedBuilderClasses( ResourceName resourceName, List> tokenHierarchies, 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 ac8d8995d2..565f997703 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,22 @@ public class FoobarName implements ResourceName { return false; } + @Override + public int hashCode() { + int h = 1; + h *= 1000003; + h ^= Objects.hashCode(fixedValue); + h *= 1000003; + h ^= Objects.hashCode(project); + h *= 1000003; + h ^= Objects.hashCode(foobar); + h *= 1000003; + h ^= Objects.hashCode(variant); + h *= 1000003; + h ^= Objects.hashCode(barFoo); + return h; + } + /** Builder for projects/{project}/foobars/{foobar}. */ public static class Builder { private String project; 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 58e15add60..b17c2718c1 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 @@ -113,6 +113,14 @@ public class SessionName implements ResourceName { return false; } + @Override + public int hashCode() { + int h = 1; + h *= 1000003; + h ^= Objects.hashCode(session); + return h; + } + /** Builder for sessions/{session}. */ public static class Builder { private String session;