Repository: cayenne Updated Branches: refs/heads/master d8bba279e -> 965cafc79
DI: new tests for wildcards and deprecated API + additions to upgrade notes. Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/965cafc7 Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/965cafc7 Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/965cafc7 Branch: refs/heads/master Commit: 965cafc796d15f281335c7c61cdf0e412e8fd431 Parents: d8bba27 Author: Nikita Timofeev <stari...@gmail.com> Authored: Fri May 12 12:18:42 2017 +0300 Committer: Nikita Timofeev <stari...@gmail.com> Committed: Fri May 12 12:18:42 2017 +0300 ---------------------------------------------------------------------- .../MockImplementation1_MapWithWildcards.java | 38 +++++ .../di/spi/DefaultInjectorInjectionTest.java | 141 ++++++++++++------- docs/doc/src/main/resources/UPGRADE.txt | 9 +- 3 files changed, 133 insertions(+), 55 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cayenne/blob/965cafc7/cayenne-di/src/test/java/org/apache/cayenne/di/mock/MockImplementation1_MapWithWildcards.java ---------------------------------------------------------------------- diff --git a/cayenne-di/src/test/java/org/apache/cayenne/di/mock/MockImplementation1_MapWithWildcards.java b/cayenne-di/src/test/java/org/apache/cayenne/di/mock/MockImplementation1_MapWithWildcards.java new file mode 100644 index 0000000..8048b83 --- /dev/null +++ b/cayenne-di/src/test/java/org/apache/cayenne/di/mock/MockImplementation1_MapWithWildcards.java @@ -0,0 +1,38 @@ +/***************************************************************** + * 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.mock; + +import java.util.Map; + +import org.apache.cayenne.di.Inject; + +/** + * @since 4.0 + */ +public class MockImplementation1_MapWithWildcards implements MockInterface1 { + + @Inject + Map<String, Class<?>> testMap; + + @Override + public String getName() { + return "map:" + testMap.size(); + } +} http://git-wip-us.apache.org/repos/asf/cayenne/blob/965cafc7/cayenne-di/src/test/java/org/apache/cayenne/di/spi/DefaultInjectorInjectionTest.java ---------------------------------------------------------------------- diff --git a/cayenne-di/src/test/java/org/apache/cayenne/di/spi/DefaultInjectorInjectionTest.java b/cayenne-di/src/test/java/org/apache/cayenne/di/spi/DefaultInjectorInjectionTest.java index 27411e3..8d7d742 100644 --- a/cayenne-di/src/test/java/org/apache/cayenne/di/spi/DefaultInjectorInjectionTest.java +++ b/cayenne-di/src/test/java/org/apache/cayenne/di/spi/DefaultInjectorInjectionTest.java @@ -19,6 +19,7 @@ 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; @@ -27,6 +28,7 @@ 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; @@ -47,10 +49,11 @@ import org.junit.Test; import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; +import java.util.Map; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; public class DefaultInjectorInjectionTest { @@ -79,10 +82,8 @@ public class DefaultInjectorInjectionTest { 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(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); } }; @@ -138,10 +139,8 @@ public class DefaultInjectorInjectionTest { 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(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); } }; @@ -160,10 +159,8 @@ public class DefaultInjectorInjectionTest { 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(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); } @@ -183,8 +180,7 @@ public class DefaultInjectorInjectionTest { public void configure(Binder binder) { binder.bind(MockInterface1.class).to(MockImplementation1.class); - binder.bind(MockInterface2.class).to( - MockImplementation2_ConstructorProvider.class); + binder.bind(MockInterface2.class).to(MockImplementation2_ConstructorProvider.class); } }; @@ -199,8 +195,7 @@ public class DefaultInjectorInjectionTest { Module module = new Module() { public void configure(Binder binder) { - binder.bind(MockInterface1.class).to( - MockImplementation1_MapConfiguration.class); + binder.bind(MockInterface1.class).to(MockImplementation1_MapConfiguration.class); // empty map must be still bound binder.bindMap(Object.class, "xyz"); @@ -215,16 +210,45 @@ public class DefaultInjectorInjectionTest { } @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"); + binder.bind(MockInterface1.class).to(MockImplementation1_MapConfiguration.class); + binder.bindMap(Object.class,"xyz") + .put("x", "xvalue").put("y", "yvalue").put("x", "xvalue1"); } }; @@ -236,16 +260,40 @@ public class DefaultInjectorInjectionTest { } @Test - public void testMapInjection_Resumed() { + public void mapWithWildcardInjection() { Module module = new Module() { public void configure(Binder binder) { - binder.bind(MockInterface1.class).to( - MockImplementation1_MapConfiguration.class); + 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"); } @@ -263,9 +311,7 @@ public class DefaultInjectorInjectionTest { Module module = new Module() { public void configure(Binder binder) { - binder.bind(MockInterface1.class).to( - MockImplementation1_ListConfiguration.class); - + binder.bind(MockInterface1.class).to(MockImplementation1_ListConfiguration.class); binder.bindList(Object.class, "xyz").add("xvalue").add("yvalue"); } }; @@ -282,9 +328,7 @@ public class DefaultInjectorInjectionTest { Module module = new Module() { @Override public void configure(Binder binder) { - binder.bind(MockInterface1.class).to( - MockImplementation1_ListConfiguration.class); - + binder.bind(MockInterface1.class).to(MockImplementation1_ListConfiguration.class); binder.bind(MockInterface5.class).to(MockImplementation5.class); binder.bindList(Object.class, "xyz") @@ -308,8 +352,7 @@ public class DefaultInjectorInjectionTest { Module module = new Module() { @Override public void configure(Binder binder) { - binder.bind(MockInterface1.class).to( - MockImplementation1_ListConfiguration.class); + binder.bind(MockInterface1.class).to(MockImplementation1_ListConfiguration.class); Collection<Object> firstList = new ArrayList<>(); firstList.add("1value"); @@ -344,9 +387,7 @@ public class DefaultInjectorInjectionTest { public void configure(Binder binder) { binder.bind(MockInterface5.class).to(MockImplementation5.class); - - binder.bind(MockInterface1.class).to( - MockImplementation1_ListConfiguration.class); + binder.bind(MockInterface1.class).to(MockImplementation1_ListConfiguration.class); binder.bindList(Object.class, "xyz").add(MockInterface5.class).add("yvalue"); } @@ -364,9 +405,7 @@ public class DefaultInjectorInjectionTest { Module module = new Module() { public void configure(Binder binder) { - binder.bind(MockInterface1.class).to( - MockImplementation1_ListConfiguration.class); - + binder.bind(MockInterface1.class).to(MockImplementation1_ListConfiguration.class); binder.bind(MockInterface5.class).to(MockImplementation5.class); binder.bindList(Object.class, "xyz") @@ -391,9 +430,7 @@ public class DefaultInjectorInjectionTest { Module module = new Module() { public void configure(Binder binder) { - binder.bind(MockInterface1.class).to( - MockImplementation1_ListConfiguration.class); - + binder.bind(MockInterface1.class).to(MockImplementation1_ListConfiguration.class); binder.bindList(Object.class, "xyz").add(MockImplementation5.class).add("yvalue"); } }; @@ -410,8 +447,7 @@ public class DefaultInjectorInjectionTest { Module module = new Module() { public void configure(Binder binder) { - binder.bind(MockInterface1.class).to( - MockImplementation1_ListConfiguration.class); + binder.bind(MockInterface1.class).to(MockImplementation1_ListConfiguration.class); binder.bindList(Object.class,"xyz"); } }; @@ -428,8 +464,7 @@ public class DefaultInjectorInjectionTest { Module module = new Module() { public void configure(Binder binder) { - binder.bind(MockInterface1.class).to( - MockImplementation1_ListConfiguration.class); + binder.bind(MockInterface1.class).to(MockImplementation1_ListConfiguration.class); binder.bindList(Object.class, "xyz").add("xvalue").add("yvalue"); binder.bindList(Object.class, "xyz").add("avalue"); @@ -448,10 +483,8 @@ public class DefaultInjectorInjectionTest { 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); + 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") http://git-wip-us.apache.org/repos/asf/cayenne/blob/965cafc7/docs/doc/src/main/resources/UPGRADE.txt ---------------------------------------------------------------------- diff --git a/docs/doc/src/main/resources/UPGRADE.txt b/docs/doc/src/main/resources/UPGRADE.txt index 4cd9d98..eb5514f 100644 --- a/docs/doc/src/main/resources/UPGRADE.txt +++ b/docs/doc/src/main/resources/UPGRADE.txt @@ -52,12 +52,19 @@ UPGRADING TO 4.0.M6 - method after() replaced by explicit addAfter(), addAllAfter() - method before() replaced by insertBefore(), insertAllBefore() -* Per CAY-2258 Injection of List and Map are made type-safe, if you are using following methods: +* Per CAY-2258 Injection of List and Map are made type-safe, as a result small incompatibilities are introduced. + If you are using following methods: - bindMap(String bindingName) - bindList(String bindingName) you should change them to corresponding type-safe versions: - bindMap(Class<T> valueType, String bindingName) - bindList(Class<T> valueType, String bindingName) + Also if you are using DI Keys like Key.get(Map.class, "bindingName") or Key.get(List.class, "bindingName") + you should use new corresponding factory methods Key.mapOf(MapValues.class, "bindingName") + and Key.listOf(ListValues.class, "bindingName"). + Additionally new API allows you to bind Lists and Maps without using names: + - binder.bindList(SomeUniqueType.class).add(...); + - @Inject List<SomeUniqueType> list; * Per CAY-1873 and CAY-2266 Cache and remote notification configuration was moved from Modeler into runtime DI settings. To set custom cache size, you should use custom module like this: