<commit_before>package com.dplm.simpleDI;

import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.HashSet;

import com.dplm.simpleDI.exceptions.CircularDependencyException;
import com.dplm.simpleDI.exceptions.EmptyConstructorNotFoundException;
import com.dplm.simpleDI.exceptions.UnexpectedInstantiationException;

public class Injector {

	private static Injector singleton;	

	private HashMap<Class<?>, Object> instanceMap;
	
	public Injector(){
		instanceMap = new HashMap<Class<?>, Object>();
	}
	
	@SuppressWarnings("unchecked")
	public static <T> T inject(Class<T> classObj){
		
		if(singleton == null){
			singleton = new Injector();
		}
		
		return (T)singleton.checkCacheOrInject(classObj, new HashSet<Class<?>>());
	}
	
	private Object checkCacheOrInject(Class<?> classObj, HashSet<Class<?>> processingStack){
		if(instanceMap.containsKey(classObj)){
			return instanceMap.get(classObj);
		}
		
		circularDependencyChecking(classObj, processingStack);
		
		Object result = resolveInjection(classObj, processingStack);
		instanceMap.put(classObj, result);
		return result;
	}

	private void circularDependencyChecking(Class<?> classObj, HashSet<Class<?>> processingStack){
		if(processingStack.contains(classObj)){
			throw new CircularDependencyException();
		}else{
			processingStack.add(classObj);
		}		
	}
	
	private Object resolveInjection(Class<?> classObj, HashSet<Class<?>> processingStack){
		Constructor<?> constructor = findConstructor(classObj);
		if(constructor.getParameterCount() == 0){
			return resolveEmptyConstructor(constructor);
		}else{
			return resolveInjectedConstructor(constructor, processingStack);
		}
	}
		
	private Constructor<?> findConstructor(Class<?> classObj){
		Constructor<?> emptyConstructor = null;
		for(Constructor<?> constructor : classObj.getConstructors()){
			if(constructor.isAnnotationPresent(AutoInject.class)){
				return constructor;
			}else if(constructor.getParameterCount() == 0){
				emptyConstructor = constructor;
			}
		}
		
		if(emptyConstructor == null){
			throw new EmptyConstructorNotFoundException();			
		}else{
			return emptyConstructor;
		}
	}	
	
	private Object resolveEmptyConstructor(Constructor<?> constructor){
		try {
			return constructor.newInstance();
		} catch (Exception e) {
			throw new UnexpectedInstantiationException();
		}
	}
	
	private Object resolveInjectedConstructor(Constructor<?> constructor, HashSet<Class<?>> processingStack){
		Object[] params = buildConstructorParameter(constructor, processingStack);
		
		try {
			return constructor.newInstance(params);
		} catch (Exception e) {
			throw new UnexpectedInstantiationException();
		}
	}
	
	private Object[] buildConstructorParameter(Constructor<?> constructor, HashSet<Class<?>> processingStack){
		Object[] params = new Object[constructor.getParameterCount()];
		int id = 0;
		for(Class<?> classObj : constructor.getParameterTypes()){
			params[id++] = checkCacheOrInject(classObj, processingStack);
		}
		
		return params;
	}
}<commit_msg>Store dependency information during the injection<commit_after>package com.dplm.simpleDI;

import java.lang.reflect.Constructor;
import java.util.HashMap;

import com.dplm.simpleDI.exceptions.CircularDependencyException;
import com.dplm.simpleDI.exceptions.EmptyConstructorNotFoundException;
import com.dplm.simpleDI.exceptions.UnexpectedInstantiationException;

public class Injector {

	private static Injector singleton;	

	private HashMap<Class<?>, Object> instanceMap;
	
	public Injector(){
		instanceMap = new HashMap<Class<?>, Object>();
	}
	
	@SuppressWarnings("unchecked")
	public static <T> T inject(Class<T> classObj){
		
		if(singleton == null){
			singleton = new Injector();
		}
		
		return (T)singleton.checkCacheOrInject(classObj, null, new HashMap<Class<?>, Class<?>>());
	}
	
	private Object checkCacheOrInject(Class<?> classObj, Class<?> parentClassObj, HashMap<Class<?>, Class<?>> dependencyMap){
		if(instanceMap.containsKey(classObj)){
			return instanceMap.get(classObj);
		}
		
		circularDependencyChecking(classObj, parentClassObj, dependencyMap);
		
		Object result = resolveInjection(classObj, dependencyMap);
		instanceMap.put(classObj, result);
		return result;
	}

	private void circularDependencyChecking(Class<?> classObj, Class<?> parentClassObj, HashMap<Class<?>, Class<?>> dependencyMap){
		if(dependencyMap.containsKey(classObj)){
			throw new CircularDependencyException();
		}else{
			dependencyMap.put(classObj, parentClassObj);
		}
	}
	
	private Object resolveInjection(Class<?> classObj, HashMap<Class<?>, Class<?>> dependencyMap){
		Constructor<?> constructor = findConstructor(classObj);
		if(constructor.getParameterCount() == 0){
			return resolveEmptyConstructor(constructor);
		}else{
			return resolveInjectedConstructor(constructor, dependencyMap);
		}
	}
		
	private Constructor<?> findConstructor(Class<?> classObj){
		Constructor<?> emptyConstructor = null;
		for(Constructor<?> constructor : classObj.getConstructors()){
			if(constructor.isAnnotationPresent(AutoInject.class)){
				return constructor;
			}else if(constructor.getParameterCount() == 0){
				emptyConstructor = constructor;
			}
		}
		
		if(emptyConstructor == null){
			throw new EmptyConstructorNotFoundException();			
		}else{
			return emptyConstructor;
		}
	}	
	
	private Object resolveEmptyConstructor(Constructor<?> constructor){
		try {
			return constructor.newInstance();
		} catch (Exception e) {
			throw new UnexpectedInstantiationException();
		}
	}
	
	private Object resolveInjectedConstructor(Constructor<?> constructor, HashMap<Class<?>, Class<?>> dependencyMap){
		Object[] params = buildConstructorParameter(constructor, dependencyMap);
		
		try {
			return constructor.newInstance(params);
		} catch (Exception e) {
			throw new UnexpectedInstantiationException();
		}
	}
	
	private Object[] buildConstructorParameter(Constructor<?> constructor, HashMap<Class<?>, Class<?>> dependencyMap){
		Object[] params = new Object[constructor.getParameterCount()];
		int id = 0;
		for(Class<?> classObj : constructor.getParameterTypes()){
			params[id++] = checkCacheOrInject(classObj, constructor.getDeclaringClass(), dependencyMap);
		}
		
		return params;
	}
}
{'fraction_non_alphanumeric': 0.12033462033462033, 'fraction_numerical': 0.0009652509652509653, 'mean_word_length': 5.794535519125683, 'pattern_counts': {'":': 0, '<': 71, '<?xml version=': 0, '>': 71, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5559362', 'n_tokens_mistral': 1929, 'n_tokens_neox': 1724, 'n_words': 365}