diff --git a/changelog/@unreleased/pr-954.v2.yml b/changelog/@unreleased/pr-954.v2.yml new file mode 100644 index 00000000..9fe1096a --- /dev/null +++ b/changelog/@unreleased/pr-954.v2.yml @@ -0,0 +1,5 @@ +type: improvement +improvement: + description: Arg#hashCode does not allocate + links: + - https://github.com/palantir/safe-logging/pull/954 diff --git a/safe-logging/build.gradle b/safe-logging/build.gradle index e58fc36c..02ef4a34 100644 --- a/safe-logging/build.gradle +++ b/safe-logging/build.gradle @@ -4,3 +4,10 @@ apply plugin: 'com.palantir.revapi' tasks.withType(JavaCompile) { options.errorprone.disable 'PreferSafeLoggingPreconditions' } + +dependencies { + compileOnly 'com.google.code.findbugs:jsr305' + + testImplementation 'junit:junit' + testImplementation 'org.assertj:assertj-core' +} diff --git a/safe-logging/src/main/java/com/palantir/logsafe/Arg.java b/safe-logging/src/main/java/com/palantir/logsafe/Arg.java index 83175a4a..9a7db5e9 100644 --- a/safe-logging/src/main/java/com/palantir/logsafe/Arg.java +++ b/safe-logging/src/main/java/com/palantir/logsafe/Arg.java @@ -70,6 +70,10 @@ public final boolean equals(Object other) { @Override public final int hashCode() { - return Objects.hash(name, value); + int result = 1; + result = 31 * result + name.hashCode(); + result = 31 * result + Objects.hashCode(value); + result = 31 * result + Boolean.hashCode(isSafeForLogging()); + return result; } } diff --git a/safe-logging/src/test/java/com/palantir/logsafe/ArgTest.java b/safe-logging/src/test/java/com/palantir/logsafe/ArgTest.java new file mode 100644 index 00000000..30294199 --- /dev/null +++ b/safe-logging/src/test/java/com/palantir/logsafe/ArgTest.java @@ -0,0 +1,49 @@ +/* + * (c) Copyright 2024 Palantir Technologies Inc. All rights reserved. + * + * 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 com.palantir.logsafe; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Map; +import org.junit.Test; + +public class ArgTest { + + @Test + @SuppressWarnings({"EqualsWithItself", "AssertBetweenInconvertibleTypes"}) // testing equals + public void testSafeVersusUnsafe() { + SafeArg safeArg = SafeArg.of("test", "value"); + SafeArg safeArg2 = SafeArg.of("test", "value"); + UnsafeArg unsafeArg = UnsafeArg.of("test", "value"); + + assertThat(safeArg.getName()).isEqualTo(unsafeArg.getName()); + assertThat(safeArg.getValue()).isEqualTo(unsafeArg.getValue()); + assertThat(safeArg.isSafeForLogging()).isTrue(); + assertThat(safeArg2.isSafeForLogging()).isTrue(); + assertThat(unsafeArg.isSafeForLogging()).isFalse(); + assertThat(safeArg) + .isEqualTo(safeArg2) + .isEqualTo(safeArg) + .hasSameHashCodeAs(safeArg2) + .hasToString(safeArg2.toString()) + .isNotEqualTo(Map.of("test", "value")); + assertThat(safeArg2).isEqualTo(safeArg).isEqualTo(safeArg2).isNotEqualTo(Map.of("test", "value")); + assertThat(unsafeArg).isNotEqualTo(safeArg).isNotEqualTo(safeArg2).isNotEqualTo(Map.of("test", "value")); + assertThat(safeArg).isNotEqualTo(unsafeArg).doesNotHaveSameHashCodeAs(unsafeArg); + assertThat(safeArg).hasToString("value").hasToString(unsafeArg.toString()); + } +}