Commit 90991880 authored by Piotr Gawron's avatar Piotr Gawron

list of issues contains information about bioentity connected to the problem...

list of issues contains information about bioentity connected to the problem (if such bioentity exists)
parent 52426aff
......@@ -4,24 +4,42 @@ 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 javax.persistence.OneToOne;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.util.ReflectionUtils;
import lcsb.mapviewer.common.Pair;
import lcsb.mapviewer.model.map.BioEntity;
import lcsb.mapviewer.model.map.model.ModelData;
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>() {
private static final Set<Class<?>> SKIPPED_CLASSES = new HashSet<>(Arrays.asList(
int.class,
double.class,
boolean.class,
long.class,
float.class,
char.class,
short.class,
byte.class,
User.class));
private interface ProcessIssue {
void accept(Object object, Field field, Object subjectUnderInvestigation);
}
public List<Pair<Object, String>> getValidationIssues(Object o) {
final List<Pair<Object, String>> result = new ArrayList<>();
processValidationIssues(o, new ProcessIssue() {
@Override
public void accept(Object t, Field u) {
public void accept(Object t, Field u, Object objectUnderInvestigation) {
try {
Column column = getAnnotationColumn(u);
if (u.getType() == String.class) {
......@@ -31,13 +49,14 @@ public class ObjectValidator {
if (column != null) {
if (!column.nullable()) {
if (newObject == null) {
result.add(u + " is null but shouldn't");
result.add(new Pair<>(objectUnderInvestigation, 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);
result.add(new Pair<>(objectUnderInvestigation,
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
......@@ -45,18 +64,21 @@ public class ObjectValidator {
Object newObject = u.get(t);
if (column != null && !column.nullable()) {
if (newObject == null) {
result.add(u + " is null but shouldn't");
result.add(new Pair<>(objectUnderInvestigation, 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);
result.add(new Pair<>(objectUnderInvestigation, u + " has invalid entry: " + o));
}
}
} else {
logger.error("Don't know how to handle class: " + u.getType());
Object newObject = u.get(t);
if (isProblematicProperty(newObject, getOneToOne(u))) {
result.add(new Pair<>(objectUnderInvestigation, u + " is invalid: " + newObject));
}
}
} catch (IllegalArgumentException | IllegalAccessException e) {
logger.error("Problem with validating property", e);
......@@ -76,10 +98,19 @@ public class ObjectValidator {
return null;
}
private OneToOne getOneToOne(Field u) {
for (Annotation a : u.getAnnotations()) {
if (a instanceof OneToOne) {
return (OneToOne) a;
}
}
return null;
}
public void fixValidationIssues(Object object) {
processValidationIssues(object, new BiConsumer<Object, Field>() {
processValidationIssues(object, new ProcessIssue() {
@Override
public void accept(Object t, Field u) {
public void accept(Object t, Field u, Object objectUnderInvestigation) {
try {
u.setAccessible(true);
Column column = getAnnotationColumn(u);
......@@ -143,28 +174,17 @@ public class ObjectValidator {
}
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<Object> processed = new HashSet<>();
Queue<Pair<Object, Object>> objects = new LinkedList<>();
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);
private synchronized void processValidationIssues(Object o, ProcessIssue processIssue) {
initQueue();
addToQueue(o, null);
while (objects.size() > 0) {
Object object = objects.poll();
Pair<Object, Object> pair = objects.poll();
Object object = pair.getLeft();
ReflectionUtils.doWithFields(object.getClass(), new ReflectionUtils.FieldCallback() {
@Override
......@@ -172,7 +192,7 @@ public class ObjectValidator {
arg0.setAccessible(true);
Column column = getAnnotationColumn(arg0);
Object property = arg0.get(object);
if (skippedClasses.contains(arg0.getType())) {
if (SKIPPED_CLASSES.contains(arg0.getType())) {
// skip
} else if (java.lang.reflect.Modifier.isStatic(arg0.getModifiers())) {
// skip static
......@@ -180,7 +200,7 @@ public class ObjectValidator {
|| 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);
processIssue.accept(object, arg0, pair.getRight());
}
} else if (Collection.class.isAssignableFrom(arg0.getType())) {
Collection<?> newObjectSet = (Collection<?>) property;
......@@ -191,29 +211,22 @@ public class ObjectValidator {
if (isProblematicProperty(newObject, column)) {
problematicEntries.add(newObject);
}
if (newObject != null && !skippedClasses.contains(newObject.getClass())) {
if (!processed.contains(newObject)) {
objects.add(newObject);
processed.add(newObject);
}
}
addToQueue(newObject, pair.getRight());
}
if (problematicEntries.size() > 0) {
processIssue.accept(object, arg0);
processIssue.accept(object, arg0, pair.getRight());
}
}
} 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);
}
if (isProblematicProperty(property, getOneToOne(arg0))) {
processIssue.accept(object, arg0, pair.getRight());
}
addToQueue(property, pair.getRight());
} else {
logger.error("Don't know how to process: " + arg0.getType());
}
......@@ -224,6 +237,26 @@ public class ObjectValidator {
}
private void addToQueue(Object object, Object objectUnderInvestigation) {
if (object != null && !SKIPPED_CLASSES.contains(object.getClass())) {
if (!processed.contains(object)) {
if (object instanceof BioEntity) {
objectUnderInvestigation = object;
}
if (object instanceof ModelData && objectUnderInvestigation == null) {
objectUnderInvestigation = object;
}
objects.add(new Pair<>(object, objectUnderInvestigation));
processed.add(object);
}
}
}
private void initQueue() {
processed = new HashSet<>();
objects = new LinkedList<>();
}
private boolean isProblematicProperty(Object property, Column column)
throws IllegalArgumentException, IllegalAccessException {
if (column != null) {
......@@ -243,5 +276,16 @@ public class ObjectValidator {
return false;
}
private boolean isProblematicProperty(Object property, OneToOne column)
throws IllegalArgumentException, IllegalAccessException {
if (column != null) {
if (!column.optional()) {
if (property == null) {
return true;
}
}
}
return false;
}
}
......@@ -13,6 +13,7 @@ import lcsb.mapviewer.persist.mapper.AllMapperTests;
DbUtilsTest.class,
InitialStateTest.class,
ObjectValidatorTest.class,
ObjectValidatorGenericTest.class,
SpringApplicationContextTest.class,
})
......
package lcsb.mapviewer.persist;
import static org.junit.Assert.assertEquals;
import java.awt.Color;
import java.io.IOException;
import java.util.*;
import javax.persistence.Column;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import lcsb.mapviewer.model.map.MiriamType;
@RunWith(Parameterized.class)
public class ObjectValidatorGenericTest extends PersistTestFunctions {
ObjectValidator objectValidator = new ObjectValidator();
static class NullString {
@Column(nullable = false)
String val = null;
}
static class NullElementInStringList {
@Column(nullable = false)
List<String> val = new ArrayList<>(Arrays.asList("str", null));
}
static class NullElementInStringSet {
@Column(nullable = false)
Set<String> val = new HashSet<>(Arrays.asList("str", null));
}
static class NullDouble {
@Column(nullable = false)
Double val = null;
}
static class NullInteger {
@Column(nullable = false)
Integer val = null;
}
static class NullColor {
@Column(nullable = false)
Color val = null;
}
static class NullEnum {
@Column(nullable = false)
MiriamType val = null;
}
static class NullCalendar {
@Column(nullable = false)
Calendar val = null;
}
static class NullClass {
@Column(nullable = false)
Class<?> val = null;
}
static class ToLongString {
@Column(length = 3)
String val = "xxxx";
}
private Object testedObject;
public ObjectValidatorGenericTest(String testName, Class<?> testedClass) throws Exception {
this.testedObject = testedClass.newInstance();
}
@Parameters(name = "{index} : {0}")
public static Collection<Object[]> data() throws IOException {
Collection<Object[]> data = new ArrayList<Object[]>();
data.add(new Object[] { "Too long String", ToLongString.class });
data.add(new Object[] { "Null String for not nullable", NullString.class });
data.add(new Object[] { "Null Double for not nullable", NullDouble.class });
data.add(new Object[] { "Null Integer for not nullable", NullInteger.class });
data.add(new Object[] { "Null Color for not nullable", NullColor.class });
data.add(new Object[] { "Null Enum for not nullable", NullEnum.class });
data.add(new Object[] { "Null Calendar for not nullable", NullCalendar.class });
data.add(new Object[] { "Null Class for not nullable", NullClass.class });
data.add(new Object[] { "Null String in List for not nullable", NullElementInStringList.class });
data.add(new Object[] { "Null String in Set for not nullable", NullElementInStringSet.class });
return data;
}
@Test
public void testGetValidation() throws Exception {
assertEquals(1, objectValidator.getValidationIssues(testedObject).size());
}
@Test
public void testFixValidation() throws Exception {
objectValidator.fixValidationIssues(testedObject);
assertEquals(0, objectValidator.getValidationIssues(testedObject).size());
}
}
package lcsb.mapviewer.persist;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import java.awt.Color;
import java.io.IOException;
import java.util.*;
import javax.persistence.Column;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import lcsb.mapviewer.model.map.MiriamType;
import lcsb.mapviewer.common.Pair;
import lcsb.mapviewer.model.Project;
import lcsb.mapviewer.model.map.model.Model;
import lcsb.mapviewer.model.map.model.ModelFullIndexed;
import lcsb.mapviewer.model.map.reaction.Reaction;
import lcsb.mapviewer.model.map.reaction.type.TransportReaction;
import lcsb.mapviewer.model.map.species.GenericProtein;
import lcsb.mapviewer.model.map.species.Protein;
@RunWith(Parameterized.class)
public class ObjectValidatorTest extends PersistTestFunctions {
ObjectValidator objectValidator = new ObjectValidator();
static class NullString {
@Column(nullable = false)
String val = null;
}
static class NullElementInStringList {
@Column(nullable = false)
List<String> val = new ArrayList<>(Arrays.asList("str", null));
}
static class NullElementInStringSet {
@Column(nullable = false)
Set<String> val = new HashSet<>(Arrays.asList("str", null));
}
static class NullDouble {
@Column(nullable = false)
Double val = null;
}
static class NullInteger {
@Column(nullable = false)
Integer val = null;
}
static class NullColor {
@Column(nullable = false)
Color val = null;
}
static class NullEnum {
@Column(nullable = false)
MiriamType val = null;
}
static class NullCalendar {
@Column(nullable = false)
Calendar val = null;
}
static class NullClass {
@Column(nullable = false)
Class<?> val = null;
}
static class ToLongString {
@Column(length = 3)
String val = "xxxx";
}
private Object testedObject;
public ObjectValidatorTest(String testName, Class<?> testedClass) throws Exception {
this.testedObject = testedClass.newInstance();
@Test
public void testGetValidationSubjectForSpeciesIssue() throws Exception {
Protein protein = new GenericProtein("id");
protein.setFontSize((Double) null);
Project project = new Project("proj");
Model model = new ModelFullIndexed(null);
project.addModel(model);
model.addElement(protein);
List<Pair<Object, String>> issues = objectValidator.getValidationIssues(project);
assertEquals(1, issues.size());
assertEquals(protein, issues.get(0).getLeft());
}
@Parameters(name = "{index} : {0}")
public static Collection<Object[]> data() throws IOException {
Collection<Object[]> data = new ArrayList<Object[]>();
data.add(new Object[] { "Too long String", ToLongString.class });
data.add(new Object[] { "Null String for not nullable", NullString.class });
data.add(new Object[] { "Null Double for not nullable", NullDouble.class });
data.add(new Object[] { "Null Integer for not nullable", NullInteger.class });
data.add(new Object[] { "Null Color for not nullable", NullColor.class });
data.add(new Object[] { "Null Enum for not nullable", NullEnum.class });
data.add(new Object[] { "Null Calendar for not nullable", NullCalendar.class });
data.add(new Object[] { "Null Class for not nullable", NullClass.class });
data.add(new Object[] { "Null String in List for not nullable", NullElementInStringList.class });
data.add(new Object[] { "Null String in Set for not nullable", NullElementInStringSet.class });
return data;
@Test
public void testGetValidationSubjectForReactionIssue() throws Exception {
Reaction reaction = new TransportReaction("id");
reaction.setLine(null);
List<Pair<Object, String>> issues = objectValidator.getValidationIssues(reaction);
assertEquals(1, issues.size());
assertEquals(reaction, issues.get(0).getLeft());
}
@Test
public void testGetValidation() throws Exception {
assertEquals(1, objectValidator.getValidationIssues(testedObject).size());
public void testGetValidationSubjectForModelIssue() throws Exception {
Model m = new ModelFullIndexed(null);
m.setProject(new Project());
List<Pair<Object, String>> issues = objectValidator.getValidationIssues(m);
assertEquals(1, issues.size());
assertEquals(m.getModelData(), issues.get(0).getLeft());
}
@Test
public void testFixValidation() throws Exception {
objectValidator.fixValidationIssues(testedObject);
List<String> issues = objectValidator.getValidationIssues(testedObject);
assertEquals(0, issues.size());
public void testGetValidationSubjectForProjectIssue() throws Exception {
Project p = new Project();
List<Pair<Object, String>> issues = objectValidator.getValidationIssues(p);
assertEquals(1, issues.size());
assertNull(issues.get(0).getLeft());
}
}
......@@ -3,7 +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.ObjectValidatorGenericTest;
import lcsb.mapviewer.persist.dao.cache.AllCacheDbTests;
import lcsb.mapviewer.persist.dao.graphics.AllGraphicsDaoTests;
import lcsb.mapviewer.persist.dao.map.AllMapDaoTests;
......
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