From 701d981e185834dbfd82635ea45d383b84b76e87 Mon Sep 17 00:00:00 2001 From: alekulikov Date: Sat, 9 Mar 2024 17:33:49 +0300 Subject: [PATCH] add hw13-di --- .../AppComponentsContainerImpl.java | 65 +++++++++++++++++-- .../AppComponentContainerException.java | 11 ++++ hw13-di/src/test/java/ru/otus/AppTest.java | 4 -- 3 files changed, 69 insertions(+), 11 deletions(-) create mode 100644 hw13-di/src/main/java/ru/otus/appcontainer/exception/AppComponentContainerException.java diff --git a/hw13-di/src/main/java/ru/otus/appcontainer/AppComponentsContainerImpl.java b/hw13-di/src/main/java/ru/otus/appcontainer/AppComponentsContainerImpl.java index d6c21e9..262c3b1 100644 --- a/hw13-di/src/main/java/ru/otus/appcontainer/AppComponentsContainerImpl.java +++ b/hw13-di/src/main/java/ru/otus/appcontainer/AppComponentsContainerImpl.java @@ -1,11 +1,12 @@ package ru.otus.appcontainer; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.*; +import ru.otus.appcontainer.api.AppComponent; import ru.otus.appcontainer.api.AppComponentsContainer; import ru.otus.appcontainer.api.AppComponentsContainerConfig; +import ru.otus.appcontainer.exception.AppComponentContainerException; @SuppressWarnings("squid:S1068") public class AppComponentsContainerImpl implements AppComponentsContainer { @@ -19,7 +20,24 @@ public AppComponentsContainerImpl(Class initialConfigClass) { private void processConfig(Class configClass) { checkConfigClass(configClass); - // You code here... + var config = getConfigObject(configClass); + var componentsInitMethods = Arrays.stream(configClass.getMethods()) + .filter(method -> method.isAnnotationPresent(AppComponent.class)) + .sorted(Comparator.comparingInt( + method -> method.getAnnotation(AppComponent.class).order())) + .toList(); + for (Method componentInitMethod : componentsInitMethods) { + var componentName = + componentInitMethod.getAnnotation(AppComponent.class).name(); + if (!appComponentsByName.containsKey(componentName)) { + var component = initComponent(componentInitMethod, config); + appComponents.add(component); + appComponentsByName.put(componentName, component); + } else { + throw new AppComponentContainerException( + String.format("Component with name %s already exist", componentName)); + } + } } private void checkConfigClass(Class configClass) { @@ -28,13 +46,46 @@ private void checkConfigClass(Class configClass) { } } + private Object getConfigObject(Class configClass) { + try { + return configClass.getDeclaredConstructor().newInstance(); + } catch (Exception e) { + throw new AppComponentContainerException( + String.format("Config %s cannot be create", configClass.getName()), e); + } + } + + private Object initComponent(Method componentInitMethod, Object config) { + var parameters = Arrays.stream(componentInitMethod.getParameterTypes()) + .map(this::getAppComponent) + .toArray(); + try { + return componentInitMethod.invoke(config, parameters); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new AppComponentContainerException( + String.format("Method %s cannot be invoke", componentInitMethod.getName()), e); + } + } + @Override public C getAppComponent(Class componentClass) { - return null; + var components = + appComponents.stream().filter(componentClass::isInstance).toList(); + if (components.isEmpty()) { + throw new AppComponentContainerException(String.format("Component %s not found", componentClass.getName())); + } else if (components.size() > 1) { + throw new AppComponentContainerException( + String.format("More than one component %s found", componentClass.getName())); + } + return (C) components.get(0); } @Override public C getAppComponent(String componentName) { - return null; + if (appComponentsByName.containsKey(componentName)) { + return (C) appComponentsByName.get(componentName); + } else { + throw new AppComponentContainerException(String.format("Component %s not found", componentName)); + } } } diff --git a/hw13-di/src/main/java/ru/otus/appcontainer/exception/AppComponentContainerException.java b/hw13-di/src/main/java/ru/otus/appcontainer/exception/AppComponentContainerException.java new file mode 100644 index 0000000..a3bf0b5 --- /dev/null +++ b/hw13-di/src/main/java/ru/otus/appcontainer/exception/AppComponentContainerException.java @@ -0,0 +1,11 @@ +package ru.otus.appcontainer.exception; + +public class AppComponentContainerException extends RuntimeException { + public AppComponentContainerException(String message) { + super(message); + } + + public AppComponentContainerException(String message, Exception cause) { + super(message, cause); + } +} diff --git a/hw13-di/src/test/java/ru/otus/AppTest.java b/hw13-di/src/test/java/ru/otus/AppTest.java index c9c4d44..7252f54 100644 --- a/hw13-di/src/test/java/ru/otus/AppTest.java +++ b/hw13-di/src/test/java/ru/otus/AppTest.java @@ -8,7 +8,6 @@ import java.util.Arrays; import java.util.Scanner; import java.util.stream.Collectors; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -21,7 +20,6 @@ class AppTest { - @Disabled("Эту аннотацию надо убрать") @DisplayName("Из контекста тремя способами должен корректно доставаться компонент с проставленными полями") @ParameterizedTest(name = "Достаем по: {0}") @CsvSource( @@ -74,7 +72,6 @@ void shouldExtractFromContextCorrectComponentWithNotNullFields(String classNameO } } - @Disabled("Эту аннотацию надо убрать") @DisplayName("В контексте не должно быть компонентов с одинаковым именем") @Test void shouldNotAllowTwoComponentsWithSameName() { @@ -82,7 +79,6 @@ void shouldNotAllowTwoComponentsWithSameName() { .isInstanceOf(Exception.class); } - @Disabled("Эту аннотацию надо убрать") @DisplayName( "При попытке достать из контекста отсутствующий или дублирующийся компонент, должно выкидываться исключение") @Test