All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.nill14.utils.init.inject.PojoInjectionDescriptor Maven / Gradle / Ivy

package com.github.nill14.utils.init.inject;

import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.Set;
import java.util.stream.Stream;

import javax.inject.Qualifier;

import com.github.nill14.utils.init.api.IBeanDescriptor;
import com.github.nill14.utils.init.api.IParameterType;
import com.github.nill14.utils.init.meta.AnnotationScanner;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.reflect.TypeToken;


@SuppressWarnings("serial")
public class PojoInjectionDescriptor implements Serializable, IBeanDescriptor {

	
	private final ImmutableList fields;
	private final ImmutableList methods;
	private final ImmutableList constructors;

	private final TypeToken typeToken;
	private final Set> interfaces;

	@SuppressWarnings("unchecked")
	public PojoInjectionDescriptor(IParameterType parameterType) {
		this((TypeToken) TypeToken.of(parameterType.getGenericType()));
	}
	
	public PojoInjectionDescriptor(Class pojoClazz) {
		this(TypeToken.of(pojoClazz));
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	public PojoInjectionDescriptor(TypeToken typeToken) {
		Preconditions.checkNotNull(typeToken);
		this.typeToken = typeToken;
		Set> classes = (Set) typeToken.getTypes().classes().rawTypes();
		interfaces = typeToken.getTypes().interfaces().rawTypes();
		
		fields = ImmutableList.copyOf(
				injectableFields(nonStaticFields(classes.stream())).iterator());
		
		methods = ImmutableList.copyOf(
				injectableMethods(nonStaticMethods(classes.stream())).iterator());
		
		constructors = ImmutableList.copyOf(
				injectableConstructors(Stream.of(typeToken.getRawType().getDeclaredConstructors())).iterator());
		
//		ImmutableList.Builder builder = ImmutableList.builder();
//		for (FieldInjectionDescriptor f : fields) {
//			builder.add(f.getParameterType());
//		}
//		for (MethodInjectionDescriptor m : methods) {
//			builder.addAll(m.getParameterTypes());
//		}
//		TODO gather optional and mandatory dependencies 
	}
	
	@Override
	public ImmutableList getFieldDescriptors() {
		return fields;
	}

	@Override
	public ImmutableList getMethodDescriptors() {
		return methods;
	}
	
	@Override
	public ImmutableList getConstructorDescriptors() {
		return constructors;
	}

	
	@Override
	public Set> getInterfaces() {
		return interfaces;
	}
	
	@Override
	public Set> getDeclaredTypes() {
		return typeToken.getTypes().rawTypes();
	}
	
	@Override
	@Deprecated
	public Set getDeclaredQualifiers() {
		return ImmutableSet.copyOf(AnnotationScanner.findAnnotations(typeToken.getRawType().getAnnotations(), Qualifier.class).values());
	}
	
	private Stream nonStaticMethods(Stream> declaredClasses) {
		return declaredClasses
			.flatMap(c -> Stream.of(c.getDeclaredMethods()))
			.filter(f -> !Modifier.isStatic(f.getModifiers()));
	}

	private Stream nonStaticFields(Stream> declaredClasses) {
		return declaredClasses
				.flatMap(c -> Stream.of(c.getDeclaredFields()))
				.filter(f -> !Modifier.isStatic(f.getModifiers()));
	}

	private Stream injectableConstructors(Stream> constructors) {
		return constructors.map(c -> {
			if (c.getParameterCount() == 0 
					|| c.isAnnotationPresent(javax.inject.Inject.class) 
					|| c.isAnnotationPresent(com.google.inject.Inject.class)) {
				return new ConstructorInjectionDescriptor(c);
			} 
			else return null;
		}).filter(x -> x != null);
	}	
	
	
	private Stream injectableMethods(Stream nonStaticMethods) {
		return nonStaticMethods.map(m -> {
			if (m.isAnnotationPresent(javax.inject.Inject.class) 
					|| m.isAnnotationPresent(com.google.inject.Inject.class)) {
				return new MethodInjectionDescriptor(m);
			} 
			else return null;
		}).filter(x -> x != null);
	}	

	private Stream injectableFields(Stream nonStaticFields) {
		return nonStaticFields.map(f -> {
			if (f.isAnnotationPresent(javax.inject.Inject.class) 
					|| f.isAnnotationPresent(com.google.inject.Inject.class)) {
				return new FieldInjectionDescriptor(f);
			} 
			else return null;
		}).filter(x -> x != null);
	}

	@SuppressWarnings("unchecked")
	@Override
	public Class getRawType() {
		return (Class) typeToken.getRawType();
	}
	
	@Override
	public Type getGenericType() {
		return typeToken.getType();
	}

	@Override
	public boolean canBeInstantiated() {
		Class clazz = typeToken.getRawType();
		return !clazz.isInterface() && !Modifier.isAbstract(clazz.getModifiers()) && !constructors.isEmpty();
	}	

	
//	public List> getMandatoryDependencies() {
//		return ImmutableList.copyOf(fields.stream()
//				.map(PojoInjectionDescriptor::transformDependency).iterator());
//	}
//
//	public List> getOptionalDependencies() {
//		return ImmutableList.copyOf(fields.stream()
//				.map(PojoInjectionDescriptor::transformDependency).iterator());
//	}
	
//	private static Class transformDependency(IType type) {
//		Class rawType = type.getRawType();
//		if (type.isParametrized()) {
//			if (Optional.class.equals(rawType)) {
//				return type.getFirstParamClass();
//			} else if (Collection.class.isAssignableFrom(rawType)) {
//				return type.getFirstParamClass();
//			} 
//		} else if (rawType.isArray()) {
//			return rawType.getComponentType();
//		}
//		
//		return rawType;
//	}
	
	@Override
	public String toString() {
		return typeToken.toString();
	}
	
	private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
		throw new InvalidObjectException("Proxy required");
	}
	
    private Object writeReplace() {
        return new SerializableProxy(this);
    }
    
    private static class SerializableProxy implements Serializable {
    	private final TypeToken  token;

    	public SerializableProxy(PojoInjectionDescriptor pd) {
			this.token = pd.typeToken;
		}
    	
    	private Object readResolve() {
    		return new PojoInjectionDescriptor<>(token);
    	}
    }

	@Override
	public TypeToken getToken() {
		return typeToken;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy