В прошлый раз обещал, что выложу самописный IoC контейнер. Видимо пора бы это сделать уже - столько времени прошло.
Итак исходники качаем тут.
Начнем как всегда с тестов.
Именно так я и написал код, когда я начал разработку этого примера. Никаких классов контейнера естественно не было, и тест не компилился. Но я создал пустые классы с помощью IDE (Ctrl1-1 в Eclipse или Alt-Enter в Idea).
Вот он код пустой
Так теперь код хоть компилится! :) После того как была создана интерфейсная часть, я взялся за реализацию с помощью TDD.
Вот те тестовые сценарии, которые я один за другим написал и реализовал. Кода очень много :) потому что должен был проверить всевозможные случаи инъекции с разными полями, с одинаковыми полями, с наследниками, с реализациями, с примитивами и так далее. Если хочешь скипнуть - жми сюда.
Текста на самом деле много. А еще я все классы сделал Inner классами хотя в реальной версии они должны быть отдельными public классами иначе ничего не получится. Работа с иннераклассами у меня у туду.
Постепенно появлялась реализация. После несокльких подходов к коду я родил вот эти реализации
Классы достаточно сложновастые, но рефлексия все же. Библиотеку Fest Reflection я не хотел подключать из за лишней jar-dependency. В следующий раз попробую сделаю с ней - за одно попиарю этот классный инструмент для работы с рефлексией.
В будущих планах есть сделать то же но со Spring IoC. Ждите, продолжение следует..
Итак исходники качаем тут.
Начнем как всегда с тестов.
package container; import static org.junit.Assert.*; import org.junit.Before; import org.junit.Test; import container.ioc.*; import container.flashlight.*; import container.battery.*; public class TestBaterry { private Container container; @Before public void initContainer() { // обрати внимание перед каждым тестом проинитится контейнер, которому мы сообщили, что // заместь батарейки используй ChinaBattery а вместо фонарика SomeFlashlight container = new ContainerImpl( Binder.use(ChinaBattery.class).as(Battery.class), Binder.use(SomeFlashlight.class).as(Flashlight.class)); } @Test public void testDischargeNewBattery() { // таким нехитрым способом по интерфейсу мы получаем реализацию // контейнер пройдется по всем полям новосозданного объекта и // если там найдет знакомые типы то вставит в них реализации, // в соответствии с настройками, которые мы указали Flashlight flashlight = container.get(Flashlight.class); assertFalse(flashlight.isShines()); flashlight.swithOn(); assertTrue(flashlight.isShines()); for (int count = 0; count < 1000; count ++) { flashlight.swithOff(); flashlight.swithOn(); } flashlight.swithOn(); assertFalse(flashlight.isShines()); } @Test public void testBadBattery() { Battery battery = new Battery(){ @Override public boolean getVoltage() { return false; } }; // а вот так мы вдруг можем передумать и переопределить настройки контейнера container.update(Binder.use(battery).as(Battery.class)); Flashlight flashlight = container.get(Flashlight.class); assertFalse(flashlight.isShines()); flashlight.swithOn(); assertFalse(flashlight.isShines()); } @Test public void testNoGetPowerIfDoubleSwithOn() { Flashlight flashlight = container.get(Flashlight.class); assertFalse(flashlight.isShines()); for (int count = 0; count < 1000; count ++) { flashlight.swithOn(); } assertTrue(flashlight.isShines()); } @Test public void testNoBatteryNoLight() { container.remove(Battery.class); Flashlight flashlight = container.get(Flashlight.class); assertFalse(flashlight.isShines()); flashlight.swithOn(); assertFalse(flashlight.isShines()); } @Test public void integrationTestGetPowerFormNewChinaBattery() { Flashlight flashlight = container.get(Flashlight.class); assertFalse(flashlight.isShines()); flashlight.swithOn(); assertTrue(flashlight.isShines()); } }
Именно так я и написал код, когда я начал разработку этого примера. Никаких классов контейнера естественно не было, и тест не компилился. Но я создал пустые классы с помощью IDE (Ctrl1-1 в Eclipse или Alt-Enter в Idea).
Вот он код пустой
package container.ioc; public class Binder { public static Binder use(Class<?> classToCreate) { return null; } public static Binder use(Object object) { return null; } public Binder as(Class<?> interfaceClass) { return null; } }
package container.ioc; public interface Container { <T> T get(Class<T> interfaceClass); void remove(Class<?> clazz); void update(Binder binder); }
package container.ioc; public class ContainerImpl implements Container { public ContainerImpl(Binder...binders) { } @Override public <T> T get(Class<T> interfaceClass) { return null; } @Override public void remove(Class<?> clazz) { } @Override public void update(Binder binder) { } }
Так теперь код хоть компилится! :) После того как была создана интерфейсная часть, я взялся за реализацию с помощью TDD.
Вот те тестовые сценарии, которые я один за другим написал и реализовал. Кода очень много :) потому что должен был проверить всевозможные случаи инъекции с разными полями, с одинаковыми полями, с наследниками, с реализациями, с примитивами и так далее. Если хочешь скипнуть - жми сюда.
Текста на самом деле много. А еще я все классы сделал Inner классами хотя в реальной версии они должны быть отдельными public классами иначе ничего не получится. Работа с иннераклассами у меня у туду.
package container2.ioc.test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import org.junit.Test; import container.ioc.Binder; import container.ioc.ContainerImpl; public class IoCTest { interface Marker1 { } class Marker1Impl implements Marker1{ } interface Marker2 { } class Marker2Impl implements Marker2 { } interface Marker3 { } class Marker3Impl implements Marker3 { } interface MainMarker { } private <T> T getImpl(Class<T> mainClass) { return (T)new ContainerImpl( Binder.use(Marker1Impl.class).as(Marker1.class), Binder.use(Marker2Impl.class).as(Marker2.class), Binder.use(Marker3Impl.class).as(Marker3.class), Binder.use(mainClass).as(MainMarker.class)).get(MainMarker.class); } class ClassWithDefaultConstructor implements MainMarker { Marker1 marker1; public ClassWithDefaultConstructor() { } } @Test public void testWithDefaultConstructor() { assertEquals(Marker1Impl.class, getImpl(ClassWithDefaultConstructor.class).marker1.getClass()); } class ClassWithoutAnyConstructors implements MainMarker { Marker1 marker1; private ClassWithoutAnyConstructors() { } } @Test public void testWithoutAnyConstructors() { assertEquals(Marker1Impl.class, getImpl(ClassWithoutAnyConstructors.class).marker1.getClass()); } class ClassWithPrivateField implements MainMarker { private Marker1 marker1; public ClassWithPrivateField() {} public Object getMarker1() { return marker1; } } @Test public void testWithPrivateField() { assertEquals(Marker1Impl.class, getImpl(ClassWithPrivateField.class).getMarker1().getClass()); } class ClassWithInjectorConstructor implements MainMarker { private Marker1 marker1; public ClassWithInjectorConstructor(Marker1 marker1) { this.marker1 = marker1; } public Marker1 getMarker1() { return marker1; } } @Test public void testWithInjectorConstructor() { assertEquals(Marker1Impl.class, getImpl(ClassWithInjectorConstructor.class).getMarker1().getClass()); } class СlassWithInjectorConstructorAndTwoFields implements MainMarker { private Marker1 marker1; private Marker2 marker2; public СlassWithInjectorConstructorAndTwoFields(Marker2 marker2, Marker1 marker1) { this.marker1 = marker1; this.marker2 = marker2; } public Marker1 getMarker1() { return marker1; } public Marker2 getMarker2() { return marker2; } } @Test public void testWithInjectorConstructorAndTwoFieldsCheckField1() { assertEquals(Marker1Impl.class, getImpl(СlassWithInjectorConstructorAndTwoFields.class).getMarker1().getClass()); } @Test public void testWithInjectorConstructorAndTwoFieldsCheckField2() { assertEquals(Marker2Impl.class, getImpl(СlassWithInjectorConstructorAndTwoFields.class).getMarker2().getClass()); } class СlassWithPrivateInjectorConstructorAndTwoFields implements MainMarker { private Marker1 marker1; private Marker2 marker2; private СlassWithPrivateInjectorConstructorAndTwoFields(Marker2 marker2, Marker1 marker1) { this.marker1 = marker1; this.marker2 = marker2; } public Marker1 getMarker1() { return marker1; } public Marker2 getMarker2() { return marker2; } } @Test public void testWithPrivateInjectorConstructorAndTwoFieldsCheckField1() { assertEquals(Marker1Impl.class, getImpl(СlassWithPrivateInjectorConstructorAndTwoFields.class).getMarker1().getClass()); } @Test public void testWithPrivateInjectorConstructorAndTwoFieldsCheckField2() { assertEquals(Marker2Impl.class, getImpl(СlassWithPrivateInjectorConstructorAndTwoFields.class).getMarker2().getClass()); } class ClassWithTwoConstructors implements MainMarker { private Marker1 marker1; public ClassWithTwoConstructors() { } private ClassWithTwoConstructors(Marker1 marker) { this.marker1 = marker; } public Object getMarker1() { return marker1; } } @Test public void testWithTwoConstructors() { assertEquals(Marker1Impl.class, getImpl(ClassWithTwoConstructors.class).getMarker1().getClass()); } class ClassWithTwoConstructorsWitnSameParametersCount implements MainMarker { private Marker1 marker1; private ClassWithTwoConstructorsWitnSameParametersCount(Marker1 marker) { this.marker1 = marker; } private ClassWithTwoConstructorsWitnSameParametersCount(String string) { } public Object getMarker1() { return marker1; } } @Test public void testWithTwoConstructorsWithSameParametersCount() { assertEquals(Marker1Impl.class, getImpl(ClassWithTwoConstructorsWitnSameParametersCount.class).getMarker1().getClass()); } class ClassWithTwoFieldsAndOnlyOneInjectedViaConstructor implements MainMarker { private Marker1 marker1; private Marker2 marker2; private boolean costructorCall = false; private ClassWithTwoFieldsAndOnlyOneInjectedViaConstructor(Marker1 marker) { this.costructorCall = true; this.marker1 = marker; } public Object getMarker1() { return marker1; } public Object getMarker2() { return marker2; } public boolean isCostructorCall() { return costructorCall; } } @Test public void testWithTwoFieldsAndOnlyOneInjectedViaConstructor1() { assertEquals(Marker1Impl.class, getImpl(ClassWithTwoFieldsAndOnlyOneInjectedViaConstructor.class).getMarker1().getClass()); } @Test public void testWithTwoFieldsAndOnlyOneInjectedViaConstructor2() { assertEquals(Marker2Impl.class, getImpl(ClassWithTwoFieldsAndOnlyOneInjectedViaConstructor.class).getMarker2().getClass()); } @Test public void testWithTwoFieldsAndOnlyOneInjectedViaConstructor_constructorUsed() { assertTrue(getImpl(ClassWithTwoFieldsAndOnlyOneInjectedViaConstructor.class).isCostructorCall()); } class ClassWithTwoFieldsAndOtherOneInjectedViaConstructor implements MainMarker { private Marker1 marker1; private Marker2 marker2; private boolean costructorCall = false; private ClassWithTwoFieldsAndOtherOneInjectedViaConstructor(Marker2 marker) { this.costructorCall = true; this.marker2 = marker; } public Object getMarker1() { return marker1; } public Object getMarker2() { return marker2; } public boolean isCostructorCall() { return costructorCall; } } @Test public void testWithTwoFieldsAndOtherOneInjectedViaConstructor_CheckField1() { assertEquals(Marker1Impl.class, getImpl(ClassWithTwoFieldsAndOtherOneInjectedViaConstructor.class).getMarker1().getClass()); } @Test public void testWithTwoFieldsAndOtherOneInjectedViaConstructor_CheckField2() { assertEquals(Marker2Impl.class, getImpl(ClassWithTwoFieldsAndOtherOneInjectedViaConstructor.class).getMarker2().getClass()); } @Test public void testWithTwoFieldsAndOtherOneInjectedViaConstructor_constructorUsed() { assertTrue(getImpl(ClassWithTwoFieldsAndOtherOneInjectedViaConstructor.class).isCostructorCall()); } class ClassWithThreeFieldsAndOnlyOneInjectedViaConstructor implements MainMarker { private Marker1 marker1; private Marker2 marker2; private boolean costructorCall = false; private Marker3 marker3; private ClassWithThreeFieldsAndOnlyOneInjectedViaConstructor(Marker3 marker) { this.costructorCall = true; this.marker3 = marker; } public Object getMarker1() { return marker1; } public Object getMarker2() { return marker2; } public boolean isCostructorCall() { return costructorCall; } public Object getMarker3() { return marker3; } } @Test public void testWithThreeFieldsAndOtherOneInjectedViaConstructor_CheckField1() { assertEquals(Marker1Impl.class, getImpl(ClassWithThreeFieldsAndOnlyOneInjectedViaConstructor.class).getMarker1().getClass()); } @Test public void testWithThreeFieldsAndOtherOneInjectedViaConstructor_CheckField2() { assertEquals(Marker2Impl.class, getImpl(ClassWithThreeFieldsAndOnlyOneInjectedViaConstructor.class).getMarker2().getClass()); } @Test public void testWithThreeFieldsAndOtherOneInjectedViaConstructor_CheckField3() { assertEquals(Marker3Impl.class, getImpl(ClassWithThreeFieldsAndOnlyOneInjectedViaConstructor.class).getMarker3().getClass()); } @Test public void testWithThreeFieldsAndOtherOneInjectedViaConstructor_constructorUsed() { assertTrue(getImpl(ClassWithThreeFieldsAndOnlyOneInjectedViaConstructor.class).isCostructorCall()); } class Marker1Fasade implements Marker1 { private Marker1 marker; public Marker1Fasade(Marker1 marker) { this.marker = marker; } public Object getMarker() { return marker; } } class ClassWithTwoFieldsAndOnlyOneInjectedViaConstructorWithFasade implements MainMarker { private Marker1 marker1; private Marker2 marker2; private ClassWithTwoFieldsAndOnlyOneInjectedViaConstructorWithFasade(Marker1 marker) { this.marker1 = new Marker1Fasade(marker); } public Object getMarker1() { return marker1; } public Object getMarker2() { return marker2; } } @Test public void testWithTwoFieldsAndOnlyOneInjectedViaConstructorWithFasade_checkThatNoReflectionInjectionIfConstructorInjected() { ClassWithTwoFieldsAndOnlyOneInjectedViaConstructorWithFasade impl = getImpl(ClassWithTwoFieldsAndOnlyOneInjectedViaConstructorWithFasade.class); assertEquals(Marker1Fasade.class, impl.getMarker1().getClass()); assertEquals(Marker1Impl.class, ((Marker1Fasade)impl.getMarker1()).getMarker().getClass()); } class ClassWithThreeFieldsAndTwoInjectedViaConstructor implements MainMarker { private Marker3 marker3; private boolean costructorCall = false; private Marker1 marker1; private Marker2 marker2; private ClassWithThreeFieldsAndTwoInjectedViaConstructor(Marker3 marker3, Marker2 marker2) { this.costructorCall = true; this.marker3 = marker3; this.marker2 = marker2; } public Object getMarker1() { return marker1; } public Object getMarker2() { return marker2; } public boolean isCostructorCall() { return costructorCall; } public Object getMarker3() { return marker3; } } @Test public void testWithThreeFieldsAndTwoInjectedViaConstructor_CheckField1() { assertEquals(Marker1Impl.class, getImpl(ClassWithThreeFieldsAndTwoInjectedViaConstructor.class).getMarker1().getClass()); } @Test public void testWithThreeFieldsAndTwoInjectedViaConstructor_CheckField2() { assertEquals(Marker2Impl.class, getImpl(ClassWithThreeFieldsAndTwoInjectedViaConstructor.class).getMarker2().getClass()); } @Test public void testWithThreeFieldsAndTwoInjectedViaConstructor_CheckField3() { assertEquals(Marker3Impl.class, getImpl(ClassWithThreeFieldsAndTwoInjectedViaConstructor.class).getMarker3().getClass()); } @Test public void testWithThreeFieldsAndTwoInjectedViaConstructor_constructorUsed() { assertTrue(getImpl(ClassWithThreeFieldsAndTwoInjectedViaConstructor.class).isCostructorCall()); } class Marker3Fasade implements Marker3 { private Marker3 marker; public Marker3Fasade(Marker3 marker) { this.marker = marker; } public Object getMarker() { return marker; } } class ClassWithThreeFieldsAndTwoConstructors implements MainMarker { private Marker3 marker3; private boolean isCommonCostructorCall = false; private Marker1 marker1; private Marker2 marker2; private ClassWithThreeFieldsAndTwoConstructors(Marker1 marker1) { this.marker1 = marker1; } private ClassWithThreeFieldsAndTwoConstructors(Marker3 marker3, Marker2 marker2) { this.isCommonCostructorCall = true; this.marker3 = new Marker3Fasade(marker3); this.marker2 = marker2; } public Object getMarker1() { return marker1; } public Object getMarker2() { return marker2; } public boolean isCommonCostructorCall() { return isCommonCostructorCall; } public Object getMarker3() { return marker3; } } @Test public void testWithThreeFieldsAndTwoConstructors_CheckField1() { assertEquals(Marker1Impl.class, getImpl(ClassWithThreeFieldsAndTwoConstructors.class).getMarker1().getClass()); } @Test public void testWithThreeFieldsAndTwoConstructors_CheckField2() { assertEquals(Marker2Impl.class, getImpl(ClassWithThreeFieldsAndTwoConstructors.class).getMarker2().getClass()); } @Test public void testWithThreeFieldsAndTwoConstructors_CheckField3() { ClassWithThreeFieldsAndTwoConstructors impl = getImpl(ClassWithThreeFieldsAndTwoConstructors.class); assertEquals(Marker3Fasade.class, impl.getMarker3().getClass()); assertEquals(Marker3Impl.class, ((Marker3Fasade)impl.getMarker3()).getMarker().getClass()); } @Test public void testWithThreeFieldsAndTwoConstructors_constructorUsed() { assertTrue(getImpl(ClassWithThreeFieldsAndTwoConstructors.class).isCommonCostructorCall()); } class ClassWithThreeFieldsAndThreeConstructorsOneIsNotUsed implements MainMarker { private Marker3 marker3; private boolean isCommonCostructorCall = false; private Marker1 marker1; private Marker2 marker2; private ClassWithThreeFieldsAndThreeConstructorsOneIsNotUsed(Marker1 marker1) { this.marker1 = marker1; } private ClassWithThreeFieldsAndThreeConstructorsOneIsNotUsed(Marker3 marker3, Marker2 marker2) { this.isCommonCostructorCall = true; this.marker3 = new Marker3Fasade(marker3); this.marker2 = marker2; } private ClassWithThreeFieldsAndThreeConstructorsOneIsNotUsed(Marker3 marker3, Marker2 marker2, String bla) { this.marker3 = marker3; this.marker2 = marker2; } public Object getMarker1() { return marker1; } public Object getMarker2() { return marker2; } public boolean isCommonCostructorCall() { return isCommonCostructorCall; } public Object getMarker3() { return marker3; } } @Test public void testWithThreeFieldsAndThreeConstructorsOneIsNotUsed_CheckField1() { assertEquals(Marker1Impl.class, getImpl(ClassWithThreeFieldsAndThreeConstructorsOneIsNotUsed.class).getMarker1().getClass()); } @Test public void testWithThreeFieldsAndThreeConstructorsOneIsNotUsed_CheckField2() { assertEquals(Marker2Impl.class, getImpl(ClassWithThreeFieldsAndThreeConstructorsOneIsNotUsed.class).getMarker2().getClass()); } @Test public void testWithThreeFieldsAndThreeConstructorsOneIsNotUsed_CheckField3() { ClassWithThreeFieldsAndThreeConstructorsOneIsNotUsed impl = getImpl(ClassWithThreeFieldsAndThreeConstructorsOneIsNotUsed.class); assertEquals(Marker3Fasade.class, impl.getMarker3().getClass()); assertEquals(Marker3Impl.class, ((Marker3Fasade)impl.getMarker3()).getMarker().getClass()); } @Test public void testWithThreeFieldsAndThreeConstructorsOneIsNotUsed_constructorUsed() { assertTrue(getImpl(ClassWithThreeFieldsAndThreeConstructorsOneIsNotUsed.class).isCommonCostructorCall()); } }
Постепенно появлялась реализация. После несокльких подходов к коду я родил вот эти реализации
package container.ioc; public class Binder { Class<?> interfaceClass; Class<?> classToCreate; Object object; public Binder(Class<?> classToCreate) { this.classToCreate = classToCreate; } public Binder(Object object) { this.object = object; } public static Binder use(Class<?> classToCreate) { return new Binder(classToCreate); } public static Binder use(Object object) { return new Binder(object); } public Binder as(Class<?> interfaceClass) { this.interfaceClass = interfaceClass; return this; } }
package container.ioc; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.LinkedList; import java.util.List; public class ContainerImpl implements Container { private Collection<Binder> binders; public ContainerImpl(Binder...binders) { this.binders = new LinkedList<Binder>(Arrays.asList(binders)); } @Override public <T> T get(Class<T> interfaceClass) { Binder binder = find(interfaceClass); if (binder.object != null) { return (T) binder.object; } Class<?> classToCreate = binder.classToCreate; List<Constructor<?>> constructors = getCostructors(classToCreate); List<Object> dependencies = getObjectsFor(onlyInterfaceTypes(getTypes(getFields(classToCreate)))); return (T) foundCommonConstructor(constructors, dependencies).newInstanceFor(dependencies); } private InstanceMaker foundCommonConstructor( List<Constructor<?>> constructors, List<Object> dependencies) { sortByParameterCount(constructors); for (Constructor<?> constructor : constructors) { if (sufficiently(constructor.getParameterTypes(), dependencies)) { return new InstanceMaker(constructor); } } throw new RuntimeException("Constructor not found"); } private void sortByParameterCount(List<Constructor<?>> constructors) { Collections.sort(constructors, new Comparator<Constructor<?>>() { @Override public int compare(Constructor<?> constructor1, Constructor<?> constructor2) { return constructor2.getParameterTypes().length - constructor1.getParameterTypes().length; } }); } private boolean sufficiently(Class<?>[] parameterTypes, List<Object> dependencies) { for (Class<?> clazz : parameterTypes) { if (notIn(clazz, dependencies)) { return false; } } return true; } private boolean notIn(Class<?> clazz, List<Object> dependencies) { for (Object dependency : dependencies) { if (clazz.isAssignableFrom(dependency.getClass())) { return false; } } return true; } private List<Class<?>> getTypes(Collection<Field> fields) { List<Class<?>> result = new LinkedList<Class<?>>(); for (Field field : fields) { result.add(field.getType()); } return result; } private List<Class<?>> onlyInterfaceTypes(List<Class<?>> classes) { List<Class<?>> result = new LinkedList<Class<?>>(); for (Class<?> clazz : classes) { try { find(clazz); result.add(clazz); } catch (RuntimeException e) { continue; } } return result; } private Binder find(Class<?> interfaceClass) { for (Binder binder : binders) { if (binder.interfaceClass.equals(interfaceClass)) { return binder; } } throw new RuntimeException("Dependency class not found for interface" + interfaceClass.getName()); } private List<Object> getObjectsFor(List<Class<?>> parameterTypes) { List<Object> result = new LinkedList<Object>(); for (Class<?> clazz : parameterTypes) { result.add(get(clazz)); } return result; } private List<Constructor<?>> getCostructors(Class<?> classToCreate) { return Arrays.asList(classToCreate.getDeclaredConstructors()); } private Collection<Field> getFields(Class<?> classToCreate) { return Arrays.asList(classToCreate.getDeclaredFields()); } @Override public void remove(Class<?> clazz) { for (Binder binder : binders) { if (binder.interfaceClass.equals(clazz)) { binders.remove(binder); return; } } } @Override public void update(Binder binder) { remove(binder.interfaceClass); binders.add(binder); } }
package container.ioc; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.LinkedList; import java.util.List; public class InstanceMaker { private Constructor<?> constructor; public InstanceMaker(Constructor<?> constructor) { this.constructor = constructor; } public Object newInstanceFor(List<Object> dependencies) { List<Object> foundDependencies = getDependenciesFor(constructor, dependencies); Object object = getObject(constructor, foundDependencies); dependencies.removeAll(foundDependencies); return injectToField(object, dependencies); } private List<Object> getDependenciesFor(Constructor<?> constructor, List<Object> dependencies) { List<Object> result = new LinkedList<Object> (); for (Class<?> parameterType : constructor.getParameterTypes()) { for (Object dependency : dependencies) { if (parameterType.isAssignableFrom(dependency.getClass())) { result.add(dependency); break; } } } return result; } private Object getObject(Constructor<?> constructor, List<Object> dependencies) { try { constructor.setAccessible(true); Object newInstance = constructor.newInstance(dependencies.toArray(new Object[0])); constructor.setAccessible(false); return newInstance; } catch (IllegalArgumentException e) { throw new RuntimeException(e); } catch (InstantiationException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { throw new RuntimeException(e); } } private <T> T injectToField(T object, List<Object> dependencies) { for (Object dependency : dependencies) { Injector.injectAll(object, dependency); } return object; } }
Классы достаточно сложновастые, но рефлексия все же. Библиотеку Fest Reflection я не хотел подключать из за лишней jar-dependency. В следующий раз попробую сделаю с ней - за одно попиарю этот классный инструмент для работы с рефлексией.
В будущих планах есть сделать то же но со Spring IoC. Ждите, продолжение следует..
Комментариев нет:
Отправить комментарий