jodd.vtor.Vtor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jodd-vtor Show documentation
Show all versions of jodd-vtor Show documentation
Jodd VTor is focused validation framework for any Java object.
// Copyright (c) 2003-present, Jodd Team (http://jodd.org)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
package jodd.vtor;
import jodd.bean.BeanUtil;
import jodd.util.StringUtil;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
/**
* Vtor validator.
*/
public class Vtor {
/**
* Static constructor for fluent usage.
*/
public static Vtor create() {
return new Vtor();
}
public static final String DEFAULT_PROFILE = "default";
public static final String ALL_PROFILES = "*";
// ---------------------------------------------------------------- violations
protected List violations;
/**
* Adds new {@link Violation violation}. Violations are added during {@link #validate(ValidationContext, Object, String) validation}.
* They can be added after the validation as well, with null
check (and constraint).
*/
public void addViolation(final Violation v) {
if (v == null) {
return;
}
if (violations == null) {
violations = new ArrayList<>();
}
violations.add(v);
}
/**
* Resets list of all violations.
*/
public void resetViolations() {
violations = null;
}
// ---------------------------------------------------------------- validation
/**
* Validate object using context from the annotations.
*/
public List validate(final Object target) {
return validate(ValidationContext.resolveFor(target.getClass()), target);
}
/**
* @see #validate(ValidationContext, Object, String)
*/
public List validate(final ValidationContext vctx, final Object target) {
return validate(vctx, target, null);
}
/**
* Performs validation of provided validation context and appends violations.
*/
public List validate(final ValidationContext ctx, final Object target, final String targetName) {
for (Map.Entry> entry : ctx.map.entrySet()) {
String name = entry.getKey();
Object value = BeanUtil.declaredSilent.getProperty(target, name);
String valueName = targetName != null ? (targetName + '.' + name) : name; // move up
ValidationConstraintContext vcc = new ValidationConstraintContext(this, target, valueName);
for (Check check : entry.getValue()) {
String[] checkProfiles = check.getProfiles();
if (!matchProfiles(checkProfiles)) {
continue;
}
if (check.getSeverity() < severity) {
continue;
}
ValidationConstraint constraint = check.getConstraint();
if (!constraint.isValid(vcc, value)) {
addViolation(new Violation(valueName, target, value, check));
}
}
}
return getViolations();
}
// ---------------------------------------------------------------- severity
protected int severity;
/**
* Set validation severity. Only checks with equal and higher severity
* will be checked.
*/
public void setSeverity(final int severity) {
this.severity = severity;
}
// ---------------------------------------------------------------- profiles
protected HashSet enabledProfiles;
protected boolean validateAllProfilesByDefault;
public boolean isValidateAllProfilesByDefault() {
return validateAllProfilesByDefault;
}
/**
* Specifies how to validate when no profiles is specified.
* If set to true
, then all profiles will be validated;
* otherwise, only default profiles will be validated.
*/
public void setValidateAllProfilesByDefault(final boolean validateAllProfilesByDefault) {
this.validateAllProfilesByDefault = validateAllProfilesByDefault;
}
/**
* Enables single profile.
*/
public void useProfile(final String profile) {
if (profile == null) {
return;
}
if (this.enabledProfiles == null) {
this.enabledProfiles = new HashSet<>();
}
this.enabledProfiles.add(profile);
}
/**
* Enables list of profiles.
*/
public void useProfiles(final String... enabledProfiles) {
if (enabledProfiles == null) {
return;
}
if (this.enabledProfiles == null) {
this.enabledProfiles = new HashSet<>();
}
Collections.addAll(this.enabledProfiles, enabledProfiles);
}
/**
* Reset profiles by clearing all enabled profiles
* and setting to default state.
* @see #setValidateAllProfilesByDefault(boolean)
*/
public void resetProfiles() {
enabledProfiles = null;
}
/**
* Determine if any of checks profiles is among enabled profiles.
*/
protected boolean matchProfiles(final String[] checkProfiles) {
// test for all profiles
if ((checkProfiles != null) && (checkProfiles.length == 1) && checkProfiles[0].equals(ALL_PROFILES)) {
return true;
}
if (enabledProfiles == null || enabledProfiles.isEmpty()) {
if (validateAllProfilesByDefault) {
return true; // all profiles are considered as enabled
}
// only default profile is enabled
if ((checkProfiles == null) || (checkProfiles.length == 0)) {
return true;
}
for (String profile : checkProfiles) {
if (StringUtil.isEmpty(profile)) {
return true; // default profile
}
if (profile.equals(DEFAULT_PROFILE)) {
return true;
}
}
return false;
}
// there are enabled profiles
if ((checkProfiles == null) || (checkProfiles.length == 0)) {
return enabledProfiles.contains(DEFAULT_PROFILE);
}
boolean result = false;
for (String profile : checkProfiles) {
boolean b = true;
boolean must = false;
if (StringUtil.isEmpty(profile)) {
profile = DEFAULT_PROFILE;
} else if (profile.charAt(0) == '-') {
profile = profile.substring(1);
b = false;
} else if (profile.charAt(0) == '+') {
profile = profile.substring(1);
must = true;
}
if (enabledProfiles.contains(profile)) {
if (!b) {
return false;
}
result = true;
} else {
if (must) {
return false;
}
}
}
return result;
}
// ---------------------------------------------------------------- after validation
/**
* Returns the list of validation violations or null
if validation is successful.
*/
public List getViolations() {
return violations;
}
/**
* Returns true
if there are validations.
*/
public boolean hasViolations() {
return violations != null;
}
}