From 5fd2bfd7ed396658a6ad6ed1b4a38b720a6ab87f Mon Sep 17 00:00:00 2001 From: rus1980707 Date: Thu, 3 Oct 2024 18:36:54 +0300 Subject: [PATCH 1/2] jv-dependency-injection --- src/main/java/mate.academy/Main.java | 3 +- src/main/java/mate.academy/lib/Component.java | 5 +- src/main/java/mate.academy/lib/Inject.java | 5 +- src/main/java/mate.academy/lib/Injector.java | 57 ++++++++++++++++++- .../service/impl/FileReaderServiceImpl.java | 2 + .../service/impl/ProductParserImpl.java | 2 + .../service/impl/ProductServiceImpl.java | 5 ++ 7 files changed, 74 insertions(+), 5 deletions(-) diff --git a/src/main/java/mate.academy/Main.java b/src/main/java/mate.academy/Main.java index 9be740020..4afee2f36 100644 --- a/src/main/java/mate.academy/Main.java +++ b/src/main/java/mate.academy/Main.java @@ -8,9 +8,8 @@ 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); } diff --git a/src/main/java/mate.academy/lib/Component.java b/src/main/java/mate.academy/lib/Component.java index c7e830420..563153122 100644 --- a/src/main/java/mate.academy/lib/Component.java +++ b/src/main/java/mate.academy/lib/Component.java @@ -1,5 +1,8 @@ package mate.academy.lib; -public @interface Component { +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +@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..dfd2a0486 100644 --- a/src/main/java/mate.academy/lib/Inject.java +++ b/src/main/java/mate.academy/lib/Inject.java @@ -1,5 +1,8 @@ package mate.academy.lib; -public @interface Inject { +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +@Retention(RetentionPolicy.RUNTIME) +public @interface Inject { } diff --git a/src/main/java/mate.academy/lib/Injector.java b/src/main/java/mate.academy/lib/Injector.java index e87b914ad..cec70a690 100644 --- a/src/main/java/mate.academy/lib/Injector.java +++ b/src/main/java/mate.academy/lib/Injector.java @@ -1,13 +1,68 @@ package mate.academy.lib; +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; + public class Injector { private static final Injector injector = new Injector(); + private final Map, Object> instances = new HashMap<>(); public static Injector getInjector() { return injector; } public Object getInstance(Class interfaceClazz) { - return null; + // Try to resolve implementation for the given interface + Class implClass = findImplementation(interfaceClazz); + + // Check if class is annotated with @Component + if (!implClass.isAnnotationPresent(Component.class)) { + throw new RuntimeException("Class " + implClass.getName() + + " is not marked as @Component"); + } + + // Check if an instance already exists + if (instances.containsKey(implClass)) { + return instances.get(implClass); + } + + // Create a new instance and inject dependencies + Object instance = createInstance(implClass); + instances.put(implClass, instance); + return instance; + } + + private Object createInstance(Class implClass) { + try { + Object instance = implClass.getDeclaredConstructor().newInstance(); + + // Inject dependencies into fields annotated with @Inject + for (Field field : implClass.getDeclaredFields()) { + if (field.isAnnotationPresent(Inject.class)) { + field.setAccessible(true); + Object fieldInstance = getInstance(field.getType()); + field.set(instance, fieldInstance); + } + } + + return instance; + } catch (Exception e) { + throw new RuntimeException("Failed to create instance of " + implClass.getName(), e); + } + } + + private Class findImplementation(Class interfaceClazz) { + if (interfaceClazz.isInterface()) { + if (interfaceClazz == mate.academy.service.FileReaderService.class) { + return mate.academy.service.impl.FileReaderServiceImpl.class; + } else if (interfaceClazz == mate.academy.service.ProductParser.class) { + return mate.academy.service.impl.ProductParserImpl.class; + } else if (interfaceClazz == mate.academy.service.ProductService.class) { + return mate.academy.service.impl.ProductServiceImpl.class; + } + throw new RuntimeException("No implementation found for " + interfaceClazz.getName()); + } + return interfaceClazz; } } 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 9320432576d030ebf7d2a147301a0f584e0be661 Mon Sep 17 00:00:00 2001 From: rus1980707 Date: Thu, 3 Oct 2024 19:05:02 +0300 Subject: [PATCH 2/2] jv-dependency-injection --- src/main/java/mate.academy/lib/Component.java | 3 +++ src/main/java/mate.academy/lib/Inject.java | 3 +++ src/main/java/mate.academy/lib/Injector.java | 5 ----- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/mate.academy/lib/Component.java b/src/main/java/mate.academy/lib/Component.java index 563153122..46e39cec8 100644 --- a/src/main/java/mate.academy/lib/Component.java +++ b/src/main/java/mate.academy/lib/Component.java @@ -1,8 +1,11 @@ package mate.academy.lib; +import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) public @interface Component { } diff --git a/src/main/java/mate.academy/lib/Inject.java b/src/main/java/mate.academy/lib/Inject.java index dfd2a0486..0730cb740 100644 --- a/src/main/java/mate.academy/lib/Inject.java +++ b/src/main/java/mate.academy/lib/Inject.java @@ -1,8 +1,11 @@ package mate.academy.lib; +import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) public @interface Inject { } diff --git a/src/main/java/mate.academy/lib/Injector.java b/src/main/java/mate.academy/lib/Injector.java index cec70a690..2a1e3d685 100644 --- a/src/main/java/mate.academy/lib/Injector.java +++ b/src/main/java/mate.academy/lib/Injector.java @@ -13,21 +13,17 @@ public static Injector getInjector() { } public Object getInstance(Class interfaceClazz) { - // Try to resolve implementation for the given interface Class implClass = findImplementation(interfaceClazz); - // Check if class is annotated with @Component if (!implClass.isAnnotationPresent(Component.class)) { throw new RuntimeException("Class " + implClass.getName() + " is not marked as @Component"); } - // Check if an instance already exists if (instances.containsKey(implClass)) { return instances.get(implClass); } - // Create a new instance and inject dependencies Object instance = createInstance(implClass); instances.put(implClass, instance); return instance; @@ -37,7 +33,6 @@ private Object createInstance(Class implClass) { try { Object instance = implClass.getDeclaredConstructor().newInstance(); - // Inject dependencies into fields annotated with @Inject for (Field field : implClass.getDeclaredFields()) { if (field.isAnnotationPresent(Inject.class)) { field.setAccessible(true);