/***************************************************************** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. ****************************************************************/ package org.apache.cayenne.validation; import java.util.Collection; import org.apache.cayenne.CayenneRuntimeException; import org.apache.cayenne.reflect.PropertyUtils; /** * ValidationFailure implementation that described a failure of a single named property of * a Java Bean object. * * @since 1.1 */ public class BeanValidationFailure extends SimpleValidationFailure { protected String property; private static String validationMessage(String attribute, String message) { StringBuilder buffer = new StringBuilder(message.length() + attribute.length() + 5); buffer.append('\"').append(attribute).append("\" ").append(message); return buffer.toString(); } /** * Returns a ValidationFailure if a collection attribute of an object is null or * empty. */ public static ValidationFailure validateNotEmpty( Object bean, String attribute, Collection<?> value) { if (value == null) { return new BeanValidationFailure(bean, attribute, validationMessage( attribute, " is required.")); } if (value.isEmpty()) { return new BeanValidationFailure(bean, attribute, validationMessage( attribute, " can not be empty.")); } return null; } public static ValidationFailure validateMandatory( Object bean, String attribute, Object value) { if (value instanceof String) { return validateNotEmpty(bean, attribute, (String) value); } if (value instanceof Collection) { return validateNotEmpty(bean, attribute, (Collection<?>) value); } return validateNotNull(bean, attribute, value); } public static ValidationFailure validateMandatory(Object bean, String attribute) { if (bean == null) { throw new NullPointerException("Null bean."); } try { Object result = PropertyUtils.getProperty(bean, attribute); return validateMandatory(bean, attribute, result); } catch (Exception ex) { throw new CayenneRuntimeException("Error validationg bean property: " + bean.getClass().getName() + "." + attribute, ex); } } public static ValidationFailure validateNotNull( Object bean, String attribute, Object value) { if (value == null) { return new BeanValidationFailure(bean, attribute, validationMessage( attribute, " is required.")); } return null; } /** * A utility method that returns a ValidationFailure if a string is either null or has * a length of zero; otherwise returns null. */ public static ValidationFailure validateNotEmpty( Object bean, String attribute, String value) { if (value == null || value.length() == 0) { return new BeanValidationFailure(bean, attribute, validationMessage( attribute, " is a required field.")); } return null; } /** * A utility method that checks that a given string is a valid Java full class name, * returning a non-null ValidationFailure if this is not so. * * Special case: primitive arrays like byte[] are also handled as a valid java * class name. * * @since 1.2 */ public static ValidationFailure validateJavaClassName( Object bean, String attribute, String identifier) { ValidationFailure emptyFailure = validateNotEmpty(bean, attribute, identifier); if (emptyFailure != null) { return emptyFailure; } char c = identifier.charAt(0); if (!Character.isJavaIdentifierStart(c)) { return new BeanValidationFailure(bean, attribute, validationMessage( attribute, " starts with invalid character: " + c)); } // handle arrays if (identifier.endsWith("[]")) { identifier = identifier.substring(0, identifier.length() - 2); } boolean wasDot = false; for (int i = 1; i < identifier.length(); i++) { c = identifier.charAt(i); if (c == '.') { if (wasDot || i + 1 == identifier.length()) { return new BeanValidationFailure(bean, attribute, validationMessage( attribute, " is not a valid Java Class Name: " + identifier)); } wasDot = true; continue; } if (!Character.isJavaIdentifierPart(c)) { return new BeanValidationFailure(bean, attribute, validationMessage( attribute, " contains invalid character: " + c)); } wasDot = false; } return null; } /** * Creates new BeanValidationFailure. */ public BeanValidationFailure(Object source, String property, Object error) { super(source, error); if (source == null && property != null) { throw new IllegalArgumentException( "ValidationFailure cannot have 'property' when 'source' is null."); } this.property = property; } /** * Returns a failed property of the failure source object. */ public String getProperty() { return property; } /** * Returns a String representation of the failure. */ @Override public String toString() { StringBuilder buffer = new StringBuilder(); buffer.append("Validation failure for "); Object source = getSource(); if (source == null) { buffer.append("[General]"); } else { String property = getProperty(); buffer.append(source.getClass().getName()).append('.').append( (property == null ? "[General]" : property)); } buffer.append(": "); buffer.append(getDescription()); return buffer.toString(); } }