protected void validateForSave()

in cayenne/src/main/java/org/apache/cayenne/PersistentObject.java [548:663]


    protected void validateForSave(ValidationResult validationResult) {

        ObjEntity objEntity = getObjectContext().getEntityResolver().getObjEntity(this);
        if (objEntity == null) {
            throw new CayenneRuntimeException("No ObjEntity mapping found for Persistent %s", getClass().getName());
        }

        // validate mandatory attributes

        Map<String, ValidationFailure> failedDbAttributes = null;

        for (ObjAttribute next : objEntity.getAttributes()) {
            // TODO: andrus, 2/20/2007 - handle embedded attribute
            if (next instanceof EmbeddedAttribute) {
                continue;
            }

            DbAttribute dbAttribute = next.getDbAttribute();
            if (dbAttribute == null) {
                throw new CayenneRuntimeException("ObjAttribute '%s"
                        + "' does not have a corresponding DbAttribute", next.getName());
            }

            // pk may still be generated
            if (dbAttribute.isPrimaryKey()) {
                continue;
            }

            Object value = this.readPropertyDirectly(next.getName());
            if (dbAttribute.isMandatory()) {
                ValidationFailure failure = BeanValidationFailure.validateNotNull(this, next.getName(), value);

                if (failure != null) {

                    if (failedDbAttributes == null) {
                        failedDbAttributes = new HashMap<>();
                    }

                    failedDbAttributes.put(dbAttribute.getName(), failure);
                    continue;
                }
            }

            // validate length
            if (value != null && dbAttribute.getMaxLength() > 0) {
                if (value.getClass().isArray()) {
                    int len = Array.getLength(value);
                    if (len > dbAttribute.getMaxLength()) {
                        String message = "\"" + next.getName() + "\" exceeds maximum allowed length ("
                                + dbAttribute.getMaxLength() + " bytes): " + len;
                        validationResult.addFailure(new BeanValidationFailure(this, next.getName(), message));
                    }
                } else if (value instanceof CharSequence) {
                    int len = ((CharSequence) value).length();
                    if (len > dbAttribute.getMaxLength()) {
                        String message = "\"" + next.getName() + "\" exceeds maximum allowed length ("
                                + dbAttribute.getMaxLength() + " chars): " + len;
                        validationResult.addFailure(new BeanValidationFailure(this, next.getName(), message));
                    }
                }
            }
        }

        // validate mandatory relationships
        for (final ObjRelationship relationship : objEntity.getRelationships()) {

            List<DbRelationship> dbRels = relationship.getDbRelationships();
            if (dbRels.isEmpty()) {
                continue;
            }

            // skip db relationships that we can't validate or that can't be invalid here
            // can't handle paths longer than two db relationships
            // see ObjRelationship.recalculateReadOnlyValue() for more info
            if (relationship.isSourceIndependentFromTargetChange()) {
                continue;
            }

            // if db relationship is not based on a PK and is based on mandatory
            // attributes, see if we have a target object set
            // relationship will be validated only if all db path has mandatory
            // db relationships
            boolean validate = true;
            for (DbRelationship dbRelationship : dbRels) {
                for (DbJoin join : dbRelationship.getJoins()) {
                    DbAttribute source = join.getSource();
                    if (source.isMandatory()) {
                        // clear attribute failures...
                        if (failedDbAttributes != null && !failedDbAttributes.isEmpty()) {
                            failedDbAttributes.remove(source.getName());
                        }
                    } else {
                        // do not validate if the relation is based on
                        // multiple keys with some that can be nullable.
                        validate = false;
                    }
                }
            }

            if (validate) {
                Object value = this.readPropertyDirectly(relationship.getName());
                ValidationFailure failure = BeanValidationFailure.validateNotNull(this, relationship.getName(), value);

                if (failure != null) {
                    validationResult.addFailure(failure);
                }
            }
        }

        // deal with previously found attribute failures...
        if (failedDbAttributes != null && !failedDbAttributes.isEmpty()) {
            for (ValidationFailure failure : failedDbAttributes.values()) {
                validationResult.addFailure(failure);
            }
        }
    }