From 23c83955bcd4371d3ce217268b1ccc3bf819e766 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4?= Date: Thu, 3 Aug 2023 13:39:38 +0300 Subject: [PATCH 1/8] changed java version from 11 to 17 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5a9247c52..6b87b67bc 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ - 11 + 17 UTF-8 UTF-8 3.1.1 From a73b40223a3f85b7cb84ccd163ebc6136c9c312e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4?= Date: Thu, 3 Aug 2023 13:40:33 +0300 Subject: [PATCH 2/8] completed @Inject and @Component annotations --- src/main/java/mate.academy/lib/Component.java | 8 +++++++- src/main/java/mate.academy/lib/Inject.java | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/main/java/mate.academy/lib/Component.java b/src/main/java/mate.academy/lib/Component.java index c7e830420..8bcd94af1 100644 --- a/src/main/java/mate.academy/lib/Component.java +++ b/src/main/java/mate.academy/lib/Component.java @@ -1,5 +1,11 @@ package mate.academy.lib; -public @interface Component { +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface Component { } diff --git a/src/main/java/mate.academy/lib/Inject.java b/src/main/java/mate.academy/lib/Inject.java index 1741f9df9..295195fee 100644 --- a/src/main/java/mate.academy/lib/Inject.java +++ b/src/main/java/mate.academy/lib/Inject.java @@ -1,5 +1,11 @@ package mate.academy.lib; -public @interface Inject { +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface Inject { } From a9680e42b7e9c625d294515606231f4e3ea4fcfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4?= Date: Thu, 3 Aug 2023 13:41:19 +0300 Subject: [PATCH 3/8] integrate @Inject and @Component annotations --- .../mate.academy/service/impl/FileReaderServiceImpl.java | 2 ++ .../java/mate.academy/service/impl/ProductParserImpl.java | 2 ++ .../java/mate.academy/service/impl/ProductServiceImpl.java | 5 +++++ 3 files changed, 9 insertions(+) diff --git a/src/main/java/mate.academy/service/impl/FileReaderServiceImpl.java b/src/main/java/mate.academy/service/impl/FileReaderServiceImpl.java index 58540d301..752474e0d 100644 --- a/src/main/java/mate.academy/service/impl/FileReaderServiceImpl.java +++ b/src/main/java/mate.academy/service/impl/FileReaderServiceImpl.java @@ -4,8 +4,10 @@ import java.io.IOException; import java.nio.file.Files; import java.util.List; +import mate.academy.lib.Component; import mate.academy.service.FileReaderService; +@Component public class FileReaderServiceImpl implements FileReaderService { @Override public List readFile(String fileName) { diff --git a/src/main/java/mate.academy/service/impl/ProductParserImpl.java b/src/main/java/mate.academy/service/impl/ProductParserImpl.java index 00837f28d..03ea21a56 100644 --- a/src/main/java/mate.academy/service/impl/ProductParserImpl.java +++ b/src/main/java/mate.academy/service/impl/ProductParserImpl.java @@ -1,9 +1,11 @@ package mate.academy.service.impl; import java.math.BigDecimal; +import mate.academy.lib.Component; import mate.academy.model.Product; import mate.academy.service.ProductParser; +@Component public class ProductParserImpl implements ProductParser { public static final int ID_POSITION = 0; public static final int NAME_POSITION = 1; diff --git a/src/main/java/mate.academy/service/impl/ProductServiceImpl.java b/src/main/java/mate.academy/service/impl/ProductServiceImpl.java index 755304777..425ca5552 100644 --- a/src/main/java/mate.academy/service/impl/ProductServiceImpl.java +++ b/src/main/java/mate.academy/service/impl/ProductServiceImpl.java @@ -2,13 +2,18 @@ import java.util.List; import java.util.stream.Collectors; +import mate.academy.lib.Component; +import mate.academy.lib.Inject; import mate.academy.model.Product; import mate.academy.service.FileReaderService; import mate.academy.service.ProductParser; import mate.academy.service.ProductService; +@Component public class ProductServiceImpl implements ProductService { + @Inject private ProductParser productParser; + @Inject private FileReaderService fileReaderService; @Override From ab51f7285aba36e075f15eafb5d08d0db7732f38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4?= Date: Thu, 3 Aug 2023 13:41:53 +0300 Subject: [PATCH 4/8] completed Injector class --- src/main/java/mate.academy/lib/Injector.java | 128 ++++++++++++++++++- 1 file changed, 127 insertions(+), 1 deletion(-) diff --git a/src/main/java/mate.academy/lib/Injector.java b/src/main/java/mate.academy/lib/Injector.java index e87b914ad..e99919556 100644 --- a/src/main/java/mate.academy/lib/Injector.java +++ b/src/main/java/mate.academy/lib/Injector.java @@ -1,13 +1,139 @@ package mate.academy.lib; +import java.io.File; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + public class Injector { private static final Injector injector = new Injector(); + private static final Map, Class> interfacesImplementations; + private static final Map, Object> instances = new HashMap<>(); + private static final String SERVICE_PACKAGE = "mate.academy.service"; + private static final String SERVICE_PACKAGE_IMPL = "mate.academy.service.impl"; + private static final String CLASS_INDICATOR = ".class"; + + static { + interfacesImplementations = interfacesImplementationsConfiguration(); + } public static Injector getInjector() { return injector; } public Object getInstance(Class interfaceClazz) { - return null; + Object clazzImplementationInstance = null; + Class clazz = findImplementation(interfaceClazz); + Field[] fields = clazz.getDeclaredFields(); + for (Field field : fields) { + if (field.isAnnotationPresent(Inject.class)) { + Object fieldInstance = getInstance(field.getType()); + clazzImplementationInstance = createNewInstance(clazz); + field.setAccessible(true); + try { + field.set(clazzImplementationInstance, fieldInstance); + } catch (IllegalAccessException e) { + throw new RuntimeException("Can't initialize field value. Class: " + + clazz.getName() + ", field: " + field.getName()); + } + } + } + if (clazzImplementationInstance == null) { + clazzImplementationInstance = createNewInstance(clazz); + } + return clazzImplementationInstance; + } + + private static Object createNewInstance(Class clazz) { + if (instances.containsKey(clazz)) { + return instances.get(clazz); + } + try { + Constructor constructor = clazz.getConstructor(); + Object instance = constructor.newInstance(); + instances.put(clazz, instance); + return instance; + } catch (ReflectiveOperationException e) { + throw new RuntimeException("Can't create new instance of class - " + clazz.getName()); + } + } + + private static Class findImplementation(Class interfaceClazz) { + if (interfaceClazz.isInterface()) { + if (!interfacesImplementations.containsKey(interfaceClazz)) { + throw new RuntimeException("Can`t find interface " + interfaceClazz.getName()); + } + Class implementation = interfacesImplementations.get(interfaceClazz); + if (implementation == null) { + throw new RuntimeException("Interface " + interfaceClazz.getName() + + " has no implementations or they doesn't annotated by @Component"); + } + return implementation; + } + componentCheck(interfaceClazz); + return interfaceClazz; + } + + private static Map, Class> interfacesImplementationsConfiguration() { + Map, Class> interfacesImplementations = new HashMap<>(); + for (Class clazzInterface : findServiceInterfaces()) { + Class interfaceImplementation = null; + for (Class clazzImplementation : findComponents()) { + if (clazzInterface.isAssignableFrom(clazzImplementation)) { + interfaceImplementation = clazzImplementation; + break; + } + } + System.out.println(clazzInterface + " " + interfaceImplementation); + interfacesImplementations.put(clazzInterface, interfaceImplementation); + } + return interfacesImplementations; + } + + private static List> findComponents() { + return findClassesByPackage(SERVICE_PACKAGE_IMPL).stream() + .filter(clazz -> clazz.isAnnotationPresent(Component.class)) + .toList(); + } + + private static List> findServiceInterfaces() { + return findClassesByPackage(SERVICE_PACKAGE).stream() + .filter(Class::isInterface) + .toList(); + } + + public static List> findClassesByPackage(String packageName) { + String path = packageName.replace('.', '/'); + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + File packageDirectory = new File(classLoader.getResource(path).getFile()); + File[] files = packageDirectory.listFiles(); + return Arrays.stream(files) + .filter(File::isFile) + .filter(file -> file.getName().endsWith(CLASS_INDICATOR)) + .map(file -> getClass(file.getName(), packageName)) + .collect(Collectors.toList()); + } + + private static Class getClass(String className, String packageName) { + try { + String clearedClassName = className.substring(0, + className.length() - CLASS_INDICATOR.length()); + return Class.forName(packageName + "." + clearedClassName); + } catch (ClassNotFoundException e) { + throw new RuntimeException("Can't find class " + className); + } + } + + private static void componentCheck(Class clazz) { + if (!clazz.isAnnotationPresent(Component.class)) { + throw new RuntimeException("Unsupported class " + clazz + + ", should be annotated by @Component"); + } + } } + From 4c63ad83a528bdc97e8a163bb72c7ad0186e2583 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4?= Date: Thu, 3 Aug 2023 13:42:30 +0300 Subject: [PATCH 5/8] initialized ProductService --- src/main/java/mate.academy/Main.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/mate.academy/Main.java b/src/main/java/mate.academy/Main.java index 9be740020..62ebf42e6 100644 --- a/src/main/java/mate.academy/Main.java +++ b/src/main/java/mate.academy/Main.java @@ -10,7 +10,7 @@ public class Main { public static void main(String[] args) { // Please test your Injector here. Feel free to push this class as a part of your solution Injector injector = Injector.getInjector(); - ProductService productService = null; + ProductService productService = (ProductService) injector.getInstance(ProductService.class); List products = productService.getAllFromFile("products.txt"); products.forEach(System.out::println); } From 9ac9ff348adcf9c1ca6b83f51ed1f1f1b8ffb15c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4?= Date: Fri, 4 Aug 2023 22:14:20 +0300 Subject: [PATCH 6/8] fixed after review --- src/main/java/mate.academy/lib/Injector.java | 107 ++++++------------- 1 file changed, 30 insertions(+), 77 deletions(-) diff --git a/src/main/java/mate.academy/lib/Injector.java b/src/main/java/mate.academy/lib/Injector.java index e99919556..b09c4e59c 100644 --- a/src/main/java/mate.academy/lib/Injector.java +++ b/src/main/java/mate.academy/lib/Injector.java @@ -1,28 +1,27 @@ package mate.academy.lib; -import java.io.File; import java.lang.reflect.Constructor; import java.lang.reflect.Field; -import java.util.Arrays; import java.util.HashMap; -import java.util.List; import java.util.Map; -import java.util.stream.Collectors; +import mate.academy.service.FileReaderService; +import mate.academy.service.ProductParser; +import mate.academy.service.ProductService; +import mate.academy.service.impl.FileReaderServiceImpl; +import mate.academy.service.impl.ProductParserImpl; +import mate.academy.service.impl.ProductServiceImpl; public class Injector { - private static final Injector injector = new Injector(); - private static final Map, Class> interfacesImplementations; - private static final Map, Object> instances = new HashMap<>(); - private static final String SERVICE_PACKAGE = "mate.academy.service"; - private static final String SERVICE_PACKAGE_IMPL = "mate.academy.service.impl"; - private static final String CLASS_INDICATOR = ".class"; + private static final Injector INJECTOR = new Injector(); + private static final Map, Class> INTERFACES_IMPLEMENTATIONS; + private static final Map, Object> INSTANCES = new HashMap<>(); static { - interfacesImplementations = interfacesImplementationsConfiguration(); + INTERFACES_IMPLEMENTATIONS = interfacesImplementationsConfig(); } public static Injector getInjector() { - return injector; + return INJECTOR; } public Object getInstance(Class interfaceClazz) { @@ -42,20 +41,18 @@ public Object getInstance(Class interfaceClazz) { } } } - if (clazzImplementationInstance == null) { - clazzImplementationInstance = createNewInstance(clazz); - } - return clazzImplementationInstance; + return clazzImplementationInstance == null ? createNewInstance(clazz) + : clazzImplementationInstance; } private static Object createNewInstance(Class clazz) { - if (instances.containsKey(clazz)) { - return instances.get(clazz); + if (INSTANCES.containsKey(clazz)) { + return INSTANCES.get(clazz); } try { Constructor constructor = clazz.getConstructor(); Object instance = constructor.newInstance(); - instances.put(clazz, instance); + INSTANCES.put(clazz, instance); return instance; } catch (ReflectiveOperationException e) { throw new RuntimeException("Can't create new instance of class - " + clazz.getName()); @@ -64,76 +61,32 @@ private static Object createNewInstance(Class clazz) { private static Class findImplementation(Class interfaceClazz) { if (interfaceClazz.isInterface()) { - if (!interfacesImplementations.containsKey(interfaceClazz)) { - throw new RuntimeException("Can`t find interface " + interfaceClazz.getName()); - } - Class implementation = interfacesImplementations.get(interfaceClazz); - if (implementation == null) { - throw new RuntimeException("Interface " + interfaceClazz.getName() - + " has no implementations or they doesn't annotated by @Component"); - } - return implementation; + interfaceCheck(interfaceClazz); + interfaceClazz = INTERFACES_IMPLEMENTATIONS.get(interfaceClazz); } componentCheck(interfaceClazz); return interfaceClazz; } - private static Map, Class> interfacesImplementationsConfiguration() { - Map, Class> interfacesImplementations = new HashMap<>(); - for (Class clazzInterface : findServiceInterfaces()) { - Class interfaceImplementation = null; - for (Class clazzImplementation : findComponents()) { - if (clazzInterface.isAssignableFrom(clazzImplementation)) { - interfaceImplementation = clazzImplementation; - break; - } - } - System.out.println(clazzInterface + " " + interfaceImplementation); - interfacesImplementations.put(clazzInterface, interfaceImplementation); - } - return interfacesImplementations; - } - - private static List> findComponents() { - return findClassesByPackage(SERVICE_PACKAGE_IMPL).stream() - .filter(clazz -> clazz.isAnnotationPresent(Component.class)) - .toList(); - } - - private static List> findServiceInterfaces() { - return findClassesByPackage(SERVICE_PACKAGE).stream() - .filter(Class::isInterface) - .toList(); - } - - public static List> findClassesByPackage(String packageName) { - String path = packageName.replace('.', '/'); - ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); - File packageDirectory = new File(classLoader.getResource(path).getFile()); - File[] files = packageDirectory.listFiles(); - return Arrays.stream(files) - .filter(File::isFile) - .filter(file -> file.getName().endsWith(CLASS_INDICATOR)) - .map(file -> getClass(file.getName(), packageName)) - .collect(Collectors.toList()); - } - - private static Class getClass(String className, String packageName) { - try { - String clearedClassName = className.substring(0, - className.length() - CLASS_INDICATOR.length()); - return Class.forName(packageName + "." + clearedClassName); - } catch (ClassNotFoundException e) { - throw new RuntimeException("Can't find class " + className); - } + private static Map, Class> interfacesImplementationsConfig() { + Map, Class> map = new HashMap<>(); + map.put(FileReaderService.class, FileReaderServiceImpl.class); + map.put(ProductParser.class, ProductParserImpl.class); + map.put(ProductService.class, ProductServiceImpl.class); + return map; } private static void componentCheck(Class clazz) { if (!clazz.isAnnotationPresent(Component.class)) { - throw new RuntimeException("Unsupported class " + clazz + throw new RuntimeException("Unsupported class - " + clazz + ", should be annotated by @Component"); } + } + private static void interfaceCheck(Class clazz) { + if (!INTERFACES_IMPLEMENTATIONS.containsKey(clazz)) { + throw new RuntimeException("Unsupported interface - " + clazz.getName()); + } } } From 79446d55d2076232d12afa170e845949a87101ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4?= Date: Tue, 8 Aug 2023 17:09:56 +0300 Subject: [PATCH 7/8] fixed after review --- src/main/java/mate.academy/lib/Injector.java | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/src/main/java/mate.academy/lib/Injector.java b/src/main/java/mate.academy/lib/Injector.java index b09c4e59c..883725894 100644 --- a/src/main/java/mate.academy/lib/Injector.java +++ b/src/main/java/mate.academy/lib/Injector.java @@ -13,13 +13,12 @@ public class Injector { private static final Injector INJECTOR = new Injector(); - private static final Map, Class> INTERFACES_IMPLEMENTATIONS; + private static final Map, Class> INTERFACES_IMPLEMENTATIONS = Map.of( + FileReaderService.class, FileReaderServiceImpl.class, + ProductParser.class, ProductParserImpl.class, + ProductService.class, ProductServiceImpl.class); private static final Map, Object> INSTANCES = new HashMap<>(); - static { - INTERFACES_IMPLEMENTATIONS = interfacesImplementationsConfig(); - } - public static Injector getInjector() { return INJECTOR; } @@ -68,14 +67,6 @@ private static Class findImplementation(Class interfaceClazz) { return interfaceClazz; } - private static Map, Class> interfacesImplementationsConfig() { - Map, Class> map = new HashMap<>(); - map.put(FileReaderService.class, FileReaderServiceImpl.class); - map.put(ProductParser.class, ProductParserImpl.class); - map.put(ProductService.class, ProductServiceImpl.class); - return map; - } - private static void componentCheck(Class clazz) { if (!clazz.isAnnotationPresent(Component.class)) { throw new RuntimeException("Unsupported class - " + clazz From a12295620e11bc236889db374c9e7a678bf9757c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4?= Date: Tue, 8 Aug 2023 21:45:10 +0300 Subject: [PATCH 8/8] removed static modification for private methods --- src/main/java/mate.academy/lib/Injector.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/mate.academy/lib/Injector.java b/src/main/java/mate.academy/lib/Injector.java index 883725894..8e7027fe9 100644 --- a/src/main/java/mate.academy/lib/Injector.java +++ b/src/main/java/mate.academy/lib/Injector.java @@ -44,7 +44,7 @@ public Object getInstance(Class interfaceClazz) { : clazzImplementationInstance; } - private static Object createNewInstance(Class clazz) { + private Object createNewInstance(Class clazz) { if (INSTANCES.containsKey(clazz)) { return INSTANCES.get(clazz); } @@ -58,7 +58,7 @@ private static Object createNewInstance(Class clazz) { } } - private static Class findImplementation(Class interfaceClazz) { + private Class findImplementation(Class interfaceClazz) { if (interfaceClazz.isInterface()) { interfaceCheck(interfaceClazz); interfaceClazz = INTERFACES_IMPLEMENTATIONS.get(interfaceClazz); @@ -67,14 +67,14 @@ private static Class findImplementation(Class interfaceClazz) { return interfaceClazz; } - private static void componentCheck(Class clazz) { + private void componentCheck(Class clazz) { if (!clazz.isAnnotationPresent(Component.class)) { throw new RuntimeException("Unsupported class - " + clazz + ", should be annotated by @Component"); } } - private static void interfaceCheck(Class clazz) { + private void interfaceCheck(Class clazz) { if (!INTERFACES_IMPLEMENTATIONS.containsKey(clazz)) { throw new RuntimeException("Unsupported interface - " + clazz.getName()); }