alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (MapBinderTest.java)

This example Java source code file (MapBinderTest.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

abstractmodule, annotation, binding, both, injector, integer, key, mapbinder, override, provider, reflection, set, string, typeliteral, util, valuetype

The MapBinderTest.java Java example source code

/**
 * Copyright (C) 2008 Google Inc.
 *
 * 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.google.inject.multibindings;

import static com.google.inject.Asserts.asModuleChain;
import static com.google.inject.Asserts.assertContains;
import static com.google.inject.multibindings.SpiUtils.VisitType.BOTH;
import static com.google.inject.multibindings.SpiUtils.VisitType.MODULE;
import static com.google.inject.multibindings.SpiUtils.assertMapVisitor;
import static com.google.inject.multibindings.SpiUtils.instance;
import static com.google.inject.multibindings.SpiUtils.providerInstance;
import static com.google.inject.name.Names.named;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import com.google.common.base.Function;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.inject.AbstractModule;
import com.google.inject.Asserts;
import com.google.inject.Binding;
import com.google.inject.BindingAnnotation;
import com.google.inject.ConfigurationException;
import com.google.inject.CreationException;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Module;
import com.google.inject.Provider;
import com.google.inject.Provides;
import com.google.inject.ProvisionException;
import com.google.inject.Stage;
import com.google.inject.TypeLiteral;
import com.google.inject.internal.WeakKeySetUtils;
import com.google.inject.name.Names;
import com.google.inject.spi.Dependency;
import com.google.inject.spi.HasDependencies;
import com.google.inject.spi.InstanceBinding;
import com.google.inject.util.Modules;
import com.google.inject.util.Providers;
import com.google.inject.util.Types;

import junit.framework.TestCase;

import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.ref.WeakReference;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @author dpb@google.com (David P. Baker)
 */
public class MapBinderTest extends TestCase {

  private static final Set<Key FRAMEWORK_KEYS = ImmutableSet.of(
      Key.get(java.util.logging.Logger.class),
      Key.get(Stage.class),
      Key.get(Injector.class)
  );

  final TypeLiteral<Map> mapOfStringJavaxProvider =
      new TypeLiteral<Map>() {};
  final TypeLiteral<Map> mapOfStringProvider =
      new TypeLiteral<Map>() {}; 
  final TypeLiteral<Map mapOfString = new TypeLiteral>() {};
  final TypeLiteral<Map mapOfIntString =
      new TypeLiteral<Map() {};
  final TypeLiteral<Map mapOfInteger = new TypeLiteral>() {};
  final TypeLiteral<Map> mapOfSetOfString =
      new TypeLiteral<Map>() {};
      
  private final TypeLiteral<String> stringType = TypeLiteral.get(String.class);
  private final TypeLiteral<Integer> intType = TypeLiteral.get(Integer.class);

  private Type javaxProviderOf(Type type) {
    return Types.javaxProviderOf(type);
  }

  private Type mapEntryOf(Type keyType, Type valueType) {
    return Types.newParameterizedTypeWithOwner(Map.class, Map.Entry.class, keyType, valueType);
  }

  private Type collectionOf(Type type) {
    return Types.newParameterizedType(Collection.class, type);
  }

  public void testAllBindings() {
    Module module = new AbstractModule() {
      @Override
      protected void configure() {
        MapBinder.newMapBinder(binder(), String.class, String.class).permitDuplicates();
      }
    };

    Injector injector = Guice.createInjector(module);

    Map<Key> bindings = injector.getBindings();

    ImmutableSet<Key expectedBindings = ImmutableSet.>builder()
        .add(
            // Map<K, V>
            Key.get(Types.mapOf(String.class, String.class)),
            // Map<K, Provider
            Key.get(Types.mapOf(String.class, Types.providerOf(String.class))),
            // Map<K, javax.inject.Provider
            Key.get(Types.mapOf(String.class, javaxProviderOf(String.class))),
            // Map<K, Set
            Key.get(Types.mapOf(String.class, Types.setOf(String.class))),
            // Map<K, Set
            Key.get(Types.mapOf(String.class, Types.setOf(Types.providerOf(String.class)))),
            // Map<K, Set
            Key.get(Types.mapOf(String.class, Types.setOf(Types.javaxProviderOf(String.class)))),
            // Map<K, Collection
            Key.get(Types.mapOf(String.class, Types.collectionOf(Types.providerOf(String.class)))),
            // Map<K, Collection
            Key.get(Types.mapOf(String.class, 
                Types.collectionOf(Types.javaxProviderOf(String.class)))),
            // Set<Map.Entry>
            Key.get(Types.setOf(mapEntryOf(String.class, Types.providerOf(String.class)))),
            // Set<Map.Entry>
            Key.get(Types.setOf(mapEntryOf(String.class, Types.javaxProviderOf(String.class)))),
            // Collection<Provider>>
            Key.get(collectionOf(Types.providerOf(
                mapEntryOf(String.class, Types.providerOf(String.class))))),
            // Collection<javax.inject.Provider>>
            Key.get(collectionOf(Types.javaxProviderOf(
                mapEntryOf(String.class, Types.providerOf(String.class))))),
            // @Named(...) Boolean
            Key.get(Boolean.class,
                named("Multibinder<java.util.Map$Entry> permits duplicates"))
        )
        .addAll(FRAMEWORK_KEYS).build();

    Set<Key missingBindings = Sets.difference(expectedBindings, bindings.keySet());
    Set<Key extraBindings = Sets.difference(bindings.keySet(), expectedBindings);

    assertTrue("There should be no missing bindings. Missing: " + missingBindings,
        missingBindings.isEmpty());
    assertTrue("There should be no extra bindings. Extra: " + extraBindings,
        extraBindings.isEmpty());
  }

  public void testMapBinderAggregatesMultipleModules() {
    Module abc = new AbstractModule() {
      @Override protected void configure() {
        MapBinder<String, String> multibinder = MapBinder.newMapBinder(
            binder(), String.class, String.class);
        multibinder.addBinding("a").toInstance("A");
        multibinder.addBinding("b").toInstance("B");
        multibinder.addBinding("c").toInstance("C");
      }
    };
    Module de = new AbstractModule() {
      @Override protected void configure() {
        MapBinder<String, String> multibinder = MapBinder.newMapBinder(
            binder(), String.class, String.class);
        multibinder.addBinding("d").toInstance("D");
        multibinder.addBinding("e").toInstance("E");
      }
    };

    Injector injector = Guice.createInjector(abc, de);
    Map<String, String> abcde = injector.getInstance(Key.get(mapOfString));

    assertEquals(mapOf("a", "A", "b", "B", "c", "C", "d", "D", "e", "E"), abcde);
    assertMapVisitor(Key.get(mapOfString), stringType, stringType, setOf(abc, de), BOTH, false, 0,
        instance("a", "A"), instance("b", "B"), instance("c", "C"), instance("d", "D"), instance("e", "E"));

    // just make sure these succeed
    injector.getInstance(Key.get(mapOfStringProvider));
    injector.getInstance(Key.get(mapOfStringJavaxProvider));
  }

  public void testMapBinderAggregationForAnnotationInstance() {
    Module module = new AbstractModule() {
      @Override protected void configure() {
        MapBinder<String, String> multibinder = MapBinder.newMapBinder(
            binder(), String.class, String.class, Names.named("abc"));
        multibinder.addBinding("a").toInstance("A");
        multibinder.addBinding("b").toInstance("B");

        multibinder = MapBinder.newMapBinder(
            binder(), String.class, String.class, Names.named("abc"));
        multibinder.addBinding("c").toInstance("C");
      }
    };
    Injector injector = Guice.createInjector(module);

    Key<Map key = Key.get(mapOfString, Names.named("abc"));
    Map<String, String> abc = injector.getInstance(key);
    assertEquals(mapOf("a", "A", "b", "B", "c", "C"), abc);
    assertMapVisitor(key, stringType, stringType, setOf(module), BOTH, false, 0,
        instance("a", "A"), instance("b", "B"), instance("c", "C"));
    
    // just make sure these succeed
    injector.getInstance(Key.get(mapOfStringProvider, Names.named("abc")));
    injector.getInstance(Key.get(mapOfStringJavaxProvider, Names.named("abc")));
  }

  public void testMapBinderAggregationForAnnotationType() {
    Module module = new AbstractModule() {
      @Override protected void configure() {
        MapBinder<String, String> multibinder = MapBinder.newMapBinder(
            binder(), String.class, String.class, Abc.class);
        multibinder.addBinding("a").toInstance("A");
        multibinder.addBinding("b").toInstance("B");

        multibinder = MapBinder.newMapBinder(
            binder(), String.class, String.class, Abc.class);
        multibinder.addBinding("c").toInstance("C");
      }
    };
    Injector injector = Guice.createInjector(module);

    Key<Map key = Key.get(mapOfString, Abc.class);
    Map<String, String> abc = injector.getInstance(key);
    assertEquals(mapOf("a", "A", "b", "B", "c", "C"), abc);
    assertMapVisitor(key, stringType, stringType, setOf(module), BOTH, false, 0,
        instance("a", "A"), instance("b", "B"), instance("c", "C"));
    
    // just make sure these succeed
    injector.getInstance(Key.get(mapOfStringProvider, Abc.class));
    injector.getInstance(Key.get(mapOfStringJavaxProvider, Abc.class));
  }

  public void testMapBinderWithMultipleAnnotationValueSets() {
    Module module = new AbstractModule() {
      @Override protected void configure() {
        MapBinder<String, String> abcMapBinder = MapBinder.newMapBinder(
            binder(), String.class, String.class, named("abc"));
        abcMapBinder.addBinding("a").toInstance("A");
        abcMapBinder.addBinding("b").toInstance("B");
        abcMapBinder.addBinding("c").toInstance("C");

        MapBinder<String, String> deMapBinder = MapBinder.newMapBinder(
            binder(), String.class, String.class, named("de"));
        deMapBinder.addBinding("d").toInstance("D");
        deMapBinder.addBinding("e").toInstance("E");
      }
    };
    Injector injector = Guice.createInjector(module);

    Key<Map abcKey = Key.get(mapOfString, named("abc"));
    Map<String, String> abc = injector.getInstance(abcKey);
    Key<Map deKey = Key.get(mapOfString, named("de"));
    Map<String, String> de = injector.getInstance(deKey);
    assertEquals(mapOf("a", "A", "b", "B", "c", "C"), abc);
    assertEquals(mapOf("d", "D", "e", "E"), de);
    assertMapVisitor(abcKey, stringType, stringType, setOf(module), BOTH, false, 1,
        instance("a", "A"), instance("b", "B"), instance("c", "C"));
    assertMapVisitor(deKey, stringType, stringType, setOf(module), BOTH, false, 1,
        instance("d", "D"), instance("e", "E"));     
    
    // just make sure these succeed
    injector.getInstance(Key.get(mapOfStringProvider, named("abc")));
    injector.getInstance(Key.get(mapOfStringJavaxProvider, named("abc")));
    injector.getInstance(Key.get(mapOfStringProvider, named("de")));
    injector.getInstance(Key.get(mapOfStringJavaxProvider, named("de")));
  }

  public void testMapBinderWithMultipleAnnotationTypeSets() {
    Module module = new AbstractModule() {
      @Override protected void configure() {
        MapBinder<String, String> abcMapBinder = MapBinder.newMapBinder(
            binder(), String.class, String.class, Abc.class);
        abcMapBinder.addBinding("a").toInstance("A");
        abcMapBinder.addBinding("b").toInstance("B");
        abcMapBinder.addBinding("c").toInstance("C");

        MapBinder<String, String> deMapBinder = MapBinder.newMapBinder(
            binder(), String.class, String.class, De.class);
        deMapBinder.addBinding("d").toInstance("D");
        deMapBinder.addBinding("e").toInstance("E");
      }
    };
    Injector injector = Guice.createInjector(module);

    Key<Map abcKey = Key.get(mapOfString, Abc.class);
    Map<String, String> abc = injector.getInstance(abcKey);
    Key<Map deKey = Key.get(mapOfString, De.class);
    Map<String, String> de = injector.getInstance(deKey);
    assertEquals(mapOf("a", "A", "b", "B", "c", "C"), abc);
    assertEquals(mapOf("d", "D", "e", "E"), de);
    assertMapVisitor(abcKey, stringType, stringType, setOf(module), BOTH, false, 1,
        instance("a", "A"), instance("b", "B"), instance("c", "C"));
    assertMapVisitor(deKey, stringType, stringType, setOf(module), BOTH, false, 1,
        instance("d", "D"), instance("e", "E"));
    
    // just make sure these succeed
    injector.getInstance(Key.get(mapOfStringProvider, Abc.class));
    injector.getInstance(Key.get(mapOfStringJavaxProvider, Abc.class));
    injector.getInstance(Key.get(mapOfStringProvider, De.class));
    injector.getInstance(Key.get(mapOfStringJavaxProvider, De.class));
  }

  public void testMapBinderWithMultipleTypes() {
    Module module = new AbstractModule() {
      @Override protected void configure() {
        MapBinder.newMapBinder(binder(), String.class, String.class)
            .addBinding("a").toInstance("A");
        MapBinder.newMapBinder(binder(), String.class, Integer.class)
            .addBinding("1").toInstance(1);
      }
    };
    Injector injector = Guice.createInjector(module);

    assertEquals(mapOf("a", "A"), injector.getInstance(Key.get(mapOfString)));
    assertEquals(mapOf("1", 1), injector.getInstance(Key.get(mapOfInteger)));
    assertMapVisitor(Key.get(mapOfString), stringType, stringType, setOf(module), BOTH, false, 1,
        instance("a", "A"));
    assertMapVisitor(Key.get(mapOfInteger), stringType, intType, setOf(module), BOTH, false, 1,
        instance("1", 1));
  }

  public void testMapBinderWithEmptyMap() {
    Module module = new AbstractModule() {
      @Override protected void configure() {
        MapBinder.newMapBinder(binder(), String.class, String.class);
      }
    };
    Injector injector = Guice.createInjector(module);

    Map<String, String> map = injector.getInstance(Key.get(mapOfString));
    assertEquals(Collections.emptyMap(), map);
    assertMapVisitor(Key.get(mapOfString), stringType, stringType, setOf(module), BOTH, false, 0);
  }

  public void testMapBinderMapIsUnmodifiable() {
    Injector injector = Guice.createInjector(new AbstractModule() {
      @Override protected void configure() {
        MapBinder.newMapBinder(binder(), String.class, String.class)
            .addBinding("a").toInstance("A");
      }
    });

    Map<String, String> map = injector.getInstance(Key.get(mapOfString));
    try {
      map.clear();
      fail();
    } catch(UnsupportedOperationException expected) {
    }
  }

  public void testMapBinderMapIsLazy() {
    Module module = new AbstractModule() {
      @Override protected void configure() {
        MapBinder.newMapBinder(binder(), String.class, Integer.class)
            .addBinding("num").toProvider(new Provider<Integer>() {
          int nextValue = 1;
          @Override public Integer get() {
            return nextValue++;
          }
        });
      }
    };
    Injector injector = Guice.createInjector(module);

    assertEquals(mapOf("num", 1), injector.getInstance(Key.get(mapOfInteger)));
    assertEquals(mapOf("num", 2), injector.getInstance(Key.get(mapOfInteger)));
    assertEquals(mapOf("num", 3), injector.getInstance(Key.get(mapOfInteger)));
    assertMapVisitor(Key.get(mapOfInteger), stringType, intType, setOf(module), BOTH, false, 0,
        providerInstance("num", 1));
  }

  public void testMapBinderMapForbidsDuplicateKeys() {
    Module module = new AbstractModule() {
      @Override protected void configure() {
        MapBinder<String, String> multibinder = MapBinder.newMapBinder(
            binder(), String.class, String.class);
        multibinder.addBinding("a").toInstance("A");
        multibinder.addBinding("a").toInstance("B");
      }
    };
    try {
      Guice.createInjector(module);
      fail();
    } catch(CreationException expected) {
      assertContains(expected.getMessage(),
          "Map injection failed due to duplicated key \"a\"");
    }
    
    assertMapVisitor(Key.get(mapOfString), stringType, stringType, setOf(module), MODULE, false, 0,
        instance("a", "A"), instance("a", "B"));
  }

  public void testExhaustiveDuplicateErrorMessage() throws Exception {
    class Module1 extends AbstractModule {
      @Override protected void configure() {
        MapBinder<String, Object> mapbinder =
            MapBinder.newMapBinder(binder(), String.class, Object.class);
        mapbinder.addBinding("a").to(String.class);
      }
    }
    class Module2 extends AbstractModule {
      @Override protected void configure() {
        MapBinder<String, Object> mapbinder =
            MapBinder.newMapBinder(binder(), String.class, Object.class);
        mapbinder.addBinding("a").to(Integer.class);
        mapbinder.addBinding("b").to(String.class);
      }
    }
    class Module3 extends AbstractModule {
      @Override protected void configure() {
        MapBinder<String, Object> mapbinder =
            MapBinder.newMapBinder(binder(), String.class, Object.class);
        mapbinder.addBinding("b").to(Integer.class);
      }
    }
    class Main extends AbstractModule {
      @Override protected void configure() {
        MapBinder.newMapBinder(binder(), String.class, Object.class);
        install(new Module1());
        install(new Module2());
        install(new Module3());
      }
      @Provides String provideString() { return "foo"; }
      @Provides Integer provideInt() { return 42; }
    }
    try {
      Guice.createInjector(new Main());
      fail();
    } catch(CreationException ce) {
      assertContains(ce.getMessage(),
          "Map injection failed due to duplicated key \"a\", from bindings:",
          asModuleChain(Main.class, Module1.class),
          asModuleChain(Main.class, Module2.class),
          "and key: \"b\", from bindings:",
          asModuleChain(Main.class, Module2.class),
          asModuleChain(Main.class, Module3.class),
          "at " + Main.class.getName() + ".configure(",
          asModuleChain(Main.class, MapBinder.RealMapBinder.class));
      assertEquals(1, ce.getErrorMessages().size());
    }
  }

  public void testMapBinderMapPermitDuplicateElements() {
    Module ab = new AbstractModule() {
      @Override protected void configure() {
        MapBinder<String, String> multibinder = MapBinder.newMapBinder(
            binder(), String.class, String.class);
        multibinder.addBinding("a").toInstance("A");
        multibinder.addBinding("b").toInstance("B");
        multibinder.permitDuplicates();
      }
    };
    Module bc = new AbstractModule() {
      @Override protected void configure() {
        MapBinder<String, String> multibinder = MapBinder.newMapBinder(
            binder(), String.class, String.class);
        multibinder.addBinding("b").toInstance("B");
        multibinder.addBinding("c").toInstance("C");
        multibinder.permitDuplicates();
      }
    };
    Injector injector = Guice.createInjector(ab, bc);

    assertEquals(mapOf("a", "A", "b", "B", "c", "C"), injector.getInstance(Key.get(mapOfString)));
    assertMapVisitor(Key.get(mapOfString), stringType, stringType, setOf(ab, bc), BOTH, true, 0,
        instance("a", "A"), instance("b", "B"), instance("c", "C"));
  }

  public void testMapBinderMapDoesNotDedupeDuplicateValues() {
    class ValueType {
      int keyPart;
      int dataPart;
      private ValueType(int keyPart, int dataPart) {
        this.keyPart = keyPart;
        this.dataPart = dataPart;
      }
      @Override
      public boolean equals(Object obj) {
        return (obj instanceof ValueType) && (keyPart == ((ValueType) obj).keyPart);
      }
      @Override
      public int hashCode() {
        return keyPart;
      }
    }
    Module m1 = new AbstractModule() {
      @Override protected void configure() {
        MapBinder<String, ValueType> multibinder = MapBinder.newMapBinder(
            binder(), String.class, ValueType.class);
        multibinder.addBinding("a").toInstance(new ValueType(1, 2));
      }
    };
    Module m2 = new AbstractModule() {
      @Override protected void configure() {
        MapBinder<String, ValueType> multibinder = MapBinder.newMapBinder(
            binder(), String.class, ValueType.class);
        multibinder.addBinding("b").toInstance(new ValueType(1, 3));
      }
    };
    
    Injector injector = Guice.createInjector(m1, m2);
    Map<String, ValueType> map = injector.getInstance(new Key>() {});
    assertEquals(2, map.get("a").dataPart);
    assertEquals(3, map.get("b").dataPart);
  }

  public void testMapBinderMultimap() {
    AbstractModule ab1c = new AbstractModule() {
      @Override protected void configure() {
        MapBinder<String, String> multibinder = MapBinder.newMapBinder(
            binder(), String.class, String.class);
        multibinder.addBinding("a").toInstance("A");
        multibinder.addBinding("b").toInstance("B1");
        multibinder.addBinding("c").toInstance("C");
      }
    };
    AbstractModule b2c = new AbstractModule() {
      @Override protected void configure() {
        MapBinder<String, String> multibinder = MapBinder.newMapBinder(
            binder(), String.class, String.class);
        multibinder.addBinding("b").toInstance("B2");
        multibinder.addBinding("c").toInstance("C");
        multibinder.permitDuplicates();
      }
    };
    Injector injector = Guice.createInjector(ab1c, b2c);

    assertEquals(mapOf("a", setOf("A"), "b", setOf("B1", "B2"), "c", setOf("C")),
        injector.getInstance(Key.get(mapOfSetOfString)));
    assertMapVisitor(Key.get(mapOfString), stringType, stringType, setOf(ab1c, b2c), BOTH, true, 0,
        instance("a", "A"), instance("b", "B1"), instance("b", "B2"), instance("c", "C"));
  }

  public void testMapBinderMultimapWithAnotation() {
    AbstractModule ab1 = new AbstractModule() {
      @Override protected void configure() {
        MapBinder<String, String> multibinder = MapBinder.newMapBinder(
            binder(), String.class, String.class, Abc.class);
        multibinder.addBinding("a").toInstance("A");
        multibinder.addBinding("b").toInstance("B1");
      }
    };
    AbstractModule b2c = new AbstractModule() {
      @Override protected void configure() {
        MapBinder<String, String> multibinder = MapBinder.newMapBinder(
            binder(), String.class, String.class, Abc.class);
        multibinder.addBinding("b").toInstance("B2");
        multibinder.addBinding("c").toInstance("C");
        multibinder.permitDuplicates();
      }
    };
    Injector injector = Guice.createInjector(ab1, b2c);

    assertEquals(mapOf("a", setOf("A"), "b", setOf("B1", "B2"), "c", setOf("C")),
        injector.getInstance(Key.get(mapOfSetOfString, Abc.class)));
    try {
      injector.getInstance(Key.get(mapOfSetOfString));
      fail();
    } catch (ConfigurationException expected) {}
    
    assertMapVisitor(Key.get(mapOfString, Abc.class), stringType, stringType, setOf(ab1, b2c), BOTH, true, 0,
        instance("a", "A"), instance("b", "B1"), instance("b", "B2"), instance("c", "C"));
  }

  public void testMapBinderMultimapIsUnmodifiable() {
    Injector injector = Guice.createInjector(new AbstractModule() {
      @Override protected void configure() {
        MapBinder<String, String> mapBinder = MapBinder.newMapBinder(
            binder(), String.class, String.class);
        mapBinder.addBinding("a").toInstance("A");
        mapBinder.permitDuplicates();
      }
    });

    Map<String, Set map = injector.getInstance(Key.get(mapOfSetOfString));
    try {
      map.clear();
      fail();
    } catch(UnsupportedOperationException expected) {
    }
    try {
      map.get("a").clear();
      fail();
    } catch(UnsupportedOperationException expected) {
    }
  }

  public void testMapBinderMapForbidsNullKeys() {
    try {
      Guice.createInjector(new AbstractModule() {
        @Override protected void configure() {
          MapBinder.newMapBinder(binder(), String.class, String.class).addBinding(null);
        }
      });
      fail();
    } catch (CreationException expected) {}
  }

  public void testMapBinderMapForbidsNullValues() {
    Module m = new AbstractModule() {
      @Override protected void configure() {
        MapBinder.newMapBinder(binder(), String.class, String.class)
            .addBinding("null").toProvider(Providers.<String>of(null));
      }
    };
    Injector injector = Guice.createInjector(m);

    try {
      injector.getInstance(Key.get(mapOfString));
      fail();
    } catch(ProvisionException expected) {
      assertContains(expected.getMessage(),
          "1) Map injection failed due to null value for key \"null\", bound at: "
          + m.getClass().getName() + ".configure(");
    }
  }

  public void testMapBinderProviderIsScoped() {
    final Provider<Integer> counter = new Provider() {
      int next = 1;
      @Override public Integer get() {
        return next++;
      }
    };

    Injector injector = Guice.createInjector(new AbstractModule() {
      @Override protected void configure() {
        MapBinder.newMapBinder(binder(), String.class, Integer.class)
            .addBinding("one").toProvider(counter).asEagerSingleton();
      }
    });

    assertEquals(1, (int) injector.getInstance(Key.get(mapOfInteger)).get("one"));
    assertEquals(1, (int) injector.getInstance(Key.get(mapOfInteger)).get("one"));
  }

  public void testSourceLinesInMapBindings() {
    try {
      Guice.createInjector(new AbstractModule() {
        @Override protected void configure() {
          MapBinder.newMapBinder(binder(), String.class, Integer.class)
              .addBinding("one");
        }
      });
      fail();
    } catch (CreationException expected) {
      assertContains(expected.getMessage(),
          "1) No implementation for java.lang.Integer",
          "at " + getClass().getName());
    }
  }

  /** We just want to make sure that mapbinder's binding depends on the underlying multibinder. */
  public void testMultibinderDependencies() {
    Injector injector = Guice.createInjector(new AbstractModule() {
      @Override protected void configure() {
        MapBinder<Integer, String> mapBinder
            = MapBinder.newMapBinder(binder(), Integer.class, String.class);
        mapBinder.addBinding(1).toInstance("A");
        mapBinder.addBinding(2).to(Key.get(String.class, Names.named("b")));

        bindConstant().annotatedWith(Names.named("b")).to("B");
      }
    });

    Binding<Map binding = injector.getBinding(new Key>() {});
    HasDependencies withDependencies = (HasDependencies) binding;
    Key<?> setKey = new Key>>>() {};
    assertEquals(ImmutableSet.<Dependencyof(Dependency.get(setKey)),
        withDependencies.getDependencies());
    Set<String> elements = Sets.newHashSet();
    elements.addAll(recurseForDependencies(injector, withDependencies));
    assertEquals(ImmutableSet.of("A", "B"), elements);
  }

  private Set<String> recurseForDependencies(Injector injector, HasDependencies hasDependencies) {
    Set<String> elements = Sets.newHashSet();
    for (Dependency<?> dependency : hasDependencies.getDependencies()) {
      Binding<?> binding = injector.getBinding(dependency.getKey());
      HasDependencies deps = (HasDependencies) binding;
      if (binding instanceof InstanceBinding) {
        elements.add((String) ((InstanceBinding<?>) binding).getInstance());
      } else {
        elements.addAll(recurseForDependencies(injector, deps));
      }
    }    
    return elements;
  }

  /** We just want to make sure that mapbinder's binding depends on the underlying multibinder. */
  public void testMultibinderDependenciesInToolStage() {
    Injector injector = Guice.createInjector(Stage.TOOL, new AbstractModule() {
      @Override protected void configure() {
          MapBinder<Integer, String> mapBinder
              = MapBinder.newMapBinder(binder(), Integer.class, String.class);
          mapBinder.addBinding(1).toInstance("A");
          mapBinder.addBinding(2).to(Key.get(String.class, Names.named("b")));
  
          bindConstant().annotatedWith(Names.named("b")).to("B");
        }});

    Binding<Map binding = injector.getBinding(new Key>() {});
    HasDependencies withDependencies = (HasDependencies) binding;
    Key<?> setKey = new Key>>>() {};
    assertEquals(ImmutableSet.<Dependencyof(Dependency.get(setKey)),
        withDependencies.getDependencies());
  }
  

  /**
   * Our implementation maintains order, but doesn't guarantee it in the API spec.
   * TODO: specify the iteration order?
   */
  public void testBindOrderEqualsIterationOrder() {
    Injector injector = Guice.createInjector(
        new AbstractModule() {
          @Override protected void configure() {
            MapBinder<String, String> mapBinder
                = MapBinder.newMapBinder(binder(), String.class, String.class);
            mapBinder.addBinding("leonardo").toInstance("blue");
            mapBinder.addBinding("donatello").toInstance("purple");
            install(new AbstractModule() {
              @Override protected void configure() {
                MapBinder.newMapBinder(binder(), String.class, String.class)
                    .addBinding("michaelangelo").toInstance("orange");
              }
            });
          }
        },
        new AbstractModule() {
          @Override protected void configure() {
            MapBinder.newMapBinder(binder(), String.class, String.class)
                .addBinding("raphael").toInstance("red");
          }
        });

    Map<String, String> map = injector.getInstance(new Key>() {});
    Iterator<Map.Entry iterator = map.entrySet().iterator();
    assertEquals(Maps.immutableEntry("leonardo", "blue"), iterator.next());
    assertEquals(Maps.immutableEntry("donatello", "purple"), iterator.next());
    assertEquals(Maps.immutableEntry("michaelangelo", "orange"), iterator.next());
    assertEquals(Maps.immutableEntry("raphael", "red"), iterator.next());
  }
  
  /**
   * With overrides, we should get the union of all map bindings.
   */
  public void testModuleOverrideAndMapBindings() {
    Module ab = new AbstractModule() {
      @Override protected void configure() {
        MapBinder<String, String> multibinder = MapBinder.newMapBinder(binder(), String.class, String.class);
        multibinder.addBinding("a").toInstance("A");
        multibinder.addBinding("b").toInstance("B");
      }
    };
    Module cd = new AbstractModule() {
      @Override protected void configure() {
        MapBinder<String, String> multibinder = MapBinder.newMapBinder(binder(), String.class, String.class);
        multibinder.addBinding("c").toInstance("C");
        multibinder.addBinding("d").toInstance("D");
      }
    };
    Module ef = new AbstractModule() {
      @Override protected void configure() {
        MapBinder<String, String> multibinder = MapBinder.newMapBinder(binder(), String.class, String.class);
        multibinder.addBinding("e").toInstance("E");
        multibinder.addBinding("f").toInstance("F");
      }
    };

    Module abcd = Modules.override(ab).with(cd);
    Injector injector = Guice.createInjector(abcd, ef);
    assertEquals(mapOf("a", "A", "b", "B", "c", "C", "d", "D", "e", "E", "f", "F"),
        injector.getInstance(Key.get(mapOfString)));
    assertMapVisitor(Key.get(mapOfString), stringType, stringType, setOf(abcd, ef), BOTH, false, 0,
        instance("a", "A"), instance("b", "B"), instance("c", "C"), instance("d", "D"), instance(
            "e", "E"), instance("f", "F"));
  }
  
  public void testDeduplicateMapBindings() {
    Module module = new AbstractModule() {
      @Override protected void configure() {
        MapBinder<String, String> mapbinder =
            MapBinder.newMapBinder(binder(), String.class, String.class);
        mapbinder.addBinding("a").toInstance("A");
        mapbinder.addBinding("a").toInstance("A");
        mapbinder.addBinding("b").toInstance("B");
        mapbinder.addBinding("b").toInstance("B");
        
      }
    };
    Injector injector = Guice.createInjector(module);
    assertEquals(mapOf("a", "A", "b", "B"),
        injector.getInstance(Key.get(mapOfString)));
    assertMapVisitor(Key.get(mapOfString), stringType, stringType, setOf(module), BOTH, false, 0,
        instance("a", "A"), instance("b", "B"));
  }
  
  /**
   * With overrides, we should get the union of all map bindings.
   */
  public void testModuleOverrideAndMapBindingsWithPermitDuplicates() {
    Module abc = new AbstractModule() {
      @Override protected void configure() {
        MapBinder<String, String> multibinder = MapBinder.newMapBinder(binder(), String.class, String.class);
        multibinder.addBinding("a").toInstance("A");
        multibinder.addBinding("b").toInstance("B");
        multibinder.addBinding("c").toInstance("C");
        multibinder.permitDuplicates();
      }
    };
    Module cd = new AbstractModule() {
      @Override protected void configure() {
        MapBinder<String, String> multibinder = MapBinder.newMapBinder(binder(), String.class, String.class);
        multibinder.addBinding("c").toInstance("C");
        multibinder.addBinding("d").toInstance("D");
        multibinder.permitDuplicates();
      }
    };
    Module ef = new AbstractModule() {
      @Override protected void configure() {
        MapBinder<String, String> multibinder = MapBinder.newMapBinder(binder(), String.class, String.class);
        multibinder.addBinding("e").toInstance("E");
        multibinder.addBinding("f").toInstance("F");
        multibinder.permitDuplicates();
      }
    };

    Module abcd = Modules.override(abc).with(cd);
    Injector injector = Guice.createInjector(abcd, ef);
    assertEquals(mapOf("a", "A", "b", "B", "c", "C", "d", "D", "e", "E", "f", "F"),
        injector.getInstance(Key.get(mapOfString)));
    assertMapVisitor(Key.get(mapOfString), stringType, stringType, setOf(abcd, ef), BOTH, true, 0,
        instance("a", "A"), instance("b", "B"), instance("c", "C"), instance(
            "d", "D"), instance("e", "E"), instance("f", "F"));

  }  

  /** Ensure there are no initialization race conditions in basic map injection. */
  public void testBasicMapDependencyInjection() {
    final AtomicReference<Map injectedMap =
        new AtomicReference<Map();
    final Object anObject = new Object() {
      @Inject void initialize(Map<String, String> map) {
        injectedMap.set(map);
      }
    };
    Module abc = new AbstractModule() {
      @Override protected void configure() {
        requestInjection(anObject);
        MapBinder<String, String> multibinder =
            MapBinder.newMapBinder(binder(), String.class, String.class);
        multibinder.addBinding("a").toInstance("A");
        multibinder.addBinding("b").toInstance("B");
        multibinder.addBinding("c").toInstance("C");
      }
    };
    Guice.createInjector(abc);
    assertEquals(mapOf("a", "A", "b", "B", "c", "C"), injectedMap.get());
  } 

  /** Ensure there are no initialization race conditions in provider multimap injection. */
  public void testProviderMultimapDependencyInjection() {
    final AtomicReference<Map>> injectedMultimap =
        new AtomicReference<Map>>();
    final Object anObject = new Object() {
      @Inject void initialize(Map<String, Set> multimap) {
        injectedMultimap.set(multimap);
      }
    };
    Module abc = new AbstractModule() {
      @Override protected void configure() {
        requestInjection(anObject);
        MapBinder<String, String> multibinder =
            MapBinder.newMapBinder(binder(), String.class, String.class);
        multibinder.permitDuplicates();
        multibinder.addBinding("a").toInstance("A");
        multibinder.addBinding("b").toInstance("B");
        multibinder.addBinding("c").toInstance("C");
      }
    };
    Guice.createInjector(abc);
    Map<String, String> map = Maps.transformValues(injectedMultimap.get(),
        new Function<Set, String>() {
          @Override public String apply(Set<Provider stringProvidersSet) {
            return Iterables.getOnlyElement(stringProvidersSet).get();
          }
        });
    assertEquals(mapOf("a", "A", "b", "B", "c", "C"), map);
  }
  
  @Retention(RUNTIME) @BindingAnnotation
  @interface Abc {}

  @Retention(RUNTIME) @BindingAnnotation
  @interface De {}

  @SuppressWarnings("unchecked")
  private <K, V> Map mapOf(Object... elements) {
    Map<K, V> result = new HashMap();
    for (int i = 0; i < elements.length; i += 2) {
      result.put((K)elements[i], (V)elements[i+1]);
    }
    return result;
  }

  @SuppressWarnings("unchecked")
  private <V> Set setOf(V... elements) {
    return new HashSet<V>(Arrays.asList(elements));
  }

  @BindingAnnotation
  @Retention(RetentionPolicy.RUNTIME)
  @Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
  private static @interface Marker {}

  @Marker
  public void testMapBinderMatching() throws Exception {
    Method m = MapBinderTest.class.getDeclaredMethod("testMapBinderMatching");
    assertNotNull(m);
    final Annotation marker = m.getAnnotation(Marker.class);
    Injector injector = Guice.createInjector(new AbstractModule() {
      @Override public void configure() {
        MapBinder<Integer, Integer> mb1 =
          MapBinder.newMapBinder(binder(), Integer.class, Integer.class, Marker.class);
        MapBinder<Integer, Integer> mb2 = 
          MapBinder.newMapBinder(binder(), Integer.class, Integer.class, marker);
        mb1.addBinding(1).toInstance(1);
        mb2.addBinding(2).toInstance(2);

        // This assures us that the two binders are equivalent, so we expect the instance added to
        // each to have been added to one set.
        assertEquals(mb1, mb2);
      }
    });
    TypeLiteral<Map t = new TypeLiteral>() {};
    Map<Integer, Integer> s1 = injector.getInstance(Key.get(t, Marker.class));
    Map<Integer, Integer> s2 = injector.getInstance(Key.get(t, marker));

    // This assures us that the two sets are in fact equal.  They may not be same set (as in Java
    // object identical), but we shouldn't expect that, since probably Guice creates the set each
    // time in case the elements are dependent on scope.
    assertEquals(s1, s2);

    // This ensures that MultiBinder is internally using the correct set name --
    // making sure that instances of marker annotations have the same set name as
    // MarkerAnnotation.class.
    Map<Integer, Integer> expected = new HashMap();
    expected.put(1, 1);
    expected.put(2, 2);
    assertEquals(expected, s1);
  }

  public void testTwoMapBindersAreDistinct() {
    Injector injector = Guice.createInjector(new AbstractModule() {
      @Override protected void configure() {  
        MapBinder.newMapBinder(binder(), String.class, String.class)
            .addBinding("A").toInstance("a");
        
        MapBinder.newMapBinder(binder(), Integer.class, String.class)
            .addBinding(1).toInstance("b");
      }
    });
    Collector collector = new Collector();
    Binding<Map map1 = injector.getBinding(Key.get(mapOfString));
    map1.acceptTargetVisitor(collector);
    assertNotNull(collector.mapbinding);
    MapBinderBinding<?> map1Binding = collector.mapbinding;
  
    Binding<Map map2 = injector.getBinding(Key.get(mapOfIntString));
    map2.acceptTargetVisitor(collector);
    assertNotNull(collector.mapbinding);
    MapBinderBinding<?> map2Binding = collector.mapbinding;
  
    List<Binding bindings = injector.findBindingsByType(stringType);
    assertEquals("should have two elements: " + bindings, 2, bindings.size());
    Binding<String> a = bindings.get(0);
    Binding<String> b = bindings.get(1);
    assertEquals("a", ((InstanceBinding<String>) a).getInstance());
    assertEquals("b", ((InstanceBinding<String>) b).getInstance());
    
    // Make sure the correct elements belong to their own sets.
    assertTrue(map1Binding.containsElement(a));
    assertFalse(map1Binding.containsElement(b));
  
    assertFalse(map2Binding.containsElement(a));
    assertTrue(map2Binding.containsElement(b));
  }

  // Tests for com.google.inject.internal.WeakKeySet not leaking memory.
  public void testWeakKeySet_integration_mapbinder() {
    Key<Map mapKey = Key.get(new TypeLiteral>() {});
    
    Injector parentInjector = Guice.createInjector(new AbstractModule() {
          @Override protected void configure() {
            bind(String.class).toInstance("hi");
          }
        });
    WeakKeySetUtils.assertNotBlacklisted(parentInjector, mapKey);

    Injector childInjector = parentInjector.createChildInjector(new AbstractModule() {
      @Override protected void configure() {
        MapBinder<String, String> binder =
            MapBinder.newMapBinder(binder(), String.class, String.class);
        binder.addBinding("bar").toInstance("foo");
      }
    });
    WeakReference<Injector> weakRef = new WeakReference(childInjector);
    WeakKeySetUtils.assertBlacklisted(parentInjector, mapKey);
    
    // Clear the ref, GC, and ensure that we are no longer blacklisting.
    childInjector = null;
    
    Asserts.awaitClear(weakRef);
    WeakKeySetUtils.assertNotBlacklisted(parentInjector, mapKey);
  }
}

Other Java examples (source code examples)

Here is a short list of links related to this Java MapBinderTest.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.