diff --git a/README.md b/README.md index 313c37c7..0cb45f91 100644 --- a/README.md +++ b/README.md @@ -54,3 +54,28 @@ Annotate Preconditions error messages with named `SafeArg` and `UnsafeArg` as ap Preconditions.checkArgument(uname.size() > MAX_LEN, "username longer than max", UnsafeArg.of("uname", uname), SafeArg.of("max", MAX_LEN)); + +Iterables +============= +Guava Iterables equivalent which produces exceptions conforming to the SafeLoggable standard +(using the above Preconditions) + +Usage +----- + +Add dependency to gradle: + + compile "com.palantir.safe-logging:iterables" + +Example: + + // previously + import com.google.common.collect.Iterators; + ... + Preconditions.checkState(collection.size() == 1, "Expected exactly one element in collection", args); + return Iterables.getOnlyElement(collection); + + // now + import com.palantir.logsafe.Iterables; + ... + Iterables.getOnlyElement(collection, args); diff --git a/changelog/@unreleased/pr-520.v2.yml b/changelog/@unreleased/pr-520.v2.yml new file mode 100644 index 00000000..2f9441a1 --- /dev/null +++ b/changelog/@unreleased/pr-520.v2.yml @@ -0,0 +1,5 @@ +type: improvement +improvement: + description: Add iterables package containing helper method for getting the only element in a collection + links: + - https://github.com/palantir/safe-logging/pull/520 diff --git a/iterables/build.gradle b/iterables/build.gradle new file mode 100644 index 00000000..1fb857b8 --- /dev/null +++ b/iterables/build.gradle @@ -0,0 +1,12 @@ +apply from: "${rootDir}/gradle/publish-jar.gradle" +apply plugin: 'com.palantir.revapi' + +dependencies { + api project(':safe-logging') + api project(':preconditions') + compileOnly 'com.google.code.findbugs:jsr305' + compile group: 'com.google.guava', name: 'guava' + + testImplementation 'junit:junit' + testImplementation 'org.assertj:assertj-core' +} diff --git a/iterables/src/main/java/com/palantir/logsafe/Iterables.java b/iterables/src/main/java/com/palantir/logsafe/Iterables.java new file mode 100755 index 00000000..eff6858a --- /dev/null +++ b/iterables/src/main/java/com/palantir/logsafe/Iterables.java @@ -0,0 +1,45 @@ +/* + * (c) Copyright 2018 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. + */ + +/* + * Copyright (C) 2007 The Guava Authors + * + * 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 com.google.common.base.Preconditions; +import com.google.common.collect.Iterators; +import java.util.Collection; + +public final class Iterables { + public static final String DEFAULT_ERROR_MESSAGE = "Expected exactly one element in collection"; + + private Iterables() {} + + public static > T getOnlyElement(C collection, Arg... args) { + Preconditions.checkState(collection.size() == 1, DEFAULT_ERROR_MESSAGE, args); + return Iterators.getOnlyElement(collection.iterator()); + } +} diff --git a/iterables/src/test/java/com/palantir/logsafe/IterablesTest.java b/iterables/src/test/java/com/palantir/logsafe/IterablesTest.java new file mode 100644 index 00000000..afca3e3c --- /dev/null +++ b/iterables/src/test/java/com/palantir/logsafe/IterablesTest.java @@ -0,0 +1,47 @@ +/* + * (c) Copyright 2021 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 static org.assertj.core.api.Assertions.assertThatThrownBy; + +import com.google.common.collect.ImmutableSet; +import org.junit.Test; + +public class IterablesTest { + @Test + public void getOnlyElementReturnsElement() { + String element = "element"; + assertThat(Iterables.getOnlyElement(ImmutableSet.of(element))).isEqualTo(element); + } + + @Test + public void getOnlyElementThrowsIfMoreThanOneElement() { + String element1 = "element1"; + String element2 = "element2"; + assertThatThrownBy(() -> Iterables.getOnlyElement(ImmutableSet.of(element1, element2))) + .isInstanceOf(IllegalStateException.class) + .hasMessageContaining(Iterables.DEFAULT_ERROR_MESSAGE); + } + + @Test + public void getOnlyElementThrowsIfEmpty() { + assertThatThrownBy(() -> Iterables.getOnlyElement(ImmutableSet.of())) + .isInstanceOf(IllegalStateException.class) + .hasMessageContaining(Iterables.DEFAULT_ERROR_MESSAGE); + } +} diff --git a/settings.gradle b/settings.gradle index 37098e47..f975b057 100644 --- a/settings.gradle +++ b/settings.gradle @@ -4,4 +4,5 @@ include 'safe-logging' include 'safe-logging-refactorings' include 'preconditions' include 'preconditions-assertj' +include 'iterables' diff --git a/versions.lock b/versions.lock index 137b1f5d..1cabf831 100644 --- a/versions.lock +++ b/versions.lock @@ -1,6 +1,12 @@ # Run ./gradlew --write-locks to regenerate this file com.google.code.findbugs:jsr305:3.0.2 (4 constraints: e932ae18) com.google.errorprone:error_prone_annotations:2.3.3 (4 constraints: f532671c) +com.google.guava:failureaccess:1.0.1 (1 constraints: 140ae1b4) +com.google.guava:guava:27.0.1-jre (4 constraints: 613b78c4) +com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava (1 constraints: bd17c918) +com.google.j2objc:j2objc-annotations:1.1 (1 constraints: b609eba0) +org.checkerframework:checker-qual:2.5.3 (4 constraints: 202a1965) +org.codehaus.mojo:animal-sniffer-annotations:1.17 (1 constraints: ed09d8aa) [Test dependencies] com.github.kevinstern:software-and-algorithms:1.0 (1 constraints: 7e12fcf5) @@ -13,17 +19,11 @@ com.google.errorprone:error_prone_core:2.3.3 (1 constraints: a8121509) com.google.errorprone:error_prone_refaster:2.3.3 (1 constraints: 0a050136) com.google.errorprone:error_prone_type_annotations:2.3.3 (1 constraints: f51029b8) com.google.errorprone:javac:9+181-r4173-1 (3 constraints: 003cc23b) -com.google.guava:failureaccess:1.0.1 (1 constraints: 140ae1b4) -com.google.guava:guava:27.0.1-jre (4 constraints: 613b78c4) -com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava (1 constraints: bd17c918) -com.google.j2objc:j2objc-annotations:1.1 (1 constraints: b609eba0) com.google.protobuf:protobuf-java:3.4.0 (1 constraints: f4102eb8) com.googlecode.java-diff-utils:diffutils:1.3.0 (1 constraints: df129c1b) junit:junit:4.13 (1 constraints: dc040031) org.assertj:assertj-core:3.17.0 (1 constraints: 3d054a3b) -org.checkerframework:checker-qual:2.5.3 (4 constraints: 202a1965) org.checkerframework:dataflow:2.5.3 (2 constraints: db23f14b) org.checkerframework:javacutil:2.5.3 (1 constraints: 470d3a1d) -org.codehaus.mojo:animal-sniffer-annotations:1.17 (1 constraints: ed09d8aa) org.hamcrest:hamcrest-core:1.3 (1 constraints: cc05fe3f) org.pcollections:pcollections:2.1.2 (1 constraints: f21022b8)