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

com.fleetpin.graphql.aws.lambda.util.InputMapper Maven / Gradle / Ivy

package com.fleetpin.graphql.aws.lambda.util;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Optional;

import com.fleetpin.graphql.builder.annotations.GraphQLIgnore;

public class InputMapper {

	public static void assign(Object existing, Object input) {
		try {
			Class existingClass = existing.getClass();
			Class inputClass = input.getClass();

			for(var inputField: getFields(inputClass)) {
				inputField.setAccessible(true);
				var obj = inputField.get(input);
				var type = inputField.getType();
				var generic = inputField.getGenericType();
				if(obj != null) {
					var existingField = getField(existingClass, inputField.getName());
					if(existingField == null) {
						continue;
					}
					if(Modifier.isStatic(inputField.getModifiers()) || Modifier.isStatic(existingField.getModifiers())) {
						continue;
					}
					if(Modifier.isFinal(inputField.getModifiers()) || Modifier.isFinal(existingField.getModifiers())) {
						continue;
					}
					if(obj instanceof Optional) {
						obj = ((Optional) obj).orElse(null);
						var t = ((ParameterizedType) generic).getActualTypeArguments()[0];
						if(t instanceof Class) {
							type = (Class) t;
						}else {
							type = (Class) ((ParameterizedType) t).getRawType();
							generic = t;
						}
					}
					existingField.setAccessible(true);

					if(obj instanceof Collection) {
						ParameterizedType existingType = (ParameterizedType) existingField.getGenericType();
						Class existingInnerClass = (Class) existingType.getActualTypeArguments()[0];
						
						ParameterizedType inputType = (ParameterizedType) generic;
						Class inputInnerClass = (Class) inputType.getActualTypeArguments()[0];
						if(existingInnerClass.isAssignableFrom(inputInnerClass)) {
							existingField.set(existing, obj);
						}else {
							Collection toSet = new ArrayList<>();
							
							for(Object o: (Collection) obj) {
								Object build = existingInnerClass.getConstructor().newInstance();
								assign(build, o);
								toSet.add(build);
							}
							existingField.set(existing, toSet);
						}
						continue;
					}
					

					
					
					if(existingField.getType().isAssignableFrom(type)) {
						existingField.set(existing, obj);
					}else {
						var existingObj = existingField.get(existing);
						if(existingObj == null) {
							existingObj = existingField.getType().getConstructor().newInstance();
							existingField.set(existing, existingObj);
						}
						assign(existingObj, obj);
					}
				}
			}

			//check nothing returns null that shouldn't, is just a best effort
			for(Method method: existingClass.getMethods()) {
				if(method.getDeclaringClass().equals(Object.class)) {
					continue;
				}
				if(method.isAnnotationPresent(GraphQLIgnore.class)) {
					continue;
				}
				if(Modifier.isStatic(method.getModifiers())) {
					continue;
				}
				if(method.getParameterCount() != 0) {
					continue;
				}
				//database deals to these
				if(method.getName().equals("getCreatedAt") || method.getName().equals("getUpdatedAt")) {
					continue;
				}
				if(!method.getName().matches("(get|is)[A-Z].*")) {
					continue;
				}
				String name;
				if(method.getName().startsWith("get")) {
					name = method.getName().substring("get".length(), "get".length() + 1).toLowerCase() + method.getName().substring("get".length() + 1);
				}else {
					name = method.getName().substring("is".length(), "is".length() + 1).toLowerCase() + method.getName().substring("is".length() + 1);
				}
				if(method.invoke(existing) == null) {
					throw new RuntimeException("Missing required type " + name);
				}
			}

		}catch (ReflectiveOperationException e) {
			throw new RuntimeException(e);
		}
	}

	private static Field getField(Class existingClass, String name) {
		for(var field: getFields(existingClass)) {
			if(field.getName().equals(name)) {
				return field;
			}
		}
		return null;
	}

	private static List getFields(Class inputClass) {
		List fields = new ArrayList<>();
		while(inputClass != null) {
			fields.addAll(Arrays.asList(inputClass.getDeclaredFields()));
			inputClass = inputClass.getSuperclass();
		}
		return fields;
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy