diff --git a/moshi/src/main/java/com/squareup/moshi/Types.java b/moshi/src/main/java/com/squareup/moshi/Types.java index 6dd5204..fa8e309 100644 --- a/moshi/src/main/java/com/squareup/moshi/Types.java +++ b/moshi/src/main/java/com/squareup/moshi/Types.java @@ -28,9 +28,12 @@ import java.lang.reflect.TypeVariable; import java.lang.reflect.WildcardType; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashSet; import java.util.Map; import java.util.NoSuchElementException; import java.util.Properties; +import java.util.Set; /** Factory methods for types. */ public final class Types { @@ -39,6 +42,29 @@ public final class Types { private Types() { } + /** + * Checks if {@code annotations} contains {@code jsonQualifier}. + * Returns the subset of {@code annotations} without {@code jsonQualifier}, or null if {@code + * annotations} does not contain {@code jsonQualifier}. + */ + public static Set nextAnnotations(Set annotations, + Class jsonQualifier) { + if (!jsonQualifier.isAnnotationPresent(JsonQualifier.class)) { + throw new IllegalArgumentException(jsonQualifier + " is not a JsonQualifier."); + } + if (annotations.isEmpty()) { + return null; + } + for (Annotation annotation : annotations) { + if (jsonQualifier.equals(annotation.annotationType())) { + Set delegateAnnotations = new LinkedHashSet<>(annotations); + delegateAnnotations.remove(annotation); + return Collections.unmodifiableSet(delegateAnnotations); + } + } + return null; + } + /** * Returns a new parameterized type, applying {@code typeArguments} to {@code rawType}. Use this * method if {@code rawType} is not enclosed in another type. diff --git a/moshi/src/test/java/com/squareup/moshi/TypesTest.java b/moshi/src/test/java/com/squareup/moshi/TypesTest.java index 6abc281..199680a 100644 --- a/moshi/src/test/java/com/squareup/moshi/TypesTest.java +++ b/moshi/src/test/java/com/squareup/moshi/TypesTest.java @@ -15,13 +15,17 @@ */ package com.squareup.moshi; +import java.lang.annotation.Annotation; import java.lang.annotation.Retention; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Properties; +import java.util.Set; import org.junit.Test; import static java.lang.annotation.RetentionPolicy.RUNTIME; @@ -29,6 +33,44 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.fail; public final class TypesTest { + @Retention(RUNTIME) @JsonQualifier @interface TestQualifier { + } + + @Retention(RUNTIME) @JsonQualifier @interface AnotherTestQualifier { + } + + @Retention(RUNTIME) @interface TestAnnotation { + } + + @TestQualifier private Object hasTestQualifier; + + @Test public void nextAnnotationsRequiresJsonAnnotation() throws Exception { + try { + Types.nextAnnotations(Collections.emptySet(), TestAnnotation.class); + fail(); + } catch (IllegalArgumentException expected) { + assertThat(expected).hasMessage( + "interface com.squareup.moshi.TypesTest$TestAnnotation is not a JsonQualifier."); + } + } + + @Test public void nextAnnotationsDoesNotContainReturnsNull() throws Exception { + Set annotations = + Collections.singleton(Types.createJsonQualifierImplementation(AnotherTestQualifier.class)); + assertThat(Types.nextAnnotations(annotations, TestQualifier.class)).isNull(); + assertThat( + Types.nextAnnotations(Collections.emptySet(), TestQualifier.class)).isNull(); + } + + @Test public void nextAnnotationsReturnsDelegateAnnotations() throws Exception { + Set annotations = new LinkedHashSet<>(2); + annotations.add(Types.createJsonQualifierImplementation(TestQualifier.class)); + annotations.add(Types.createJsonQualifierImplementation(AnotherTestQualifier.class)); + Set expected = + Collections.singleton(Types.createJsonQualifierImplementation(AnotherTestQualifier.class)); + assertThat(Types.nextAnnotations(Collections.unmodifiableSet(annotations), TestQualifier.class)) + .isEqualTo(expected); + } @Test public void newParameterizedType() throws Exception { // List. List is a top-level class. @@ -170,16 +212,11 @@ public final class TypesTest { @Test public void createJsonQualifierImplementation() throws Exception { TestQualifier actual = Types.createJsonQualifierImplementation(TestQualifier.class); TestQualifier expected = - (TestQualifier) TypesTest.class.getDeclaredField("unused").getAnnotations()[0]; + (TestQualifier) TypesTest.class.getDeclaredField("hasTestQualifier").getAnnotations()[0]; assertThat(actual.annotationType()).isEqualTo(TestQualifier.class); assertThat(actual).isEqualTo(expected); assertThat(actual).isNotEqualTo(null); assertThat(actual.hashCode()).isEqualTo(expected.hashCode()); assertThat(actual.getClass()).isNotEqualTo(TestQualifier.class); } - - @TestQualifier private static Object unused; - - @Retention(RUNTIME) @JsonQualifier @interface TestQualifier { - } }