org.mongodb.morphia.mapping.validation.MappingValidator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of morphia Show documentation
Show all versions of morphia Show documentation
Java Object Document Mapper for MongoDB
The newest version!
package org.mongodb.morphia.mapping.validation;
import org.mongodb.morphia.ObjectFactory;
import org.mongodb.morphia.annotations.Embedded;
import org.mongodb.morphia.annotations.Property;
import org.mongodb.morphia.annotations.Reference;
import org.mongodb.morphia.annotations.Serialized;
import org.mongodb.morphia.logging.Logger;
import org.mongodb.morphia.logging.MorphiaLoggerFactory;
import org.mongodb.morphia.mapping.MappedClass;
import org.mongodb.morphia.mapping.Mapper;
import org.mongodb.morphia.mapping.validation.ConstraintViolation.Level;
import org.mongodb.morphia.mapping.validation.classrules.DuplicatedAttributeNames;
import org.mongodb.morphia.mapping.validation.classrules.EmbeddedAndId;
import org.mongodb.morphia.mapping.validation.classrules.EmbeddedAndValue;
import org.mongodb.morphia.mapping.validation.classrules.EntityAndEmbed;
import org.mongodb.morphia.mapping.validation.classrules.EntityCannotBeMapOrIterable;
import org.mongodb.morphia.mapping.validation.classrules.MultipleId;
import org.mongodb.morphia.mapping.validation.classrules.MultipleVersions;
import org.mongodb.morphia.mapping.validation.classrules.NoId;
import org.mongodb.morphia.mapping.validation.fieldrules.ContradictingFieldAnnotation;
import org.mongodb.morphia.mapping.validation.fieldrules.LazyReferenceMissingDependencies;
import org.mongodb.morphia.mapping.validation.fieldrules.LazyReferenceOnArray;
import org.mongodb.morphia.mapping.validation.fieldrules.MapKeyDifferentFromString;
import org.mongodb.morphia.mapping.validation.fieldrules.MapNotSerializable;
import org.mongodb.morphia.mapping.validation.fieldrules.MisplacedProperty;
import org.mongodb.morphia.mapping.validation.fieldrules.ReferenceToUnidentifiable;
import org.mongodb.morphia.mapping.validation.fieldrules.VersionMisuse;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import static java.lang.String.format;
import static java.util.Collections.singletonList;
import static java.util.Collections.sort;
/**
* @author Uwe Schaefer, ([email protected])
*/
public class MappingValidator {
private static final Logger LOG = MorphiaLoggerFactory.get(MappingValidator.class);
private ObjectFactory creator;
/**
* Creates a mapping validator
*
* @param objectFactory the object factory to be used when creating throw away instances to use in validation
*/
public MappingValidator(final ObjectFactory objectFactory) {
creator = objectFactory;
}
/**
* Validates a MappedClass
*
* @param mappedClass the MappedClass to validate
* @param mapper the Mapper to use for validation
*/
@Deprecated
public void validate(final Mapper mapper, final MappedClass mappedClass) {
validate(mapper, singletonList(mappedClass));
}
/**
* Validates a List of MappedClasses
*
* @param classes the MappedClasses to validate
* @param mapper the Mapper to use for validation
*/
public void validate(final Mapper mapper, final List classes) {
final Set ve = new TreeSet(new Comparator() {
@Override
public int compare(final ConstraintViolation o1, final ConstraintViolation o2) {
return o1.getLevel().ordinal() > o2.getLevel().ordinal() ? -1 : 1;
}
});
final List rules = getConstraints();
for (final MappedClass c : classes) {
for (final ClassConstraint v : rules) {
v.check(mapper, c, ve);
}
}
if (!ve.isEmpty()) {
final ConstraintViolation worst = ve.iterator().next();
final Level maxLevel = worst.getLevel();
if (maxLevel.ordinal() >= Level.FATAL.ordinal()) {
throw new ConstraintViolationException(ve);
}
// sort by class to make it more readable
final List l = new ArrayList();
for (final ConstraintViolation v : ve) {
l.add(new LogLine(v));
}
sort(l);
for (final LogLine line : l) {
line.log(LOG);
}
}
}
private List getConstraints() {
final List constraints = new ArrayList(32);
// normally, i do this with scanning the classpath, but that´d bring
// another dependency ;)
// class-level
constraints.add(new MultipleId());
constraints.add(new MultipleVersions());
constraints.add(new NoId());
constraints.add(new EmbeddedAndId());
constraints.add(new EntityAndEmbed());
constraints.add(new EmbeddedAndValue());
constraints.add(new EntityCannotBeMapOrIterable());
constraints.add(new DuplicatedAttributeNames());
// constraints.add(new ContainsEmbeddedWithId());
// field-level
constraints.add(new MisplacedProperty());
constraints.add(new ReferenceToUnidentifiable());
constraints.add(new LazyReferenceMissingDependencies());
constraints.add(new LazyReferenceOnArray());
constraints.add(new MapKeyDifferentFromString());
constraints.add(new MapNotSerializable());
constraints.add(new VersionMisuse(creator));
//
constraints.add(new ContradictingFieldAnnotation(Reference.class, Serialized.class));
constraints.add(new ContradictingFieldAnnotation(Reference.class, Property.class));
constraints.add(new ContradictingFieldAnnotation(Reference.class, Embedded.class));
//
constraints.add(new ContradictingFieldAnnotation(Embedded.class, Serialized.class));
constraints.add(new ContradictingFieldAnnotation(Embedded.class, Property.class));
//
constraints.add(new ContradictingFieldAnnotation(Property.class, Serialized.class));
return constraints;
}
static class LogLine implements Comparable {
private final ConstraintViolation v;
LogLine(final ConstraintViolation v) {
this.v = v;
}
@Override
public int compareTo(final LogLine o) {
return v.getPrefix().compareTo(o.v.getPrefix());
}
@Override
public int hashCode() {
return v.hashCode();
}
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final LogLine logLine = (LogLine) o;
return v.equals(logLine.v);
}
void log(final Logger logger) {
switch (v.getLevel()) {
case SEVERE:
logger.error(v.render());
break;
case WARNING:
logger.warning(v.render());
break;
case INFO:
logger.info(v.render());
break;
case MINOR:
logger.debug(v.render());
break;
default:
throw new IllegalStateException(format("Cannot log %s of Level %s", ConstraintViolation.class.getSimpleName(),
v.getLevel()));
}
}
}
}