/* BSD LICENSE NOTICE * Copyright (c) 2010-2012, Tim Boudreau, All Rights Reserved * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.mastfrog.giulius; import com.google.inject.AbstractModule; import com.google.inject.BindingAnnotation; import com.google.inject.Guice; import com.google.inject.Inject; import com.google.inject.Injector; import com.google.inject.Provider; import com.google.inject.TypeLiteral; import com.google.inject.matcher.Matchers; import com.google.inject.spi.DefaultBindingTargetVisitor; import com.google.inject.spi.TypeEncounter; import com.google.inject.spi.TypeListener; 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.util.Properties; import static org.junit.Assert.*; import org.junit.Test; /** * * @author Tim Boudreau */ public class ValueBindingTest { private static final class M extends AbstractModule { private final Properties propsA = new Properties(); private final Properties propsB = new Properties(); private final Properties defaults = new Properties(); M() { propsA.setProperty("a", "a"); propsB.setProperty("a", "b"); defaults.setProperty("a", "nothing"); } private final ThreadLocal<TypeLiteral<?>> type = new ThreadLocal<>(); @Override public void configure() { MyNamedImpl stringInjectionsOfA = new MyNamedImpl("a"); //in real life we'd iterate all the keys bind(String.class).annotatedWith(stringInjectionsOfA).toProvider(new PropsProvider(stringInjectionsOfA.value())); bindListener(Matchers.any(), new TypeListener() { @Override public <I> void hear(TypeLiteral<I> type, TypeEncounter<I> encounter) { M.this.type.set(type); } }); } private Class<?> getTheType() { return type.get().getRawType(); } public Properties getProperties() { Class<?> injectingInto = getTheType(); MyNamespace ns = injectingInto.getAnnotation(MyNamespace.class); Properties props = defaults; //fallback if (ns != null) { switch (ns.value()) { case "one": return propsA; case "two": return propsB; } } return props; } class PropsProvider extends DefaultBindingTargetVisitor<Object, Object> implements Provider<String> { private final String key; public PropsProvider(String key) { this.key = key; } @Override public String get() { return getProperties().getProperty(key); } } } @Target(ElementType.PARAMETER) @BindingAnnotation @Retention(RetentionPolicy.RUNTIME) @interface MyNamed { String value(); } private static class MyNamedImpl implements MyNamed { private final String value; public MyNamedImpl(String value) { this.value = value; } @Override public String value() { return value; } @Override public Class<? extends Annotation> annotationType() { return MyNamed.class; } public boolean equals(Object o) { return o instanceof MyNamed && value().equals(((MyNamed) o).value()); } public int hashCode() { return (127 * "value".hashCode()) ^ value.hashCode(); } } @Target({ElementType.PACKAGE, ElementType.TYPE, ElementType.FIELD, ElementType.LOCAL_VARIABLE}) @Retention(RetentionPolicy.RUNTIME) @interface MyNamespace { String value(); } @MyNamespace("one") static class InNamespaceOne { private final String value; @Inject public InNamespaceOne(@MyNamed("a") String value) { this.value = value; } } @MyNamespace("two") static class InNamespaceTwo { private final String value; @Inject public InNamespaceTwo(@MyNamed("a") String value) { this.value = value; } } static class NotNamespaced { private final String value; @Inject public NotNamespaced(@MyNamed("a") String value) { this.value = value; } } @Test public void test() { Injector inj = Guice.createInjector(new M()); InNamespaceOne a = inj.getInstance(InNamespaceOne.class); InNamespaceTwo b = inj.getInstance(InNamespaceTwo.class); NotNamespaced c = inj.getInstance(NotNamespaced.class); assertEquals("a", a.value); assertEquals("b", b.value); assertEquals("nothing", c.value); } }