Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implemented Injector class #1022

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ In this project, you can find three interfaces with their implementations.

Your task is to implement an injector that uses `@Component` and `@Inject` annotations to initialize and return
Object instances. The convention is to use `Component` on the classes that are used for instance creation (usually these are interface implementations)
and `Inject` to mark fields that need to be initialized. If the `Component` annotation is missing above the class, we shouldn't be able to create an instance of this class in Injector, and we should throw an exception <br>
and `Inject` to mark fields that need to be initialized. If the `Component` annotation is missing above the class, we shouldn't be able to create an instance of this class in Injector, and we should throw an mate.academy.exception <br>
NOTE: Pay attention to the annotation's visibility when you want to use it with reflection API, the `@Retention` property may help you configure it.

[Try to avoid these common mistakes while solving task](./checklist.md)
4 changes: 2 additions & 2 deletions src/main/java/mate.academy/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
import mate.academy.service.ProductService;

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);
Comment on lines +12 to +13

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure that the Injector class is correctly implemented and configured to return an instance of ProductService. If the Injector is not properly set up, this line may cause a runtime error.

List<Product> products = productService.getAllFromFile("products.txt");
products.forEach(System.out::println);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package mate.academy.exception;

public class RequiredAnnotationAbsenceException extends RuntimeException {
public RequiredAnnotationAbsenceException(String message) {
super(message);
}
}
7 changes: 7 additions & 0 deletions src/main/java/mate.academy/lib/Component.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
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 {

}
7 changes: 7 additions & 0 deletions src/main/java/mate.academy/lib/Inject.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
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 {

}
68 changes: 67 additions & 1 deletion src/main/java/mate.academy/lib/Injector.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,79 @@
package mate.academy.lib;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.NoSuchElementException;
import mate.academy.exception.RequiredAnnotationAbsenceException;
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 final Map<Class<?>, Object> instances = new HashMap<>();
private final Map<Class<?>, Class<?>> interfaceImplementations = Map.of(
FileReaderService.class, FileReaderServiceImpl.class,
ProductParser.class, ProductParserImpl.class,
ProductService.class, ProductServiceImpl.class
);

public static Injector getInjector() {
return injector;
}

public Object getInstance(Class<?> interfaceClazz) {
return null;
Class<?> clazz = findImplementation(interfaceClazz);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The findImplementation method may return null if the interfaceClazz is not found in the interfaceImplementations map. Consider adding a check to handle this scenario and throw an appropriate exception if no implementation is found.

Object clazzImplementationInstance = createNewInstance(clazz);

Field[] declaredFields = clazz.getDeclaredFields();
for (Field field : declaredFields) {
if (field.isAnnotationPresent(Inject.class)) {
Object fieldInstance = getInstance(field.getType());
try {
field.setAccessible(true);
field.set(clazzImplementationInstance, fieldInstance);
} catch (IllegalAccessException e) {
throw new RuntimeException("Cannot initialize field value. " + "Class: "
+ clazz.getName() + ". Field: " + field.getName());
}
}
}

return clazzImplementationInstance;
}

private Object createNewInstance(Class<?> clazz) {
if (!clazz.isAnnotationPresent(Component.class)) {
throw new RequiredAnnotationAbsenceException(
"Cannot create an instance of the class without Component annotation "
+ clazz);
}
Comment on lines +51 to +55

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure that all classes you intend to create instances for are annotated with @component. Otherwise, the RequiredAnnotationAbsenceException will be thrown, as seen in this check.

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("Cannot create a new instance of: " + clazz.getName());
}
}

private Class<?> findImplementation(Class<?> interfaceClazz) {
if (!interfaceImplementations.containsKey(interfaceClazz)) {
throw new NoSuchElementException("The key " + interfaceClazz + " not found in the map "
+ interfaceImplementations);
}
if (interfaceClazz.isInterface()) {
return interfaceImplementations.get(interfaceClazz);
}
return interfaceClazz;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<String> readFile(String fileName) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading