mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 13:10:44 +00:00
Checkpoint - class-detecting loader handling generic loaders; generic loader created & working; Loader registry moved to its own class;
This commit is contained in:
@ -31,21 +31,17 @@ import java.lang.reflect.Type;
|
|||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import com.fasterxml.jackson.core.type.TypeReference;
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
import com.kingsrook.qqq.backend.core.instances.loaders.implementations.QTableMetaDataLoader;
|
|
||||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.QMetaDataObject;
|
import com.kingsrook.qqq.backend.core.model.metadata.QMetaDataObject;
|
||||||
import com.kingsrook.qqq.backend.core.utils.ClassPathUtils;
|
|
||||||
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
|
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
|
||||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||||
import com.kingsrook.qqq.backend.core.utils.ValueUtils;
|
|
||||||
import com.kingsrook.qqq.backend.core.utils.YamlUtils;
|
import com.kingsrook.qqq.backend.core.utils.YamlUtils;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import static com.kingsrook.qqq.backend.core.utils.ValueUtils.getValueAsBoolean;
|
import static com.kingsrook.qqq.backend.core.utils.ValueUtils.getValueAsBoolean;
|
||||||
@ -61,33 +57,6 @@ public abstract class AbstractMetaDataLoader<T extends QMetaDataObject>
|
|||||||
{
|
{
|
||||||
private static final QLogger LOG = QLogger.getLogger(AbstractMetaDataLoader.class);
|
private static final QLogger LOG = QLogger.getLogger(AbstractMetaDataLoader.class);
|
||||||
|
|
||||||
private static Map<Class<?>, Class<? extends AbstractMetaDataLoader<?>>> registeredLoaders = new HashMap<>();
|
|
||||||
|
|
||||||
static
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
List<Class<?>> classesInPackage = ClassPathUtils.getClassesInPackage(QTableMetaDataLoader.class.getPackageName());
|
|
||||||
for(Class<?> loaderClass : classesInPackage)
|
|
||||||
{
|
|
||||||
Type superClass = loaderClass.getGenericSuperclass();
|
|
||||||
if(superClass.getTypeName().startsWith(AbstractMetaDataLoader.class.getName() + "<"))
|
|
||||||
// if(superClass instanceof Class<?> c && AbstractMetaDataLoader.class.isAssignableFrom(c))
|
|
||||||
{
|
|
||||||
Type actualTypeArgument = ((ParameterizedType) superClass).getActualTypeArguments()[0];
|
|
||||||
Class<?> metaDataObjectType = Class.forName(actualTypeArgument.getTypeName());
|
|
||||||
registeredLoaders.put(metaDataObjectType, (Class<? extends AbstractMetaDataLoader<?>>) loaderClass);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
System.out.println("Registered loaders: " + registeredLoaders);
|
|
||||||
}
|
|
||||||
catch(Exception e)
|
|
||||||
{
|
|
||||||
LOG.error("Error in static init block for AbstractMetaDataLoader", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String fileName;
|
private String fileName;
|
||||||
|
|
||||||
|
|
||||||
@ -185,7 +154,7 @@ public abstract class AbstractMetaDataLoader<T extends QMetaDataObject>
|
|||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
*
|
*
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
private Object reflectivelyMapValue(QInstance qInstance, Method method, Class<?> parameterType, Object rawValue) throws Exception
|
public Object reflectivelyMapValue(QInstance qInstance, Method method, Class<?> parameterType, Object rawValue) throws Exception
|
||||||
{
|
{
|
||||||
if(parameterType.equals(String.class))
|
if(parameterType.equals(String.class))
|
||||||
{
|
{
|
||||||
@ -212,8 +181,7 @@ public abstract class AbstractMetaDataLoader<T extends QMetaDataObject>
|
|||||||
Type actualTypeArgument = ((ParameterizedType) method.getGenericParameterTypes()[0]).getActualTypeArguments()[0];
|
Type actualTypeArgument = ((ParameterizedType) method.getGenericParameterTypes()[0]).getActualTypeArguments()[0];
|
||||||
Class<?> actualTypeClass = Class.forName(actualTypeArgument.getTypeName());
|
Class<?> actualTypeClass = Class.forName(actualTypeArgument.getTypeName());
|
||||||
|
|
||||||
Object value = rawValue;
|
if(rawValue instanceof @SuppressWarnings("rawtypes")List valueList)
|
||||||
if(value instanceof List valueList)
|
|
||||||
{
|
{
|
||||||
List<Object> mappedValueList = new ArrayList<>();
|
List<Object> mappedValueList = new ArrayList<>();
|
||||||
for(Object o : valueList)
|
for(Object o : valueList)
|
||||||
@ -236,8 +204,7 @@ public abstract class AbstractMetaDataLoader<T extends QMetaDataObject>
|
|||||||
Type actualTypeArgument = ((ParameterizedType) method.getGenericParameterTypes()[0]).getActualTypeArguments()[0];
|
Type actualTypeArgument = ((ParameterizedType) method.getGenericParameterTypes()[0]).getActualTypeArguments()[0];
|
||||||
Class<?> actualTypeClass = Class.forName(actualTypeArgument.getTypeName());
|
Class<?> actualTypeClass = Class.forName(actualTypeArgument.getTypeName());
|
||||||
|
|
||||||
Object value = rawValue;
|
if(rawValue instanceof @SuppressWarnings("rawtypes")List valueList)
|
||||||
if(value instanceof List valueList)
|
|
||||||
{
|
{
|
||||||
Set<Object> mappedValueSet = new LinkedHashSet<>();
|
Set<Object> mappedValueSet = new LinkedHashSet<>();
|
||||||
for(Object o : valueList)
|
for(Object o : valueList)
|
||||||
@ -268,14 +235,14 @@ public abstract class AbstractMetaDataLoader<T extends QMetaDataObject>
|
|||||||
Type actualTypeArgument = ((ParameterizedType) method.getGenericParameterTypes()[0]).getActualTypeArguments()[1];
|
Type actualTypeArgument = ((ParameterizedType) method.getGenericParameterTypes()[0]).getActualTypeArguments()[1];
|
||||||
Class<?> actualTypeClass = Class.forName(actualTypeArgument.getTypeName());
|
Class<?> actualTypeClass = Class.forName(actualTypeArgument.getTypeName());
|
||||||
|
|
||||||
Object value = rawValue;
|
if(rawValue instanceof @SuppressWarnings("rawtypes")Map valueMap)
|
||||||
if(value instanceof Map valueMap)
|
|
||||||
{
|
{
|
||||||
Map<String, Object> mappedValueMap = new LinkedHashMap<>();
|
Map<String, Object> mappedValueMap = new LinkedHashMap<>();
|
||||||
for(Object o : valueMap.entrySet())
|
for(Object o : valueMap.entrySet())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
Map.Entry<String, Object> entry = (Map.Entry<String, Object>) o;
|
Map.Entry<String, Object> entry = (Map.Entry<String, Object>) o;
|
||||||
Object mappedValue = reflectivelyMapValue(qInstance, null, actualTypeClass, entry.getValue());
|
Object mappedValue = reflectivelyMapValue(qInstance, null, actualTypeClass, entry.getValue());
|
||||||
mappedValueMap.put(entry.getKey(), mappedValue);
|
mappedValueMap.put(entry.getKey(), mappedValue);
|
||||||
@ -299,23 +266,22 @@ public abstract class AbstractMetaDataLoader<T extends QMetaDataObject>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(registeredLoaders.containsKey(parameterType))
|
else if(MetaDataLoaderRegistry.hasLoaderForClass(parameterType))
|
||||||
{
|
{
|
||||||
Object value = rawValue;
|
if(rawValue instanceof @SuppressWarnings("rawtypes")Map valueMap)
|
||||||
if(value instanceof Map valueMap)
|
|
||||||
{
|
{
|
||||||
Class<? extends AbstractMetaDataLoader<?>> loaderClass = registeredLoaders.get(parameterType);
|
Class<? extends AbstractMetaDataLoader<?>> loaderClass = MetaDataLoaderRegistry.getLoaderForClass(parameterType);
|
||||||
AbstractMetaDataLoader<?> loader = loaderClass.getConstructor().newInstance();
|
AbstractMetaDataLoader<?> loader = loaderClass.getConstructor().newInstance();
|
||||||
QMetaDataObject loadedValue = loader.mapToMetaDataObject(qInstance, valueMap);
|
//noinspection unchecked
|
||||||
return (loadedValue);
|
return (loader.mapToMetaDataObject(qInstance, valueMap));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(QMetaDataObject.class.isAssignableFrom(parameterType))
|
else if(QMetaDataObject.class.isAssignableFrom(parameterType))
|
||||||
{
|
{
|
||||||
Object value = rawValue;
|
if(rawValue instanceof @SuppressWarnings("rawtypes")Map valueMap)
|
||||||
if(value instanceof Map valueMap)
|
|
||||||
{
|
{
|
||||||
QMetaDataObject childObject = (QMetaDataObject) parameterType.getConstructor().newInstance();
|
QMetaDataObject childObject = (QMetaDataObject) parameterType.getConstructor().newInstance();
|
||||||
|
//noinspection unchecked
|
||||||
reflectivelyMap(qInstance, childObject, valueMap);
|
reflectivelyMap(qInstance, childObject, valueMap);
|
||||||
return (childObject);
|
return (childObject);
|
||||||
}
|
}
|
||||||
@ -340,117 +306,96 @@ public abstract class AbstractMetaDataLoader<T extends QMetaDataObject>
|
|||||||
throw new NoValueException();
|
throw new NoValueException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// unclear if the below is needed. if so, useful to not re-write, but is hurting test coverage, so zombie until used //
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
///***************************************************************************
|
||||||
|
// *
|
||||||
|
// ***************************************************************************/
|
||||||
|
//protected ListOfMapOrMapOfMap getListOfMapOrMapOfMap(Map<String, Object> map, String key)
|
||||||
|
//{
|
||||||
|
// if(map.containsKey(key))
|
||||||
|
// {
|
||||||
|
// if(map.get(key) instanceof List)
|
||||||
|
// {
|
||||||
|
// return (new ListOfMapOrMapOfMap((List<Map<String, Object>>) map.get(key)));
|
||||||
|
// }
|
||||||
|
// else if(map.get(key) instanceof Map)
|
||||||
|
// {
|
||||||
|
// return (new ListOfMapOrMapOfMap((Map<String, Map<String, Object>>) map.get(key)));
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// LOG.warn("Expected list or map under key [" + key + "] while processing [" + getClass().getSimpleName() + "] from [" + fileName + "], but found: " + (map.get(key) == null ? "null" : map.get(key).getClass().getSimpleName()));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return (null);
|
||||||
|
//}
|
||||||
|
|
||||||
/***************************************************************************
|
///***************************************************************************
|
||||||
*
|
// *
|
||||||
***************************************************************************/
|
// ***************************************************************************/
|
||||||
protected ListOfMapOrMapOfMap getListOfMapOrMapOfMap(Map<String, Object> map, String key)
|
//protected List<Map<String, Object>> getListOfMap(Map<String, Object> map, String key)
|
||||||
{
|
//{
|
||||||
if(map.containsKey(key))
|
// if(map.containsKey(key))
|
||||||
{
|
// {
|
||||||
if(map.get(key) instanceof List)
|
// if(map.get(key) instanceof List)
|
||||||
{
|
// {
|
||||||
return (new ListOfMapOrMapOfMap((List<Map<String, Object>>) map.get(key)));
|
// return (List<Map<String, Object>>) map.get(key);
|
||||||
}
|
// }
|
||||||
else if(map.get(key) instanceof Map)
|
// else
|
||||||
{
|
// {
|
||||||
return (new ListOfMapOrMapOfMap((Map<String, Map<String, Object>>) map.get(key)));
|
// LOG.warn("Expected list under key [" + key + "] while processing [" + getClass().getSimpleName() + "] from [" + fileName + "], but found: " + (map.get(key) == null ? "null" : map.get(key).getClass().getSimpleName()));
|
||||||
}
|
// }
|
||||||
else
|
// }
|
||||||
{
|
|
||||||
LOG.warn("Expected list or map under key [" + key + "] while processing [" + getClass().getSimpleName() + "] from [" + fileName + "], but found: " + (map.get(key) == null ? "null" : map.get(key).getClass().getSimpleName()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (null);
|
// return (null);
|
||||||
}
|
//}
|
||||||
|
|
||||||
|
///***************************************************************************
|
||||||
|
// *
|
||||||
|
// ***************************************************************************/
|
||||||
|
//protected Map<String, Map<String, Object>> getMapOfMap(Map<String, Object> map, String key)
|
||||||
|
//{
|
||||||
|
// if(map.containsKey(key))
|
||||||
|
// {
|
||||||
|
// if(map.get(key) instanceof Map)
|
||||||
|
// {
|
||||||
|
// return (Map<String, Map<String, Object>>) map.get(key);
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// LOG.warn("Expected map under key [" + key + "] while processing [" + getClass().getSimpleName() + "] from [" + fileName + "], but found: " + (map.get(key) == null ? "null" : map.get(key).getClass().getSimpleName()));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return (null);
|
||||||
|
//}
|
||||||
|
|
||||||
/***************************************************************************
|
///***************************************************************************
|
||||||
*
|
// **
|
||||||
***************************************************************************/
|
// ***************************************************************************/
|
||||||
protected List<Map<String, Object>> getListOfMap(Map<String, Object> map, String key)
|
//protected record ListOfMapOrMapOfMap(List<Map<String, Object>> listOf, Map<String, Map<String, Object>> mapOf)
|
||||||
{
|
//{
|
||||||
if(map.containsKey(key))
|
// /*******************************************************************************
|
||||||
{
|
// ** Constructor
|
||||||
if(map.get(key) instanceof List)
|
// **
|
||||||
{
|
// *******************************************************************************/
|
||||||
return (List<Map<String, Object>>) map.get(key);
|
// public ListOfMapOrMapOfMap(List<Map<String, Object>> listOf)
|
||||||
}
|
// {
|
||||||
else
|
// this(listOf, null);
|
||||||
{
|
// }
|
||||||
LOG.warn("Expected list under key [" + key + "] while processing [" + getClass().getSimpleName() + "] from [" + fileName + "], but found: " + (map.get(key) == null ? "null" : map.get(key).getClass().getSimpleName()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (null);
|
// /*******************************************************************************
|
||||||
}
|
// ** Constructor
|
||||||
|
// **
|
||||||
|
// *******************************************************************************/
|
||||||
|
// public ListOfMapOrMapOfMap(Map<String, Map<String, Object>> mapOf)
|
||||||
/***************************************************************************
|
// {
|
||||||
*
|
// this(null, mapOf);
|
||||||
***************************************************************************/
|
// }
|
||||||
protected Map<String, Map<String, Object>> getMapOfMap(Map<String, Object> map, String key)
|
//}
|
||||||
{
|
|
||||||
if(map.containsKey(key))
|
|
||||||
{
|
|
||||||
if(map.get(key) instanceof Map)
|
|
||||||
{
|
|
||||||
return (Map<String, Map<String, Object>>) map.get(key);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LOG.warn("Expected map under key [" + key + "] while processing [" + getClass().getSimpleName() + "] from [" + fileName + "], but found: " + (map.get(key) == null ? "null" : map.get(key).getClass().getSimpleName()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (null);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
**
|
|
||||||
***************************************************************************/
|
|
||||||
protected record ListOfMapOrMapOfMap(List<Map<String, Object>> listOf, Map<String, Map<String, Object>> mapOf)
|
|
||||||
{
|
|
||||||
/*******************************************************************************
|
|
||||||
** Constructor
|
|
||||||
**
|
|
||||||
*******************************************************************************/
|
|
||||||
public ListOfMapOrMapOfMap(List<Map<String, Object>> listOf)
|
|
||||||
{
|
|
||||||
this(listOf, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
|
||||||
** Constructor
|
|
||||||
**
|
|
||||||
*******************************************************************************/
|
|
||||||
public ListOfMapOrMapOfMap(Map<String, Map<String, Object>> mapOf)
|
|
||||||
{
|
|
||||||
this(null, mapOf);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
**
|
|
||||||
***************************************************************************/
|
|
||||||
protected void warnNotImplemented(Map<String, Object> map, String key)
|
|
||||||
{
|
|
||||||
if(StringUtils.hasContent(ValueUtils.getValueAsString(map.get(key))))
|
|
||||||
{
|
|
||||||
LOG.warn("Unsupported meta-data attribute [" + key + "] found while processing [" + getClass().getSimpleName() + "] from [" + fileName + "]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -23,10 +23,12 @@ package com.kingsrook.qqq.backend.core.instances.loaders;
|
|||||||
|
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import com.kingsrook.qqq.backend.core.instances.loaders.implementations.QTableMetaDataLoader;
|
import com.kingsrook.qqq.backend.core.instances.loaders.implementations.GenericMetaDataLoader;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.QMetaDataObject;
|
import com.kingsrook.qqq.backend.core.model.metadata.QMetaDataObject;
|
||||||
|
import com.kingsrook.qqq.backend.core.utils.ClassPathUtils;
|
||||||
import com.kingsrook.qqq.backend.core.utils.ValueUtils;
|
import com.kingsrook.qqq.backend.core.utils.ValueUtils;
|
||||||
|
|
||||||
|
|
||||||
@ -57,18 +59,43 @@ public class ClassDetectingMetaDataLoader extends AbstractMetaDataLoader<QMetaDa
|
|||||||
if(map.containsKey("class"))
|
if(map.containsKey("class"))
|
||||||
{
|
{
|
||||||
String classProperty = ValueUtils.getValueAsString(map.get("class"));
|
String classProperty = ValueUtils.getValueAsString(map.get("class"));
|
||||||
AbstractMetaDataLoader<?> loader = switch(classProperty)
|
try
|
||||||
{
|
{
|
||||||
case "QTableMetaData" -> new QTableMetaDataLoader();
|
|
||||||
// todo!! case "QTableMetaData" -> new QTableMetaDataLoader();
|
|
||||||
default -> throw new QMetaDataLoaderException("Unexpected class [" + classProperty + "] specified in " + getFileName());
|
|
||||||
};
|
|
||||||
|
|
||||||
return (loader);
|
if(MetaDataLoaderRegistry.hasLoaderForSimpleName(classProperty))
|
||||||
|
{
|
||||||
|
Class<? extends AbstractMetaDataLoader<?>> loaderClass = MetaDataLoaderRegistry.getLoaderForSimpleName(classProperty);
|
||||||
|
return (loaderClass.getConstructor().newInstance());
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
List<Class<?>> classesInPackage = ClassPathUtils.getClassesInPackage("com.kingsrook.qqq.backend.core.model");
|
||||||
|
for(Class<?> c : classesInPackage)
|
||||||
|
{
|
||||||
|
if(c.getSimpleName().equals(classProperty) && QMetaDataObject.class.isAssignableFrom(c))
|
||||||
|
{
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Class<? extends QMetaDataObject> metaDataClass = (Class<? extends QMetaDataObject>) c;
|
||||||
|
return new GenericMetaDataLoader<>(metaDataClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new QMetaDataLoaderException("Unexpected class [" + classProperty + "] (not a QMetaDataObject; doesn't have a registered MetaDataLoader) specified in " + getFileName());
|
||||||
|
}
|
||||||
|
catch(QMetaDataLoaderException qmdle)
|
||||||
|
{
|
||||||
|
throw (qmdle);
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
throw new QMetaDataLoaderException("Error handling class [" + classProperty + "] specified in " + getFileName(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
throw new QMetaDataLoaderException("Cannot detect meta-data type, because [class] attribute was not specified in file: " + getFileName());
|
throw new QMetaDataLoaderException("Cannot detect meta-data type, because [class] attribute was not specified in file: " + getFileName());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -0,0 +1,99 @@
|
|||||||
|
package com.kingsrook.qqq.backend.core.instances.loaders;
|
||||||
|
|
||||||
|
|
||||||
|
import java.lang.reflect.ParameterizedType;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import com.kingsrook.qqq.backend.core.instances.loaders.implementations.QTableMetaDataLoader;
|
||||||
|
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||||
|
import com.kingsrook.qqq.backend.core.utils.ClassPathUtils;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public class MetaDataLoaderRegistry
|
||||||
|
{
|
||||||
|
private static final QLogger LOG = QLogger.getLogger(AbstractMetaDataLoader.class);
|
||||||
|
|
||||||
|
private static final Map<Class<?>, Class<? extends AbstractMetaDataLoader<?>>> registeredLoaders = new HashMap<>();
|
||||||
|
private static final Map<String, Class<? extends AbstractMetaDataLoader<?>>> registeredLoadersByTargetSimpleName = new HashMap<>();
|
||||||
|
|
||||||
|
static
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
List<Class<?>> classesInPackage = ClassPathUtils.getClassesInPackage(QTableMetaDataLoader.class.getPackageName());
|
||||||
|
for(Class<?> possibleLoaderClass : classesInPackage)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Type superClass = possibleLoaderClass.getGenericSuperclass();
|
||||||
|
if(superClass.getTypeName().startsWith(AbstractMetaDataLoader.class.getName() + "<"))
|
||||||
|
{
|
||||||
|
Type actualTypeArgument = ((ParameterizedType) superClass).getActualTypeArguments()[0];
|
||||||
|
if(actualTypeArgument instanceof Class)
|
||||||
|
{
|
||||||
|
//noinspection unchecked
|
||||||
|
Class<? extends AbstractMetaDataLoader<?>> loaderClass = (Class<? extends AbstractMetaDataLoader<?>>) possibleLoaderClass;
|
||||||
|
|
||||||
|
Class<?> metaDataObjectType = Class.forName(actualTypeArgument.getTypeName());
|
||||||
|
registeredLoaders.put(metaDataObjectType, loaderClass);
|
||||||
|
registeredLoadersByTargetSimpleName.put(metaDataObjectType.getSimpleName(), loaderClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
LOG.info("Error on class: " + possibleLoaderClass, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("Registered loaders: " + registeredLoadersByTargetSimpleName);
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
LOG.error("Error in static init block for MetaDataLoaderRegistry", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
**
|
||||||
|
***************************************************************************/
|
||||||
|
public static boolean hasLoaderForClass(Class<?> metaDataClass)
|
||||||
|
{
|
||||||
|
return registeredLoaders.containsKey(metaDataClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
**
|
||||||
|
***************************************************************************/
|
||||||
|
public static Class<? extends AbstractMetaDataLoader<?>> getLoaderForClass(Class<?> metaDataClass)
|
||||||
|
{
|
||||||
|
return registeredLoaders.get(metaDataClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
**
|
||||||
|
***************************************************************************/
|
||||||
|
public static boolean hasLoaderForSimpleName(String targetSimpleName)
|
||||||
|
{
|
||||||
|
return registeredLoadersByTargetSimpleName.containsKey(targetSimpleName);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
**
|
||||||
|
***************************************************************************/
|
||||||
|
public static Class<? extends AbstractMetaDataLoader<?>> getLoaderForSimpleName(String targetSimpleName)
|
||||||
|
{
|
||||||
|
return registeredLoadersByTargetSimpleName.get(targetSimpleName);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2024. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.instances.loaders.implementations;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import com.kingsrook.qqq.backend.core.instances.loaders.AbstractMetaDataLoader;
|
||||||
|
import com.kingsrook.qqq.backend.core.instances.loaders.QMetaDataLoaderException;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QMetaDataObject;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public class GenericMetaDataLoader<T extends QMetaDataObject> extends AbstractMetaDataLoader<T>
|
||||||
|
{
|
||||||
|
private final Class<T> metaDataClass;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Constructor
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public GenericMetaDataLoader(Class<T> metaDataClass)
|
||||||
|
{
|
||||||
|
this.metaDataClass = metaDataClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
**
|
||||||
|
***************************************************************************/
|
||||||
|
@Override
|
||||||
|
public T mapToMetaDataObject(QInstance qInstance, Map<String, Object> map) throws QMetaDataLoaderException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
T object = metaDataClass.getConstructor().newInstance();
|
||||||
|
reflectivelyMap(qInstance, object, map);
|
||||||
|
return (object);
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
throw (new QMetaDataLoaderException("Error loading metaData object of type " + metaDataClass.getSimpleName(), e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -26,6 +26,7 @@ import java.nio.charset.StandardCharsets;
|
|||||||
import com.kingsrook.qqq.backend.core.BaseTest;
|
import com.kingsrook.qqq.backend.core.BaseTest;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.QMetaDataObject;
|
import com.kingsrook.qqq.backend.core.model.metadata.QMetaDataObject;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@ -50,11 +51,33 @@ class ClassDetectingMetaDataLoaderTest extends BaseTest
|
|||||||
class: QTableMetaData
|
class: QTableMetaData
|
||||||
version: 1
|
version: 1
|
||||||
name: myTable
|
name: myTable
|
||||||
|
backendName: someBackend
|
||||||
""", StandardCharsets.UTF_8), "myTable.yaml");
|
""", StandardCharsets.UTF_8), "myTable.yaml");
|
||||||
|
|
||||||
assertThat(qMetaDataObject).isInstanceOf(QTableMetaData.class);
|
assertThat(qMetaDataObject).isInstanceOf(QTableMetaData.class);
|
||||||
QTableMetaData qTableMetaData = (QTableMetaData) qMetaDataObject;
|
QTableMetaData qTableMetaData = (QTableMetaData) qMetaDataObject;
|
||||||
assertEquals("myTable", qTableMetaData.getName());
|
assertEquals("myTable", qTableMetaData.getName());
|
||||||
|
assertEquals("someBackend", qTableMetaData.getBackendName());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testProcess() throws QMetaDataLoaderException
|
||||||
|
{
|
||||||
|
QMetaDataObject qMetaDataObject = new ClassDetectingMetaDataLoader().fileToMetaDataObject(new QInstance(), IOUtils.toInputStream("""
|
||||||
|
class: QProcessMetaData
|
||||||
|
version: 1
|
||||||
|
name: myProcess
|
||||||
|
tableName: someTable
|
||||||
|
""", StandardCharsets.UTF_8), "myProcess.yaml");
|
||||||
|
|
||||||
|
assertThat(qMetaDataObject).isInstanceOf(QProcessMetaData.class);
|
||||||
|
QProcessMetaData qProcessMetaData = (QProcessMetaData) qMetaDataObject;
|
||||||
|
assertEquals("myProcess", qProcessMetaData.getName());
|
||||||
|
assertEquals("someTable", qProcessMetaData.getTableName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@ package com.kingsrook.qqq.backend.core.instances.loaders;
|
|||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import com.kingsrook.qqq.backend.core.BaseTest;
|
import com.kingsrook.qqq.backend.core.BaseTest;
|
||||||
import com.kingsrook.qqq.backend.core.actions.customizers.TableCustomizers;
|
import com.kingsrook.qqq.backend.core.actions.customizers.TableCustomizers;
|
||||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||||
@ -33,6 +34,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeType;
|
|||||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
|
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.permissions.DenyBehavior;
|
import com.kingsrook.qqq.backend.core.model.metadata.permissions.DenyBehavior;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.permissions.PermissionLevel;
|
import com.kingsrook.qqq.backend.core.model.metadata.permissions.PermissionLevel;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.Capability;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.utils.TestUtils;
|
import com.kingsrook.qqq.backend.core.utils.TestUtils;
|
||||||
import com.kingsrook.qqq.backend.core.utils.YamlUtils;
|
import com.kingsrook.qqq.backend.core.utils.YamlUtils;
|
||||||
@ -113,6 +115,9 @@ class QTableMetaDataLoaderTest extends BaseTest
|
|||||||
preDeleteRecord:
|
preDeleteRecord:
|
||||||
name: com.kingsrook.SomePreDelete
|
name: com.kingsrook.SomePreDelete
|
||||||
codeType: JAVA
|
codeType: JAVA
|
||||||
|
disabledCapabilities:
|
||||||
|
- TABLE_COUNT
|
||||||
|
- QUERY_STATS
|
||||||
""", StandardCharsets.UTF_8), "myTable.yaml");
|
""", StandardCharsets.UTF_8), "myTable.yaml");
|
||||||
|
|
||||||
assertEquals("myTable", table.getName());
|
assertEquals("myTable", table.getName());
|
||||||
@ -145,6 +150,8 @@ class QTableMetaDataLoaderTest extends BaseTest
|
|||||||
assertEquals(2, table.getCustomizers().size());
|
assertEquals(2, table.getCustomizers().size());
|
||||||
assertEquals("com.kingsrook.SomePostQuery", table.getCustomizers().get(TableCustomizers.POST_QUERY_RECORD.getRole()).getName());
|
assertEquals("com.kingsrook.SomePostQuery", table.getCustomizers().get(TableCustomizers.POST_QUERY_RECORD.getRole()).getName());
|
||||||
assertEquals("com.kingsrook.SomePreDelete", table.getCustomizers().get(TableCustomizers.PRE_DELETE_RECORD.getRole()).getName());
|
assertEquals("com.kingsrook.SomePreDelete", table.getCustomizers().get(TableCustomizers.PRE_DELETE_RECORD.getRole()).getName());
|
||||||
|
|
||||||
|
assertEquals(Set.of(Capability.TABLE_COUNT, Capability.QUERY_STATS), table.getDisabledCapabilities());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -0,0 +1,59 @@
|
|||||||
|
package com.kingsrook.qqq.backend.core.instances.loaders.implementations;
|
||||||
|
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import com.kingsrook.qqq.backend.core.BaseTest;
|
||||||
|
import com.kingsrook.qqq.backend.core.instances.loaders.QMetaDataLoaderException;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Unit test for GenericMetaDataLoader - providing coverage for AbstractMetaDataLoader.
|
||||||
|
*******************************************************************************/
|
||||||
|
class GenericMetaDataLoaderTest extends BaseTest
|
||||||
|
{
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testProcess() throws QMetaDataLoaderException
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// trying to get some coverage of various types in here (for Abstract loader) //
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
QProcessMetaData process = new GenericMetaDataLoader<>(QProcessMetaData.class).fileToMetaDataObject(new QInstance(), IOUtils.toInputStream("""
|
||||||
|
class: QProcessMetaData
|
||||||
|
version: 1
|
||||||
|
name: myProcess
|
||||||
|
tableName: someTable
|
||||||
|
maxInputRecords: 1
|
||||||
|
isHidden: true
|
||||||
|
""", StandardCharsets.UTF_8), "myProcess.yaml");
|
||||||
|
|
||||||
|
assertEquals("myProcess", process.getName());
|
||||||
|
assertEquals("someTable", process.getTableName());
|
||||||
|
assertEquals(1, process.getMaxInputRecords());
|
||||||
|
assertTrue(process.getIsHidden());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** just here for coverage of this class, as we're failing to hit it otherwise.
|
||||||
|
*******************************************************************************/
|
||||||
|
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||||
|
@Test
|
||||||
|
void testNoValueException()
|
||||||
|
{
|
||||||
|
assertThatThrownBy(() -> new GenericMetaDataLoader(QBackendMetaData.class).reflectivelyMapValue(new QInstance(), null, GenericMetaDataLoaderTest.class, "rawValue"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Reference in New Issue
Block a user