Skip to content

Commit

Permalink
Merge pull request #181 from JakeWharton/jakew/multibinding-annotatio…
Browse files Browse the repository at this point in the history
…n/2019-11-19

Add support for @Multibinds annotation
  • Loading branch information
JakeWharton committed Dec 7, 2019
2 parents 71dc297 + 6e65bc5 commit 5cbb51d
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 0 deletions.
@@ -0,0 +1,17 @@
package com.example;

import dagger.Component;
import dagger.Module;
import dagger.multibindings.Multibinds;
import java.util.Map;

@Component(modules = MultibindingMapEmpty.Module1.class)
interface MultibindingMapEmpty {
Map<String, String> values();

@Module
abstract class Module1 {
@Multibinds
abstract Map<String, String> empty();
}
}
@@ -0,0 +1,17 @@
package com.example;

import dagger.Component;
import dagger.Module;
import dagger.multibindings.Multibinds;
import java.util.Set;

@Component(modules = MultibindingSetEmpty.Module1.class)
interface MultibindingSetEmpty {
Set<String> values();

@Module
abstract class Module1 {
@Multibinds
abstract Set<String> empty();
}
}
25 changes: 25 additions & 0 deletions integration-tests/src/test/java/com/example/IntegrationTest.java
Expand Up @@ -841,6 +841,12 @@ public void multibindingSet() {
assertThat(component.values()).containsExactly("one", "two");
}

@Test
public void multibindingSetEmpty() {
MultibindingSetEmpty component = backend.create(MultibindingSetEmpty.class);
assertThat(component.values()).isEmpty();
}

@Test
public void multibindingSetElements() {
MultibindingSetElements component = backend.create(MultibindingSetElements.class);
Expand Down Expand Up @@ -879,6 +885,12 @@ public void multibindingMap() {
assertThat(component.values()).containsExactly("1", "one", "2", "two");
}

@Test
public void multibindingMapEmpty() {
MultibindingMapEmpty component = backend.create(MultibindingMapEmpty.class);
assertThat(component.values()).isEmpty();
}

@Test
public void multibindingMapClassKey() {
MultibindingMapClassKey c = backend.create(MultibindingMapClassKey.class);
Expand Down Expand Up @@ -934,6 +946,19 @@ public void multibindingMapProvider() {
assertThat(values.get("1").get()).isEqualTo("one");
}

@Test
@IgnoreCodegen
public void multibindsAnnotationWrongType() {
try {
backend.create(MultibindsAnnotationWrongType.class);
fail();
} catch (IllegalStateException e) {
assertThat(e)
.hasMessageThat()
.isEqualTo("@Multibinds return type must be Set or Map: class java.lang.String");
}
}

@Test
public void moduleClass() {
ModuleClass component = backend.create(ModuleClass.class);
Expand Down
@@ -0,0 +1,14 @@
package com.example;

import dagger.Component;
import dagger.Module;
import dagger.multibindings.Multibinds;

@Component(modules = MultibindsAnnotationWrongType.Module1.class)
interface MultibindsAnnotationWrongType {
@Module
abstract class Module1 {
@Multibinds
abstract String empty();
}
}
11 changes: 11 additions & 0 deletions reflect/src/main/java/dagger/reflect/ReflectiveModuleParser.java
Expand Up @@ -18,6 +18,7 @@
import dagger.multibindings.ElementsIntoSet;
import dagger.multibindings.IntoMap;
import dagger.multibindings.IntoSet;
import dagger.multibindings.Multibinds;
import dagger.reflect.TypeUtil.ParameterizedTypeImpl;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
Expand Down Expand Up @@ -63,6 +64,16 @@ static void parse(Class<?> moduleClass, @Nullable Object instance, Scope.Builder
addBinding(scopeBuilder, key, binding, annotations);
} catch (NoClassDefFoundError ignored) {
}
} else if (method.getAnnotation(Multibinds.class) != null) {
Key key = Key.of(qualifier, returnType);
if (method.getReturnType() == Set.class) {
scopeBuilder.createSetBinding(key);
} else if (method.getReturnType() == Map.class) {
scopeBuilder.createMapBinding(key);
} else {
throw new IllegalStateException(
"@Multibinds return type must be Set or Map: " + returnType);
}
} else {
ContributesAndroidInjector contributesAndroidInjector =
method.getAnnotation(ContributesAndroidInjector.class);
Expand Down
38 changes: 38 additions & 0 deletions reflect/src/main/java/dagger/reflect/Scope.java
Expand Up @@ -215,6 +215,25 @@ Builder addBinding(Key key, Binding binding) {
return this;
}

/**
* Create an empty set binding specified by {@code key} if it does not already exist.
*
* @param key The key defining the set. The raw class of the {@linkplain Key#type() type} must
* be {@link Set Set.class}.
*/
Builder createSetBinding(Key key) {
if (key == null) throw new NullPointerException("key == null");
if (Types.getRawType(key.type()) != Set.class) {
throw new IllegalArgumentException("key.type() must be Set");
}

if (!keyToSetBindings.containsKey(key)) {
keyToSetBindings.put(key, new SetBindings());
}

return this;
}

/**
* Adds a new element into the set specified by {@code key}.
*
Expand Down Expand Up @@ -268,6 +287,25 @@ Builder addBindingElementsIntoSet(Key key, Binding elementsBinding) {
return this;
}

/**
* Create an empty map binding specified by {@code key} if it does not already exist.
*
* @param key The key defining the set. The raw class of the {@linkplain Key#type() type} must
* be {@link Map Map.class}.
*/
Builder createMapBinding(Key key) {
if (key == null) throw new NullPointerException("key == null");
if (Types.getRawType(key.type()) != Map.class) {
throw new IllegalArgumentException("key.type() must be Map");
}

if (!keyToMapBindings.containsKey(key)) {
keyToMapBindings.put(key, new LinkedHashMap<>());
}

return this;
}

/**
* Adds a new entry into the map specified by {@code key}.
*
Expand Down

0 comments on commit 5cbb51d

Please sign in to comment.