Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.github.leeonky.dal.util.SchemaVerifier Maven / Gradle / Ivy
package com.github.leeonky.dal.util;
import com.github.leeonky.dal.RuntimeContext;
import com.github.leeonky.dal.format.Formatter;
import com.github.leeonky.dal.format.Type;
import com.github.leeonky.dal.type.AllowNull;
import com.github.leeonky.dal.type.SubType;
import com.github.leeonky.util.BeanClass;
import com.github.leeonky.util.GenericType;
import com.github.leeonky.util.PropertyReader;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static com.github.leeonky.util.BeanClass.getClassName;
import static java.lang.String.format;
import static java.util.Arrays.asList;
import static java.util.stream.IntStream.range;
import static java.util.stream.StreamSupport.stream;
public class SchemaVerifier {
private final WrappedObject object;
private final RuntimeContext runtimeContext;
public SchemaVerifier(RuntimeContext runtimeContext, WrappedObject object) {
this.runtimeContext = runtimeContext;
this.object = object;
}
@SuppressWarnings("unchecked")
private BeanClass getPolymorphicSchemaType(Class> superSchemaType) {
Class> type = superSchemaType;
SubType subType = superSchemaType.getAnnotation(SubType.class);
if (subType != null) {
Object value = object.getPropertyValue(subType.property());
type = Stream.of(subType.types())
.filter(t -> t.value().equals(value))
.map(SubType.Type::type)
.findFirst().orElseThrow(() -> new IllegalStateException(format("Cannot guess sub type through property type value[%s]", value)));
}
return (BeanClass) BeanClass.create(type);
}
public boolean verify(Class> clazz, Object schemaInstance, String subPrefix) {
Set propertyReaderNames = object.getPropertyReaderNames();
BeanClass schema = getPolymorphicSchemaType(clazz);
return noMoreUnexpectedField(schema, schema.getPropertyReaders().keySet(), propertyReaderNames)
&& allMandatoryPropertyShouldBeExist(schema, propertyReaderNames)
&& allPropertyValueShouldBeValid(subPrefix, schema, schemaInstance == null ? schema.newInstance() : schemaInstance);
}
private boolean noMoreUnexpectedField(BeanClass polymorphicBeanClass, Set expectedFields, Set actualFields) {
return actualFields.stream()
.allMatch(f -> shouldNotContainsUnexpectedField(polymorphicBeanClass, expectedFields, f));
}
private boolean allMandatoryPropertyShouldBeExist(BeanClass polymorphicBeanClass, Set actualFields) {
return polymorphicBeanClass.getPropertyReaders().values().stream()
.filter(propertyReader -> propertyReader.getAnnotation(AllowNull.class) == null)
.allMatch(propertyReader -> shouldContainsField(actualFields, polymorphicBeanClass, propertyReader));
}
private boolean allPropertyValueShouldBeValid(String subPrefix, BeanClass polymorphicBeanClass, T schemaInstance) {
return polymorphicBeanClass.getPropertyReaders().values().stream()
.allMatch(propertyReader -> {
WrappedObject wrappedPropertyValue = object.getWrappedPropertyValue(propertyReader.getName());
return allowNullAndIsNull(propertyReader, wrappedPropertyValue)
|| wrappedPropertyValue.createSchemaVerifier().verifySchemaInGenericType(subPrefix + "." + propertyReader.getName(),
propertyReader.getGenericType(), propertyReader.getValue(schemaInstance));
});
}
private boolean allowNullAndIsNull(PropertyReader propertyReader, WrappedObject propertyValueWrapper) {
return propertyReader.getAnnotation(AllowNull.class) != null && propertyValueWrapper.isNull();
}
private boolean shouldNotContainsUnexpectedField(BeanClass polymorphicBeanClass, Set expectedFields, String f) {
return expectedFields.contains(f)
|| errorLog("Unexpected field `%s` for type %s[%s]\n", f, polymorphicBeanClass.getSimpleName(), polymorphicBeanClass.getName());
}
private boolean shouldContainsField(Set actualFields, BeanClass polymorphicBeanClass, PropertyReader propertyReader) {
return actualFields.contains(propertyReader.getName())
|| errorLog("Expected field `%s` for type %s[%s], but does not exist\n", propertyReader.getName(),
polymorphicBeanClass.getSimpleName(), polymorphicBeanClass.getName());
}
private boolean errorLog(String format, Object... params) {
System.err.printf(format, params);
return false;
}
@SuppressWarnings("unchecked")
private boolean verifySchemaInGenericType(String subPrefix, GenericType genericType, Object schemaProperty) {
Class> fieldType = genericType.getRawType();
if (Formatter.class.isAssignableFrom(fieldType)) {
return verifyFormatterValue(subPrefix, getOrCreateFormatter(schemaProperty, genericType));
} else if (runtimeContext.isRegistered(fieldType))
return object.createSchemaVerifier().verify(fieldType, schemaProperty, subPrefix);
else if (Iterable.class.isAssignableFrom(fieldType))
return verifyList(subPrefix, genericType, (Iterable) schemaProperty);
else if (Map.class.isAssignableFrom(fieldType))
return verifyMap(subPrefix, genericType, (Map) schemaProperty);
else if (fieldType.isArray())
return verifyArray(subPrefix, fieldType.getComponentType(), (Object[]) schemaProperty);
else if (Type.class.isAssignableFrom(fieldType))
return verifyWrappedType(subPrefix, (Type) schemaProperty, genericType);
else
return verifyType(subPrefix, schemaProperty, fieldType);
}
private boolean verifyWrappedType(String subPrefix, Type schemaProperty, GenericType genericType) {
if (schemaProperty != null)
return schemaProperty.verify(object.getInstance())
|| errorLog("Field `%s` is invalid\n", subPrefix);
Class> rawType = genericType.getGenericTypeParameter(0)
.orElseThrow(() -> new IllegalStateException(format("%s should specify generic type", subPrefix))).getRawType();
return rawType.isInstance(object.getInstance())
|| errorLog("Expected field `%s` for type [%s], but was [%s]\n", subPrefix,
rawType.getName(), getClassName(object.getInstance()));
}
private boolean verifyType(String subPrefix, Object schemaProperty, Class> fieldType) {
if (schemaProperty != null)
return Objects.equals(schemaProperty, object.getInstance())
|| errorLog("Expected field `%s` equal to %s[%s], but was %s[%s]\n", subPrefix,
getClassName(schemaProperty), schemaProperty, getClassName(object.getInstance()), object.getInstance());
return fieldType.isInstance(object.getInstance())
|| errorLog("Expected field `%s` for type [%s], but was [%s]\n", subPrefix,
fieldType.getName(), getClassName(object.getInstance()));
}
private boolean verifyArray(String subPrefix, Class> elementType, Object[] schemaProperty) {
List wrappedObjectList = stream(object.getWrappedList().spliterator(), false)
.collect(Collectors.toList());
if (schemaProperty == null)
return range(0, wrappedObjectList.size())
.allMatch(i -> wrappedObjectList.get(i).createSchemaVerifier().verifySchemaInGenericType(
format("%s[%d]", subPrefix, i), GenericType.createGenericType(elementType), null));
else {
List schemaPropertyList = asList(schemaProperty);
return shouldBeSameSize(subPrefix, wrappedObjectList, schemaPropertyList)
&& range(0, wrappedObjectList.size())
.allMatch(i -> wrappedObjectList.get(i).createSchemaVerifier().verifySchemaInGenericType(
format("%s[%d]", subPrefix, i), GenericType.createGenericType(elementType), schemaPropertyList.get(i)));
}
}
@SuppressWarnings("unchecked")
private Formatter getOrCreateFormatter(Object schemaProperty, GenericType genericType) {
if (schemaProperty != null)
return (Formatter) schemaProperty;
Class fieldType = (Class) genericType.getRawType();
return (Formatter) genericType.getGenericTypeParameter(0)
.map(t -> BeanClass.newInstance(fieldType, t.getRawType()))
.orElseGet(() -> BeanClass.newInstance(fieldType));
}
private boolean verifyList(String subPrefix, GenericType genericType, Iterable schemaProperties) {
GenericType subGenericType = genericType.getGenericTypeParameter(0).orElseThrow(() ->
new IllegalArgumentException(subPrefix + " should be generic type"));
List wrappedObjectList = stream(object.getWrappedList().spliterator(), false)
.collect(Collectors.toList());
if (schemaProperties == null)
return range(0, wrappedObjectList.size())
.allMatch(i -> wrappedObjectList.get(i).createSchemaVerifier().verifySchemaInGenericType(format("%s[%d]", subPrefix, i), subGenericType, null));
else {
List schemaPropertyList = stream(schemaProperties.spliterator(), false)
.collect(Collectors.toList());
return shouldBeSameSize(subPrefix, wrappedObjectList, schemaPropertyList)
&& range(0, wrappedObjectList.size())
.allMatch(i -> wrappedObjectList.get(i).createSchemaVerifier().verifySchemaInGenericType(format("%s[%d]", subPrefix, i), subGenericType, schemaPropertyList.get(i)));
}
}
private boolean verifyMap(String subPrefix, GenericType genericType, Map, Object> schemaProperty) {
GenericType subGenericType = genericType.getGenericTypeParameter(1).orElseThrow(() ->
new IllegalArgumentException(format("`%s` should be generic type", subPrefix)));
if (schemaProperty == null)
return object.getPropertyReaderNames().stream()
.allMatch(key -> object.getWrappedPropertyValue(key).createSchemaVerifier().verifySchemaInGenericType(subPrefix + "." + key, subGenericType, null));
return shouldBeSameSize(subPrefix, object.getPropertyReaderNames(), schemaProperty.values())
&& object.getPropertyReaderNames().stream()
.allMatch(key -> object.getWrappedPropertyValue(key).createSchemaVerifier().verifySchemaInGenericType(subPrefix + "." + key, subGenericType, schemaProperty.get(key)));
}
private boolean shouldBeSameSize(String subPrefix, Collection> wrappedObjectList, Collection> schemaPropertyList) {
return wrappedObjectList.size() == schemaPropertyList.size()
|| errorLog("Expected field `%s` should be size [%d], but was size [%d]\n", subPrefix, schemaPropertyList.size(), wrappedObjectList.size());
}
private boolean verifyFormatterValue(String subPrefix, Formatter formatter) {
return formatter.isValid(object.getInstance())
|| errorLog("Expected field `%s` should be in `%s`, but was [%s]\n", subPrefix, formatter.getFormatterName(), object.getInstance());
}
}