ItEr34S11ArquitecturaServidorItEr33S13: Improvements to validation architecture.

"validate" method has been added to BaseEntity, GenericDAOHibernate has been refactored to use BaseEntity's "validate" method, @AssertTrue annotation has been uncommented in method "checkConstraintUniqueCriterionTypeName" in CriterionType entity and "validate" method removed, test cases fixed in CriterionTypeDAOTest ("testCriterionTypeCanBeSavedTwice" was removed since it was not conceptually correct, "testCannotSaveTwoDifferentCriterionTypesWithTheSameName" was implemented
wrongly), and finally, CriterionServiceREST now uses "GenericDao::save" to validate and save.
This commit is contained in:
Fernando Bellas Permuy 2009-11-09 21:37:52 +01:00 committed by Javier Moran Rua
parent 525fa4a556
commit 5ada35d5a5
5 changed files with 28 additions and 82 deletions

View file

@ -20,7 +20,10 @@
package org.navalplanner.business.common;
import org.hibernate.validator.ClassValidator;
import org.hibernate.validator.InvalidValue;
import org.navalplanner.business.INewObject;
import org.navalplanner.business.common.exceptions.ValidationException;
/**
@ -29,6 +32,7 @@ import org.navalplanner.business.INewObject;
* It provides the basic behavior for id and version fields.
*
* @author Manuel Rego Casasnovas <mrego@igalia.com>
* @author Fernando Bellas Permuy <fbellas@udc.es>
*/
public abstract class BaseEntity implements INewObject {
@ -80,4 +84,13 @@ public abstract class BaseEntity implements INewObject {
setNewObject(false);
}
@SuppressWarnings("unchecked")
public void validate() throws ValidationException {
ClassValidator classValidator = new ClassValidator(this.getClass());
InvalidValue[] invalidValues = classValidator.getInvalidValues(this);
if (invalidValues.length > 0) {
throw new ValidationException(invalidValues);
}
}
}

View file

@ -32,8 +32,7 @@ import org.hibernate.SessionFactory;
import org.hibernate.StaleObjectStateException;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.validator.ClassValidator;
import org.hibernate.validator.InvalidValue;
import org.navalplanner.business.common.BaseEntity;
import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
import org.navalplanner.business.common.exceptions.ValidationException;
import org.springframework.beans.factory.annotation.Autowired;
@ -57,8 +56,8 @@ import org.springframework.transaction.annotation.Transactional;
* @param <PK>
* Primary key class
*/
public class GenericDAOHibernate<E, PK extends Serializable> implements
IGenericDAO<E, PK> {
public class GenericDAOHibernate<E extends BaseEntity,
PK extends Serializable> implements IGenericDAO<E, PK> {
private Class<E> entityClass;
@ -81,20 +80,10 @@ public class GenericDAOHibernate<E, PK extends Serializable> implements
}
public void save(E entity) throws ValidationException {
checkIsValid(entity);
entity.validate();
getSession().saveOrUpdate(entity);
}
@SuppressWarnings("unchecked")
private void checkIsValid(E entity) throws ValidationException {
Class<E> entityClass = (Class<E>) entity.getClass();
ClassValidator<E> classValidator = new ClassValidator<E>(entityClass);
InvalidValue[] invalidValues = classValidator.getInvalidValues(entity);
if (invalidValues.length > 0) {
throw new ValidationException(invalidValues);
}
}
public void reattachUnmodifiedEntity(E entity) {
getSession().lock(entity, LockMode.NONE);

View file

@ -20,14 +20,11 @@
package org.navalplanner.business.resources.entities;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.hibernate.validator.AssertTrue;
import org.hibernate.validator.ClassValidator;
import org.hibernate.validator.InvalidValue;
import org.hibernate.validator.NotEmpty;
import org.hibernate.validator.Valid;
import org.navalplanner.business.common.BaseEntity;
@ -284,12 +281,7 @@ public class CriterionType extends BaseEntity implements
}
// FIXME: Surprisingly, @AssertTrue in this method causes the Maven build to
// fail due to out of memory (probably due to the configuration of Hibernate to
// automatically execute validations when saving entities). Provisionally,
// "validate" method has been provided as a hack.
// FIXME: Internationalization must be provided.
// @AssertTrue(message="el nombre del tipo de criterion ya se está usando")
@AssertTrue(message="el nombre del tipo de criterion ya se está usando")
public boolean checkConstraintUniqueCriterionTypeName() {
ICriterionTypeDAO criterionTypeDAO = Registry.getCriterionTypeDAO();
@ -340,28 +332,4 @@ public class CriterionType extends BaseEntity implements
}
// FIXME: hack to overcome problem with @AssertTrue and
// "checkConstraintUniqueCriterionTypeName" method.
public InvalidValue[] validate() {
ClassValidator<CriterionType> criterionTypeValidator =
new ClassValidator<CriterionType>(CriterionType.class);
InvalidValue[] invalidValues =
criterionTypeValidator.getInvalidValues(this);
if (!checkConstraintUniqueCriterionTypeName()) {
invalidValues =
Arrays.copyOf(invalidValues, invalidValues.length+1);
invalidValues[invalidValues.length-1] =
new InvalidValue("el nombre del tipo de criterion ya se " +
"está usando", CriterionType.class,
"checkConstraintUniqueCriterionTypeName",
null, this);
}
return invalidValues;
}
}

