Commit 38a212ae authored by Piotr Gawron's avatar Piotr Gawron

object validation methods extracted to separate class

parent 2eeb4f01
package lcsb.mapviewer.persist;
import java.awt.Color;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.*;
import java.util.function.BiConsumer;
import javax.persistence.Column;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.util.ReflectionUtils;
import lcsb.mapviewer.model.user.User;
public class ObjectValidator {
private Logger logger = LogManager.getLogger();
public List<String> getValidationIssues(Object o) {
final List<String> result = new ArrayList<>();
processValidationIssues(o, new BiConsumer<Object, Field>() {
@Override
public void accept(Object t, Field u) {
try {
Column column = getAnnotationColumn(u);
if (u.getType() == String.class) {
u.setAccessible(true);
String newObject = (String) u.get(t);
if (column != null) {
if (!column.nullable()) {
if (newObject == null) {
result.add(u + " is null but shouldn't");
}
}
if (newObject != null && column.length() <= newObject.length()
&& !column.columnDefinition().equals("TEXT")) {
result.add(
u + " is too long (limit: " + column.length() + "; found: " + newObject.length() + ")" + newObject);
}
}
} else if (u.getType() == Double.class || u.getType() == Integer.class || u.getType() == Class.class
|| u.getType() == Color.class || u.getType() == Calendar.class || u.getType().isEnum()) {
Object newObject = u.get(t);
if (column != null && !column.nullable()) {
if (newObject == null) {
result.add(u + " is null but shouldn't");
}
}
} else if (Collection.class.isAssignableFrom(u.getType())) {
Collection<?> newObjectSet = (Collection<?>) u.get(t);
for (Object o : newObjectSet) {
if (isProblematicProperty(o, column)) {
result.add(u + " has invalid entry: " + o);
}
}
} else {
logger.error("Don't know how to handle class: " + u.getType());
}
} catch (IllegalArgumentException | IllegalAccessException e) {
logger.error("Problem with validating property", e);
}
}
});
return result;
}
private Column getAnnotationColumn(Field u) {
for (Annotation a : u.getAnnotations()) {
if (a instanceof Column) {
return (Column) a;
}
}
return null;
}
public void fixValidationIssues(Object object) {
processValidationIssues(object, new BiConsumer<Object, Field>() {
@Override
public void accept(Object t, Field u) {
try {
u.setAccessible(true);
Column column = getAnnotationColumn(u);
Object newObject = u.get(t);
if (column != null) {
if (u.getType() == String.class) {
String newString = (String) u.get(t);
if (!column.nullable()) {
if (newString == null) {
u.set(t, "");
}
}
if (newString != null && column.length() <= newString.length()
&& !column.columnDefinition().equals("TEXT")) {
u.set(t, newString.substring(0, column.length() - 1));
}
} else if (u.getType() == Double.class) {
if (!column.nullable() && newObject == null) {
u.set(t, 0.0);
}
} else if (u.getType() == Integer.class) {
if (!column.nullable() && newObject == null) {
u.set(t, 0);
}
} else if (u.getType() == Color.class) {
if (!column.nullable() && newObject == null) {
u.set(t, Color.BLACK);
}
} else if (u.getType() == Class.class) {
if (!column.nullable() && newObject == null) {
u.set(t, Object.class);
}
} else if (u.getType() == Calendar.class) {
if (!column.nullable() && newObject == null) {
u.set(t, Calendar.getInstance());
}
} else if (u.getType().isEnum()) {
if (!column.nullable() && newObject == null) {
u.set(t, u.getType().getEnumConstants()[0]);
}
} else if (Collection.class.isAssignableFrom(u.getType())) {
Collection<?> newObjectSet = (Collection<?>) newObject;
Set<Object> toRemove = new HashSet<>();
for (Object o : newObjectSet) {
if (isProblematicProperty(o, column)) {
toRemove.add(o);
}
}
newObjectSet.removeAll(toRemove);
} else {
logger.error("Don't know how to handle class: " + u.getType());
}
}
} catch (IllegalArgumentException | IllegalAccessException e) {
logger.error("Problem with validating property", e);
}
}
});
}
private void processValidationIssues(Object o, BiConsumer<Object, Field> processIssue) {
Set<Object> processed = new HashSet<>();
Queue<Object> objects = new LinkedList<>();
objects.add(o);
processed.add(o);
Set<Class<?>> skippedClasses = new HashSet<>();
skippedClasses.add(int.class);
skippedClasses.add(double.class);
skippedClasses.add(boolean.class);
skippedClasses.add(long.class);
skippedClasses.add(float.class);
skippedClasses.add(char.class);
skippedClasses.add(short.class);
skippedClasses.add(byte.class);
skippedClasses.add(User.class);
while (objects.size() > 0) {
Object object = objects.poll();
ReflectionUtils.doWithFields(object.getClass(), new ReflectionUtils.FieldCallback() {
@Override
public void doWith(Field arg0) throws IllegalArgumentException, IllegalAccessException {
arg0.setAccessible(true);
Column column = getAnnotationColumn(arg0);
Object property = arg0.get(object);
if (skippedClasses.contains(arg0.getType())) {
// skip
} else if (java.lang.reflect.Modifier.isStatic(arg0.getModifiers())) {
// skip static
} else if (arg0.getType() == String.class || arg0.getType() == Double.class || arg0.getType() == Integer.class
|| arg0.getType() == Color.class || arg0.getType() == Calendar.class || arg0.getType() == Class.class
|| arg0.getType() == Calendar.class || arg0.getType().isEnum()) {
if (isProblematicProperty(property, column)) {
processIssue.accept(object, arg0);
}
} else if (Collection.class.isAssignableFrom(arg0.getType())) {
Collection<?> newObjectSet = (Collection<?>) property;
List<Object> problematicEntries = new ArrayList<>();
if (newObjectSet != null) {
for (Object newObject : newObjectSet) {
if (isProblematicProperty(newObject, column)) {
problematicEntries.add(newObject);
}
if (newObject != null && !skippedClasses.contains(newObject.getClass())) {
if (!processed.contains(newObject)) {
objects.add(newObject);
processed.add(newObject);
}
}
}
if (problematicEntries.size() > 0) {
processIssue.accept(object, arg0);
}
}
} else if (Object.class.isAssignableFrom(arg0.getType())) {
arg0.setAccessible(true);
Object newObject = arg0.get(object);
if (newObject != null) {
if (!processed.contains(newObject)) {
objects.add(newObject);
processed.add(newObject);
}
}
} else {
logger.error("Don't know how to process: " + arg0.getType());
}
}
});
}
}
private boolean isProblematicProperty(Object property, Column column)
throws IllegalArgumentException, IllegalAccessException {
if (column != null) {
if (property instanceof String) {
String stringProperty = (String) property;
if (stringProperty != null && column.length() <= stringProperty.length()
&& !column.columnDefinition().equals("TEXT")) {
return true;
}
}
if (!column.nullable()) {
if (property == null) {
return true;
}
}
}
return false;
}
}
package lcsb.mapviewer.persist.dao;
import java.awt.Color;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.criteria.*;
import org.apache.logging.log4j.LogManager;
......@@ -16,10 +11,8 @@ import org.hibernate.dialect.Dialect;
import org.hibernate.query.Query;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.util.ReflectionUtils;
import lcsb.mapviewer.common.Pair;
import lcsb.mapviewer.model.user.User;
import lcsb.mapviewer.persist.DbUtils;
/**
......@@ -346,230 +339,4 @@ public abstract class BaseDao<T> {
return dbUtils.getDialect();
}
public List<String> getValidationIssues(T o) {
final List<String> result = new ArrayList<>();
processValidationIssues(o, new BiConsumer<Object, Field>() {
@Override
public void accept(Object t, Field u) {
try {
Column column = getAnnotationColumn(u);
if (u.getType() == String.class) {
u.setAccessible(true);
String newObject = (String) u.get(t);
if (column != null) {
if (!column.nullable()) {
if (newObject == null) {
result.add(u + " is null but shouldn't");
}
}
if (newObject != null && column.length() <= newObject.length()
&& !column.columnDefinition().equals("TEXT")) {
result.add(
u + " is too long (limit: " + column.length() + "; found: " + newObject.length() + ")" + newObject);
}
}
} else if (u.getType() == Double.class || u.getType() == Integer.class || u.getType() == Class.class
|| u.getType() == Color.class || u.getType() == Calendar.class || u.getType().isEnum()) {
Object newObject = u.get(t);
if (column != null && !column.nullable()) {
if (newObject == null) {
result.add(u + " is null but shouldn't");
}
}
} else if (Collection.class.isAssignableFrom(u.getType())) {
Collection<?> newObjectSet = (Collection<?>) u.get(t);
for (Object o : newObjectSet) {
if (isProblematicProperty(o, column)) {
result.add(u + " has invalid entry: " + o);
}
}
} else {
logger.error("Don't know how to handle class: " + u.getType());
}
} catch (IllegalArgumentException | IllegalAccessException e) {
logger.error("Problem with validating property", e);
}
}
});
return result;
}
private Column getAnnotationColumn(Field u) {
for (Annotation a : u.getAnnotations()) {
if (a instanceof Column) {
return (Column) a;
}
}
return null;
}
public void fixValidationIssues(T object) {
processValidationIssues(object, new BiConsumer<Object, Field>() {
@Override
public void accept(Object t, Field u) {
try {
u.setAccessible(true);
Column column = getAnnotationColumn(u);
Object newObject = u.get(t);
if (column != null) {
if (u.getType() == String.class) {
String newString = (String) u.get(t);
if (!column.nullable()) {
if (newString == null) {
u.set(t, "");
}
}
if (newString != null && column.length() <= newString.length()
&& !column.columnDefinition().equals("TEXT")) {
u.set(t, newString.substring(0, column.length() - 1));
}
} else if (u.getType() == Double.class) {
if (!column.nullable() && newObject == null) {
u.set(t, 0.0);
}
} else if (u.getType() == Integer.class) {
if (!column.nullable() && newObject == null) {
u.set(t, 0);
}
} else if (u.getType() == Color.class) {
if (!column.nullable() && newObject == null) {
u.set(t, Color.BLACK);
}
} else if (u.getType() == Class.class) {
if (!column.nullable() && newObject == null) {
u.set(t, Object.class);
}
} else if (u.getType() == Calendar.class) {
if (!column.nullable() && newObject == null) {
u.set(t, Calendar.getInstance());
}
} else if (u.getType().isEnum()) {
if (!column.nullable() && newObject == null) {
u.set(t, u.getType().getEnumConstants()[0]);
}
} else if (Collection.class.isAssignableFrom(u.getType())) {
Collection<?> newObjectSet = (Collection<?>) newObject;
Set<Object> toRemove = new HashSet<>();
for (Object o : newObjectSet) {
if (isProblematicProperty(o, column)) {
toRemove.add(o);
}
}
newObjectSet.removeAll(toRemove);
} else {
logger.error("Don't know how to handle class: " + u.getType());
}
}
} catch (IllegalArgumentException | IllegalAccessException e) {
logger.error("Problem with validating property", e);
}
}
});
}
private void processValidationIssues(T o, BiConsumer<Object, Field> processIssue) {
Set<Object> processed = new HashSet<>();
Queue<Object> objects = new LinkedList<>();
objects.add(o);
processed.add(o);
Set<Class<?>> skippedClasses = new HashSet<>();
skippedClasses.add(int.class);
skippedClasses.add(double.class);
skippedClasses.add(boolean.class);
skippedClasses.add(long.class);
skippedClasses.add(float.class);
skippedClasses.add(char.class);
skippedClasses.add(short.class);
skippedClasses.add(byte.class);
skippedClasses.add(User.class);
while (objects.size() > 0) {
Object object = objects.poll();
ReflectionUtils.doWithFields(object.getClass(), new ReflectionUtils.FieldCallback() {
@Override
public void doWith(Field arg0) throws IllegalArgumentException, IllegalAccessException {
arg0.setAccessible(true);
Column column = getAnnotationColumn(arg0);
Object property = arg0.get(object);
if (skippedClasses.contains(arg0.getType())) {
// skip
} else if (java.lang.reflect.Modifier.isStatic(arg0.getModifiers())) {
// skip static
} else if (arg0.getType() == String.class || arg0.getType() == Double.class || arg0.getType() == Integer.class
|| arg0.getType() == Color.class || arg0.getType() == Calendar.class || arg0.getType() == Class.class
|| arg0.getType() == Calendar.class || arg0.getType().isEnum()) {
if (isProblematicProperty(property, column)) {
processIssue.accept(object, arg0);
}
} else if (Collection.class.isAssignableFrom(arg0.getType())) {
Collection<?> newObjectSet = (Collection<?>) property;
List<Object> problematicEntries = new ArrayList<>();
if (newObjectSet != null) {
for (Object newObject : newObjectSet) {
if (isProblematicProperty(newObject, column)) {
problematicEntries.add(newObject);
}
if (newObject != null && !skippedClasses.contains(newObject.getClass())) {
if (!processed.contains(newObject)) {
objects.add(newObject);
processed.add(newObject);
}
}
}
if (problematicEntries.size() > 0) {
processIssue.accept(object, arg0);
}
}
} else if (Object.class.isAssignableFrom(arg0.getType())) {
arg0.setAccessible(true);
Object newObject = arg0.get(object);
if (newObject != null) {
if (!processed.contains(newObject)) {
objects.add(newObject);
processed.add(newObject);
}
}
} else {
logger.error("Don't know how to process: " + arg0.getType());
}
}
});
}
}
private boolean isProblematicProperty(Object property, Column column)
throws IllegalArgumentException, IllegalAccessException {
if (column != null) {
if (property instanceof String) {
String stringProperty = (String) property;
if (stringProperty != null && column.length() <= stringProperty.length()
&& !column.columnDefinition().equals("TEXT")) {
return true;
}
}
if (!column.nullable()) {
if (property == null) {
return true;
}
}
}
return false;
}
}
package lcsb.mapviewer.persist.dao;
package lcsb.mapviewer.persist;
import static org.junit.Assert.assertEquals;
......@@ -12,16 +12,13 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import org.mockito.Mockito;
import lcsb.mapviewer.model.map.MiriamType;
import lcsb.mapviewer.persist.PersistTestFunctions;
@RunWith(Parameterized.class)
public class BaseDaoTest extends PersistTestFunctions {
public class ObjectValidatorTest extends PersistTestFunctions {
@SuppressWarnings("unchecked")
BaseDao<Object> dao = Mockito.mock(BaseDao.class, Mockito.CALLS_REAL_METHODS);
ObjectValidator objectValidator = new ObjectValidator();
static class NullString {
@Column(nullable = false)
......@@ -75,7 +72,7 @@ public class BaseDaoTest extends PersistTestFunctions {
private Object testedObject;
public BaseDaoTest(String testName, Class<?> testedClass) throws Exception {
public ObjectValidatorTest(String testName, Class<?> testedClass) throws Exception {
this.testedObject = testedClass.newInstance();
}
......@@ -98,13 +95,13 @@ public class BaseDaoTest extends PersistTestFunctions {
@Test
public void testGetValidation() throws Exception {
assertEquals(1, dao.getValidationIssues(testedObject).size());
assertEquals(1, objectValidator.getValidationIssues(testedObject).size());
}
@Test
public void testFixValidation() throws Exception {
dao.fixValidationIssues(testedObject);
List<String> issues = dao.getValidationIssues(testedObject);
objectValidator.fixValidationIssues(testedObject);
List<String> issues = objectValidator.getValidationIssues(testedObject);
assertEquals(0, issues.size());
}
......
......@@ -3,6 +3,7 @@ package lcsb.mapviewer.persist.dao;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import lcsb.mapviewer.persist.ObjectValidatorTest;
import lcsb.mapviewer.persist.dao.cache.AllCacheDbTests;
import lcsb.mapviewer.persist.dao.graphics.AllGraphicsDaoTests;
import lcsb.mapviewer.persist.dao.map.AllMapDaoTests;
......@@ -15,7 +16,6 @@ import lcsb.mapviewer.persist.dao.user.AllUserTests;
AllMapDaoTests.class,
AllPluginTests.class,
AllUserTests.class,
BaseDaoTest.class,
ConfigurationDaoTest.class,
ProjectDaoTest.class,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment