/***************************************************************** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 org.apache.cayenne.di.spi; import org.apache.cayenne.di.Binder; import org.apache.cayenne.di.DIRuntimeException; import org.apache.cayenne.di.Key; import org.apache.cayenne.di.Module; import org.apache.cayenne.di.mock.MockImplementation1; import org.apache.cayenne.di.mock.MockImplementation1Alt; import org.apache.cayenne.di.mock.MockImplementation1Alt2; import org.apache.cayenne.di.mock.MockImplementation1_ListConfiguration; import org.apache.cayenne.di.mock.MockImplementation1_ListConfigurationMock5; import org.apache.cayenne.di.mock.MockImplementation1_MapConfiguration; import org.apache.cayenne.di.mock.MockImplementation1_MapWithWildcards; import org.apache.cayenne.di.mock.MockImplementation1_WithInjector; import org.apache.cayenne.di.mock.MockImplementation2; import org.apache.cayenne.di.mock.MockImplementation2Sub1; import org.apache.cayenne.di.mock.MockImplementation2_ConstructorProvider; import org.apache.cayenne.di.mock.MockImplementation2_ListConfiguration; import org.apache.cayenne.di.mock.MockImplementation2_Named; import org.apache.cayenne.di.mock.MockImplementation3; import org.apache.cayenne.di.mock.MockImplementation4; import org.apache.cayenne.di.mock.MockImplementation4Alt; import org.apache.cayenne.di.mock.MockImplementation4Alt2; import org.apache.cayenne.di.mock.MockImplementation5; import org.apache.cayenne.di.mock.MockInterface1; import org.apache.cayenne.di.mock.MockInterface2; import org.apache.cayenne.di.mock.MockInterface3; import org.apache.cayenne.di.mock.MockInterface4; import org.apache.cayenne.di.mock.MockInterface5; import org.junit.Test; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Map; import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; public class DefaultInjectorInjectionTest { @Test public void testFieldInjection() { Module module = new Module() { public void configure(Binder binder) { binder.bind(MockInterface1.class).to(MockImplementation1.class); binder.bind(MockInterface2.class).to(MockImplementation2.class); } }; DefaultInjector injector = new DefaultInjector(module); MockInterface2 service = injector.getInstance(MockInterface2.class); assertNotNull(service); assertEquals("altered_MyName", service.getAlteredName()); } @Test public void testFieldInjection_Named() { Module module = new Module() { public void configure(Binder binder) { binder.bind(MockInterface1.class).to(MockImplementation1.class); binder.bind(Key.get(MockInterface1.class, "one")).to(MockImplementation1Alt.class); binder.bind(Key.get(MockInterface1.class, "two")).to(MockImplementation1Alt2.class); binder.bind(MockInterface2.class).to(MockImplementation2_Named.class); } }; DefaultInjector injector = new DefaultInjector(module); MockInterface2 service = injector.getInstance(MockInterface2.class); assertNotNull(service); assertEquals("altered_alt", service.getAlteredName()); } @Test public void testFieldInjectionSuperclass() { Module module = new Module() { public void configure(Binder binder) { binder.bind(MockInterface1.class).to(MockImplementation1.class); binder.bind(MockInterface2.class).to(MockImplementation2Sub1.class); binder.bind(MockInterface3.class).to(MockImplementation3.class); } }; DefaultInjector injector = new DefaultInjector(module); MockInterface2 service = injector.getInstance(MockInterface2.class); assertNotNull(service); assertEquals("altered_MyName:XName", service.getAlteredName()); } @Test public void testConstructorInjection() { Module module = new Module() { public void configure(Binder binder) { binder.bind(MockInterface1.class).to(MockImplementation1.class); binder.bind(MockInterface4.class).to(MockImplementation4.class); } }; DefaultInjector injector = new DefaultInjector(module); MockInterface4 service = injector.getInstance(MockInterface4.class); assertNotNull(service); assertEquals("constructor_MyName", service.getName()); } @Test public void testConstructorInjection_Named() { Module module = new Module() { public void configure(Binder binder) { binder.bind(MockInterface1.class).to(MockImplementation1.class); binder.bind(Key.get(MockInterface1.class, "one")).to(MockImplementation1Alt.class); binder.bind(Key.get(MockInterface1.class, "two")).to(MockImplementation1Alt2.class); binder.bind(MockInterface4.class).to(MockImplementation4Alt.class); } }; DefaultInjector injector = new DefaultInjector(module); MockInterface4 service = injector.getInstance(MockInterface4.class); assertNotNull(service); assertEquals("constructor_alt2", service.getName()); } @Test public void testConstructorInjection_Named_Mixed() { Module module = new Module() { public void configure(Binder binder) { binder.bind(MockInterface1.class).to(MockImplementation1.class); binder.bind(Key.get(MockInterface1.class, "one")).to(MockImplementation1Alt.class); binder.bind(Key.get(MockInterface1.class, "two")).to(MockImplementation1Alt2.class); binder.bind(MockInterface3.class).to(MockImplementation3.class); binder.bind(MockInterface4.class).to(MockImplementation4Alt2.class); } }; DefaultInjector injector = new DefaultInjector(module); MockInterface4 service = injector.getInstance(MockInterface4.class); assertNotNull(service); assertEquals("constructor_alt2_XName", service.getName()); } @Test public void testProviderInjection_Constructor() { Module module = new Module() { public void configure(Binder binder) { binder.bind(MockInterface1.class).to(MockImplementation1.class); binder.bind(MockInterface2.class).to(MockImplementation2_ConstructorProvider.class); } }; DefaultInjector injector = new DefaultInjector(module); MockInterface2 service = injector.getInstance(MockInterface2.class); assertEquals("altered_MyName", service.getAlteredName()); } @Test public void testMapInjection_Empty() { Module module = new Module() { public void configure(Binder binder) { binder.bind(MockInterface1.class).to(MockImplementation1_MapConfiguration.class); // empty map must be still bound binder.bindMap(Object.class, "xyz"); } }; DefaultInjector injector = new DefaultInjector(module); MockInterface1 service = injector.getInstance(MockInterface1.class); assertNotNull(service); assertEquals("", service.getName()); } @Test @SuppressWarnings("deprecation") public void mapInjectionDeprecated() { final String bindingName = "xyz"; final Object test = "test_map"; Module module = new Module() { @Override public void configure(Binder binder) { binder.bind(MockInterface1.class).to(MockImplementation1_MapConfiguration.class); binder.bindMap(bindingName).put("test", test).put("abc", "def"); } }; DefaultInjector injector = new DefaultInjector(module); // Even with old version of binding we should use new version of key... Map<String, Object> map = injector.getInstance(Key.getMapOf(String.class, Object.class, bindingName)); assertNotNull(map); assertEquals(test, map.get("test")); try { // Old version of getting by key will fail... injector.getInstance(Key.get(Map.class, bindingName)); fail("DI Exception should be thrown"); } catch (DIRuntimeException ignored) { } // Check that injection is working MockInterface1 interface1 = injector.getInstance(MockInterface1.class); assertThat(interface1, instanceOf(MockImplementation1_MapConfiguration.class)); assertEquals(";abc=def;test=test_map", interface1.getName()); } @Test public void testMapInjection() { Module module = new Module() { public void configure(Binder binder) { binder.bind(MockInterface1.class).to(MockImplementation1_MapConfiguration.class); binder.bindMap(Object.class,"xyz") .put("x", "xvalue").put("y", "yvalue").put("x", "xvalue1"); } }; DefaultInjector injector = new DefaultInjector(module); MockInterface1 service = injector.getInstance(MockInterface1.class); assertNotNull(service); assertEquals(";x=xvalue1;y=yvalue", service.getName()); } @Test public void mapWithWildcardInjection() { Module module = new Module() { public void configure(Binder binder) { binder.bind(MockInterface1.class).to(MockImplementation1_MapWithWildcards.class); binder.bindMap(Class.class).put("x", String.class).put("y", Integer.class).put("z", Object.class); } }; DefaultInjector injector = new DefaultInjector(module); // This is example of how to deal with wildcards: // to handle it nicer we need to use some hacks with anonymous classes: // Key.get(new TypeLiteral<String, Class<?>>(){}); Map mapUntyped = injector.getInstance(Key.getMapOf(String.class, Class.class)); @SuppressWarnings("unchecked") Map<String, Class<?>> map = (Map<String, Class<?>>)mapUntyped; assertNotNull(map); assertEquals(3, map.size()); assertEquals(String.class, map.get("x")); MockInterface1 service = injector.getInstance(MockInterface1.class); assertNotNull(service); assertEquals("map:3", service.getName()); } @Test public void testMapInjection_Resumed() { Module module = new Module() { public void configure(Binder binder) { binder.bind(MockInterface1.class).to(MockImplementation1_MapConfiguration.class); // bind 1 binder.bindMap(Object.class,"xyz").put("x", "xvalue").put("y", "yvalue"); // second binding attempt to the same map... binder.bindMap(Object.class,"xyz").put("z", "zvalue").put("x", "xvalue1"); } }; DefaultInjector injector = new DefaultInjector(module); MockInterface1 service = injector.getInstance(MockInterface1.class); assertNotNull(service); assertEquals(";x=xvalue1;y=yvalue;z=zvalue", service.getName()); } @Test public void testListInjection_addValue() { Module module = new Module() { public void configure(Binder binder) { binder.bind(MockInterface1.class).to(MockImplementation1_ListConfiguration.class); binder.bindList(Object.class, "xyz").add("xvalue").add("yvalue"); } }; DefaultInjector injector = new DefaultInjector(module); MockInterface1 service = injector.getInstance(MockInterface1.class); assertNotNull(service); assertEquals(";xvalue;yvalue", service.getName()); } @Test public void testListInjection_addOrderedValues() { Module module = new Module() { @Override public void configure(Binder binder) { binder.bind(MockInterface1.class).to(MockImplementation1_ListConfiguration.class); binder.bind(MockInterface5.class).to(MockImplementation5.class); binder.bindList(Object.class, "xyz") .add("1value") .add("2value") .addAfter("5value", MockInterface5.class) .insertBefore("3value", MockInterface5.class) .add(MockInterface5.class); } }; DefaultInjector injector = new DefaultInjector(module); MockInterface1 service = injector.getInstance(MockInterface1.class); assertNotNull(service); assertEquals(";1value;2value;3value;xyz;5value", service.getName()); } @Test public void testListInjection_addAllValues() { Module module = new Module() { @Override public void configure(Binder binder) { binder.bind(MockInterface1.class).to(MockImplementation1_ListConfiguration.class); Collection<Object> firstList = new ArrayList<>(); firstList.add("1value"); firstList.add("2value"); firstList.add("3value"); Collection<Object> secondList = new ArrayList<>(); secondList.add("6value"); secondList.add("7value"); secondList.add("8value"); binder.bind(MockInterface5.class).to(MockImplementation5.class); binder.bindList(Object.class, "xyz") .insertAllBefore(firstList, MockInterface5.class) .addAllAfter(secondList, MockInterface5.class) .add("5value") .add(MockInterface5.class); } }; DefaultInjector injector = new DefaultInjector(module); MockInterface1 service = injector.getInstance(MockInterface1.class); assertNotNull(service); assertEquals(";1value;2value;3value;xyz;6value;7value;8value;5value", service.getName()); } @Test public void testListInjection_addType() { Module module = new Module() { public void configure(Binder binder) { binder.bind(MockInterface5.class).to(MockImplementation5.class); binder.bind(MockInterface1.class).to(MockImplementation1_ListConfiguration.class); binder.bindList(Object.class, "xyz").add(MockInterface5.class).add("yvalue"); } }; DefaultInjector injector = new DefaultInjector(module); MockInterface1 service = injector.getInstance(MockInterface1.class); assertNotNull(service); assertEquals(";xyz;yvalue", service.getName()); } @Test public void testListInjection_addOrderedTypes() { Module module = new Module() { public void configure(Binder binder) { binder.bind(MockInterface1.class).to(MockImplementation1_ListConfiguration.class); binder.bind(MockInterface5.class).to(MockImplementation5.class); binder.bindList(Object.class, "xyz") .add("1value") .insertBefore("5value", MockInterface5.class) .add("2value") .addAfter("6value", MockInterface5.class) .add("3value") .add(MockInterface5.class); } }; DefaultInjector injector = new DefaultInjector(module); MockInterface1 service = injector.getInstance(MockInterface1.class); assertNotNull(service); assertEquals(";1value;2value;5value;xyz;6value;3value", service.getName()); } @Test public void testListInjection_addTypeWithBinding() { Module module = new Module() { public void configure(Binder binder) { binder.bind(MockInterface1.class).to(MockImplementation1_ListConfiguration.class); binder.bindList(Object.class, "xyz").add(MockImplementation5.class).add("yvalue"); } }; DefaultInjector injector = new DefaultInjector(module); MockInterface1 service = injector.getInstance(MockInterface1.class); assertNotNull(service); assertEquals(";xyz;yvalue", service.getName()); } @Test public void testListInjection_empty() { Module module = new Module() { public void configure(Binder binder) { binder.bind(MockInterface1.class).to(MockImplementation1_ListConfiguration.class); binder.bindList(Object.class,"xyz"); } }; DefaultInjector injector = new DefaultInjector(module); MockInterface1 service = injector.getInstance(MockInterface1.class); assertNotNull(service); assertEquals("", service.getName()); } @Test public void testListInjection_resumed() { Module module = new Module() { public void configure(Binder binder) { binder.bind(MockInterface1.class).to(MockImplementation1_ListConfiguration.class); binder.bindList(Object.class, "xyz").add("xvalue").add("yvalue"); binder.bindList(Object.class, "xyz").add("avalue"); } }; DefaultInjector injector = new DefaultInjector(module); MockInterface1 service = injector.getInstance(MockInterface1.class); assertNotNull(service); assertEquals(";xvalue;yvalue;avalue", service.getName()); } @Test public void testTypedListInjection() { Module module = new Module() { public void configure(Binder binder) { binder.bind(MockInterface1.class).to(MockImplementation1_ListConfigurationMock5.class); binder.bind(MockInterface2.class).to(MockImplementation2_ListConfiguration.class); // Bind list for MockImplementation2_ListConfiguration binder.bindList(Object.class,"xyz") .add("xvalue") .add("yvalue") .add(MockImplementation5.class); // Bind list for MockImplementation1_ListConfigurationMock5 binder.bindList(MockInterface5.class) .add(MockImplementation5.class) .add(new MockInterface5() { @Override public String toString() { return "abc"; } }); binder.bindList(Object.class) .add("avalue") .add("bvalue") .add(MockImplementation5.class); // Add to list for MockImplementation1_ListConfigurationMock5 binder.bindList(MockInterface5.class) .add(new MockInterface5() { @Override public String toString() { return "cde"; } }); // Create named list for MockInterface5 binder.bindList(MockInterface5.class, "another_binding") .add(new MockInterface5() { @Override public String toString() { return "fgh"; } }); } }; DefaultInjector injector = new DefaultInjector(module); MockInterface1 service = injector.getInstance(MockInterface1.class); assertNotNull(service); assertEquals(";xyz;abc;cde", service.getName()); MockInterface2 service2 = injector.getInstance(MockInterface2.class); assertNotNull(service2); assertTrue(service2 instanceof MockImplementation2_ListConfiguration); assertEquals(";xvalue;yvalue;xyz", service2.getName()); } @Test public void testInjectorInjection() { Module module = new Module() { public void configure(Binder binder) { binder.bind(MockInterface1.class).to( MockImplementation1_WithInjector.class); } }; DefaultInjector injector = new DefaultInjector(module); MockInterface1 service = injector.getInstance(MockInterface1.class); assertNotNull(service); assertEquals("injector_not_null", service.getName()); } }