ljacqu/DependencyInjector

View on GitHub
injector/src/main/java/ch/jalu/injector/handlers/instantiation/DefaultInjectionProvider.java

Summary

Maintainability
A
0 mins
Test Coverage
package ch.jalu.injector.handlers.instantiation;

import ch.jalu.injector.exceptions.InjectorException;

import javax.inject.Inject;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.List;

/**
 * The injector's default instantiation provider. Extending {@link StandardInjection}, it roughly follows the
 * documentation of {@link Inject} with additional restrictions:
 * <ul>
 *  <li>An exception is thrown if a class with an {@code @Inject} constructor also has fields with {@code @Inject}.
 *      In parent classes, {@code @Inject} fields are accepted.</li>
 *  <li>{@code @Inject} fields may not be static.</li>
 *  <li>This handler also checks that the class to instantiate is in the allowed root package.</li>
 * </ul>
 */
public class DefaultInjectionProvider extends StandardInjectionProvider {

    private final String rootPackage;

    public DefaultInjectionProvider(String rootPackage) {
        this.rootPackage = rootPackage;
    }

    @Override
    public <T> Resolution<T> safeGet(Class<T> clazz) {
        verifyIsClassPackageAllowed(clazz);
        return super.safeGet(clazz);
    }

    @Override
    protected void validateInjection(Class<?> clazz, Constructor<?> constructor, List<Field> fields) {
        super.validateInjection(clazz, constructor, fields);
        verifyIsClassPackageAllowed(clazz);

        final boolean hasConstructionInjection = constructor.isAnnotationPresent(Inject.class);
        for (Field field : fields) {
            if (hasConstructionInjection && field.getDeclaringClass() == clazz) {
                throw new InjectorException(clazz + " may not have @Inject constructor and @Inject fields. "
                    + "Pass the fields via the constructor as well, remove the @Inject constructor, or use "
                    + StandardInjectionProvider.class.getSimpleName() + " instead");
            }
            if (Modifier.isStatic(field.getModifiers())) {
                throw new InjectorException("@Inject may not be placed on static fields "
                    + "(found violation: '" + field + "')");
            }
        }
    }

    protected void verifyIsClassPackageAllowed(Class<?> clazz) {
        String packageName = clazz.getPackage().getName();
        if (!packageName.startsWith(rootPackage)) {
            throw new InjectorException("Class '" + clazz + "' with package '" + packageName + "' is outside of the "
                + "allowed packages. It must be provided explicitly or the package must be passed to the constructor.");
        }
    }
}