View file

@ -23,7 +23,6 @@ package org.navalplanner.business.test.resources.daos;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.navalplanner.business.BusinessGlobalNames.BUSINESS_SPRING_CONFIG_FILE;
import static org.navalplanner.business.test.BusinessGlobalNames.BUSINESS_SPRING_CONFIG_TEST_FILE;
@ -31,7 +30,6 @@ import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import org.hibernate.exception.ConstraintViolationException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
@ -40,7 +38,6 @@ import org.navalplanner.business.resources.daos.ICriterionTypeDAO;
import org.navalplanner.business.resources.entities.CriterionType;
import org.navalplanner.business.resources.entities.ResourceEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
@ -82,30 +79,13 @@ public class CriterionTypeDAOTest {
assertTrue(criterionTypeDAO.exists(criterionType.getId()));
}
@Test
public void testCriterionTypeCanBeSavedTwice() throws ValidationException {
CriterionType criterionType = createValidCriterionType();
criterionTypeDAO.save(criterionType);
criterionTypeDAO.save(criterionType);
assertTrue(criterionTypeDAO.exists(criterionType.getId())
|| criterionTypeDAO.existsByName(criterionType));
}
@Test
@Test(expected=ValidationException.class)
public void testCannotSaveTwoDifferentCriterionTypesWithTheSameName()
throws ValidationException {
try {
CriterionType criterionType = createValidCriterionType("bla","");
criterionTypeDAO.save(criterionType);
criterionType = createValidCriterionType("bla","");
criterionTypeDAO.save(criterionType);
criterionTypeDAO.flush();
fail("must send exception since thereis a duplicated criterion type");
} catch (ConstraintViolationException c) {
// This exception is raised in postgresql
} catch (DataIntegrityViolationException d) {
// This exception is raised in HSQL
}
CriterionType criterionType = createValidCriterionType("bla","");
criterionTypeDAO.save(criterionType);
criterionType = createValidCriterionType("bla","");
criterionTypeDAO.save(criterionType);
}
@Test

View file

@ -29,7 +29,7 @@ import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import org.hibernate.validator.InvalidValue;
import org.navalplanner.business.common.exceptions.ValidationException;
import org.navalplanner.business.resources.daos.ICriterionTypeDAO;
import org.navalplanner.business.resources.entities.CriterionType;
import org.navalplanner.ws.common.api.InstanceConstraintViolationsDTO;
@ -86,19 +86,15 @@ public class CriterionServiceREST implements ICriterionService {
CriterionType criterionType =
CriterionConverter.toEntity(criterionTypeDTO);
InvalidValue[] invalidValues =
criterionType.validate();
if (invalidValues.length > 0) {
try {
criterionTypeDAO.save(criterionType);
} catch (ValidationException e) {
instanceConstraintViolationsList.add(
ConstraintViolationConverter.toDTO(
generateInstanceId(instanceNumber,
criterionTypeDTO.name),
invalidValues));
} else {
criterionTypeDAO.save(criterionType);
e.getInvalidValues()));
}
instanceNumber++;