java oval 使用_OVal 使用指南

OVal is a pragmatic and extensible general purpose validation framework for any kind of Java objects

(not only JavaBeans) and allows you:

to easily validate objects on demand,

to specify constraints for class fields and getter methods,

to validate objects based on certain EJB3 JPA annotations (namely all field annotations that require a

not-null value),

to configure constraints via annotations, POJOs and/or simple XML files,

to express constraints using scripting languages such as Groovy, BeanShell, and JavaScript

to easily create custom constraints, and

to develop new constraint configuration mechanisms

When using AspectJ certain programming by contract (aka Design By Contract™ or DBC)

features are available:

specifying constraints for constructor parameters that are automatically checked

when a constructor is called (preconditions),

specifying constraints for method parameters that are automatically checked when

a method is called (preconditions),

requiring a certain object state before a method is called (preconditions)

enforcing object validation after an object has been created (invariants),

enforcing object validation before/after a method of an object is/has been called (invariants),

specifying constrains for a method's return value that are automatically checked after a method has been

executed (postconditions),

requiring a certain object state after a method is called (postconditions).

Missing a useful feature? Let's discuss it in the

OVal forum

OVal requires Java 5 or later - mainly for annotation support but other new language features (generics, for

each loop, etc.) are used across the OVal source code too. Java 5 is actually the only hard requirement, depending

on the features you want to use additional libraries are required:

AspectJ is required if you want to use the above mentioned programming by contract features.

Apache Commons JEXL is required if you want to define constraints via JEXL expressions.

BeanShell is required if you want to define constraints via BeanShell expressions.

Groovy is required if you want to define constraints via Groovy expressions.

JRuby is required if you want to define constraints via Ruby expressions.

Mozilla Rhino is required if you want to define constraints via JavaScript expressions.

MVEL is required if you want to define constraints via MVEL expressions.

OGNL is required if you want to define constraints via OGNL expressions.

XStream is required if you want to configure OVal via XML configuration files.

GNU Trove is required if you want to have OVal to internally use the GNU Trove high performance collections.

Javolution is required if you want to have OVal to internally use Javolution's high performance collections.

JXPath is required if you want to use JXPath expressions for the constraint target declarations.

JUnit and all other libraries are required if you want to run the test cases.

You can add constraint annotations to class fields that are checked when an object validation is performed.

There exists a number of pre-built constraints that you can find in the package

net.sf.oval.constraint .

An object can be validated by using the public validate(Object validatedObject) method

of net.sf.oval.Validator

public class BusinessObject {

@NotNull

@NotEmpty

@Length(max=32)

private String name;

...

}

Example usage:

Validator validator = new Validator();

BusinessObject bo = new BusinessObject();

// collect the constraint violations

List violations = validator.validate(bo);

if(violations.size()>0)

{

LOG.severe("Object " + bo + " is invalid.");

throw new BussinessException(violations);

}

You can specify constraints for the return value of getter methods. When validating the object the values

of all fields and the return values of the getter methods are checked against the specified constraints.

The methods need to be annotated with @net.sf.oval.configuration.annotation.IsInvariant.

Return value constraints specified for methods missing this annotation are ignored during validation.

Important: To retrieve the return value of the getter method OVal invokes the getter

during the validation process. Therefore you need to ensure that the getter method really is just a getter method

and does not change the object state.

public class BusinessObject

{

private String name = null;

@IsInvariant

@NotNull

@Length(max = 4)

public String getName()

{

return name;

}

...

}

Example usage:

Validator validator = new Validator();

BusinessObject bo = new BusinessObject("blabla");

List violations = validator.validate(bo);

if(violations.size()>0)

{

LOG.severe("Object " + bo + " is invalid.");

throw new BussinessException(violations);

}

When you annotate a field or getter with multiple constraint annotations they are ANDed.

If you require other logical constructs you can use a scripting language to express them.

To do so annotate the field or getter with the @net.sf.oval.constraint.Assert

annotation as shown in the following example:

public class BusinessObject

{

@NotNull

public String deliveryAddress;

@NotNull

public String invoiceAddress;

@Assert(expr = "_value ==_this.deliveryAddress || _value == _this.invoiceAddress", lang = "groovy")

public String mailingAddress;

}

The expr parameter holds the script to be evaluated. If the script returns

true the constraint is satisfied. OVal provides two special variables:

_value - contains the value to validate (field value or getter return value)

_this - is a reference to the validated object

The lang parameter specifies the scripting language you want to use. In case the required

libraries are loaded, OVal is aware of these languages:

bsh or beanshell for BeanShell,

groovy for Groovy,

jexl for JEXL,

js or javascript for JavaScript (via Mozilla Rhino),

mvel for MVEL,

ognl for OGNL,

ruby or jruby for Ruby (via JRuby)

Additional scripting languages can be registered via Validator.addExpressionLanguage(String, ExpressionLanguage).

Besides using @Assert to declare conditional constraints it is also possible to specify a activation rules

for other constraints using the when attribute. This way you can for example turn on or off

constraints based on a given state of the object. The when attribute can hold a formula in one

of the supported expression languages, it is prefixed by the id of the expression language to be used.

In the following example fieldB must not be null only if

fieldA is not null as well. With the prefix groovy: it

is indicated that the formula is expressed in the Groovy language.

public class BusinessObject

{

private String fieldA;

@NotNull(when = "groovy:_this.fieldA != null")

private String fieldB;

}

Using the target attribute of constraints you can specify the path to an object where the constraint should be applied.

In the following example the @NotNull constraint will be validated for the customer.homeAddress.street field.

public class BusinessObject

{

@AssertValid

@NotNull(target="homeAddress.street")

private Customer customer;

}

If JXPath is on the classpath you can also use the XPath syntax to specify the target value. In the following example the @NotNull constraint

will be checked for street field of the first address object in the customer.addresses collection.

public class BusinessObject

{

@AssertValid

@NotNull(target="jxpath:addresses[0]/street")

private Customer customer;

}

To target values of maps or collections JXPath must be used, the built-in implementation does not support this yet.

By specifying the special constraint annotation @AssertValid you instruct OVal to ensure that all constraints

declared on the referenced object are satisfied too.

public class BusinessObject

{

@NotNull

@AssertValid

private Address address;

}

OVal's configuration mechanism is highly customizable. Using the

net.sf.oval.configuration.Configurer interface you can write your own constraint configurers

configuring OVal based on other XML schemas, other sets of annotations or anything else you like.

OVal comes with a configurer that is capable of translating certain EJB3 JPA annotations into equivalent

OVal constraints. The net.sf.oval.configuration.annotation.JPAAnnotationsConfigurer interprets

the EJB3 JPA annotations as follows:

@javax.persistence.Basic(optional=false) => @net.sf.oval.constraint.NotNull

@javax.persistence.OneToOne(optional=false) => @net.sf.oval.constraint.NotNull

@javax.persistence.OneToOne => @net.sf.oval.constraint.AssertValid

@javax.persistence.OneToMany => @net.sf.oval.constraint.AssertValid

@javax.persistence.ManyToOne(optional=false) => @net.sf.oval.constraint.NotNull

@javax.persistence.ManyToOne => @net.sf.oval.constraint.AssertValid

@javax.persistence.Column(nullable=false) => @net.sf.oval.constraint.NotNull

(only applied for fields not annotated with @javax.persistence.GeneratedValue or @javax.persistence.Version)

@javax.persistence.Column(length=5) => @net.sf.oval.constraint.Length

@Entity

public class MyEntity

{

@Basic(optional = false)

@Column(length = 4)

public String id;

@Column(nullable = false)

public String descr;

@ManyToOne(optional = false)

public MyEntity parent;

}

Example usage:

Validator validator = new Validator(new AnnotationsConfigurer(), new JPAAnnotationsConfigurer());

MyEntity entity = new MyEntity();

entity.id = "12345";

entity.descr = null; // violation - cannot be null

entity.parent = null;

// collect the constraint violations

List violations = validator.validate(entity);

OVal itself is not a JSR303/JSR380 compliant bean validation framework. However it now comes with a configurer

that can translate the standard Bean Validation constraints (javax.validation.constraints.*) into equivalent OVal constraints.

The net.sf.oval.configuration.annotation.BeanValidationAnnotationsConfigurer interprets

the annotations as follows:

@javax.validation.constraints.AssertFalse => @net.sf.oval.constraint.AssertFalse

@javax.validation.constraints.AssertTrue => @net.sf.oval.constraint.AssertTrue

@javax.validation.constraints.DecimalMax => @net.sf.oval.constraint.Max

@javax.validation.constraints.DecimalMin => @net.sf.oval.constraint.Min

@javax.validation.constraints.Digits => @net.sf.oval.constraint.Digits

@javax.validation.constraints.Email => @net.sf.oval.constraint.Email

@javax.validation.constraints.Future => @net.sf.oval.constraint.Future

@javax.validation.constraints.FutureOrPresent => @net.sf.oval.constraint.Future(min="now")

@javax.validation.constraints.Max => @net.sf.oval.constraint.Max

@javax.validation.constraints.Min => @net.sf.oval.constraint.Min

@javax.validation.constraints.Negative => @net.sf.oval.constraint.Max(max=0, inclusive=false)

@javax.validation.constraints.NegativeOrZero => @net.sf.oval.constraint.Max(max=0, inclusive=true)

@javax.validation.constraints.NotBlank => @net.sf.oval.constraint.NotBlank

@javax.validation.constraints.NotEmpty => @net.sf.oval.constraint.NotEmpty

@javax.validation.constraints.NotNull => @net.sf.oval.constraint.NotNull

@javax.validation.constraints.Null => @net.sf.oval.constraint.Null

@javax.validation.constraints.Past => @net.sf.oval.constraint.Past

@javax.validation.constraints.PastOrPresent => @net.sf.oval.constraint.Past(max="now")

@javax.validation.constraints.Pattern => @net.sf.oval.constraint.Pattern

@javax.validation.constraints.Size => @net.sf.oval.constraint.Size

@javax.validation.constraints.Positive => @net.sf.oval.constraint.Min(min=0, inclusive=false)

@javax.validation.constraints.PositiveOrZero => @net.sf.oval.constraint.NotNegative

@javax.validation.constraints.Valid => @net.sf.oval.constraint.AssertValid

public class MyEntity

{

@javax.validation.constraints.NotNull

@javax.validation.constraints.Size(max = 4)

public String id;

@javax.validation.constraints.NotNull

public String descr;

@javax.validation.constraints.NotNull

public MyEntity parent;

}

Example usage:

Validator validator = new Validator(new AnnotationsConfigurer(), new BeanValidationAnnotationsConfigurer());

MyEntity entity = new MyEntity();

entity.id = "12345";

entity.descr = null; // violation - cannot be null

entity.parent = null;

// collect the constraint violations

List violations = validator.validate(entity);

By utilizing AspectJ OVal provides support for several aspects of programming by contract - however it is

not a full blown programming by contract implementation.

With OVal you can

enforce that a parameterized constructor/method is invoked only if the given arguments satisfy prior defined constraints(precondition)

enforce that a method is invoked only if the object is in a certain state (precondition/invariant)

enforce that the return value of a method must satisfy prior defined constraints (postcondition)

enforce that the object must be in a certain state after a method has been executed (postcondition/invariant)

The easiest way to getting started is to use the

Eclipse IDE in conjunction with the

AspectJ plug-in.

Create a new AspectJ project or add AspectJ support to an existing Java project by right-clicking the project

in the Package Explorer and selecting Convert To AspectJ Project

Add the net.sf.oval_x.x.jar file to your library path.

Create a new aspect via File -> New -> Aspect that extends the abstract aspect

net.sf.oval.guard.GuardAspect. When the new aspect is created the AspectJ builder will

automatically weave the validation related code into your compiled classes annotated with

@net.sf.oval.guard.Guarded.

Now you can create all your business classes, add the @net.sf.oval.guard.Guarded

annotation and define the required constraints using the built-in or custom constraint annotations.

Constraints specified for constructor parameters are automatically checked when the constructor is invoked.

Invocations of the constructor will be prohibited if any of the constraints is not satisfied. In such a case a

net.sf.oval.exception.ConstraintsViolatedException will be thrown.

@Guarded

public class BusinessObject

{

public BusinessObject(@NotNull String name)

{

this.name = name;

}

...

}

Example usage:

BusinessObject bo = new BusinessObject(null);

Constraints specified for method parameters are automatically checked when the method is invoked.

Invocations of to the method will be prohibited if any of the constraints is not satisfied. In such a case

a net.sf.oval.exception.ConstraintsViolatedException will be thrown.

@Guarded

public class BusinessObject

{

public void setName(@NotNull String name)

{

this.name = name;

}

...

}

Example usage:

BusinessObject bo = new BusinessObject();

bo.setName(null);

You can apply the constraints specified for a field in the same or a super class to any constructor or

method parameter by using the @net.sf.oval.constraint.AssertFieldConstraints annotation.

If you do not specify a field name within the @net.sf.oval.constraint.AssertFieldConstraints

annotation the constraints of the field with the same name as the annotated parameter are applied to the parameter.

If you specify a field name within the @net.sf.oval.constraint.AssertFieldConstraints

annotation the constraints of the field with the specified name are applied to the annotated parameter.

@Guarded

public class BusinessObject

{

@NotNull

@NotEmpty

@Length(max=10)

private String name;

public void setName(@AssertFieldConstraints String name)

{

this.name = name;

}

public void setAlternativeName(@AssertFieldConstraints("name") String altName)

{

this.alternativeName = altName;

}

...

}

Example usage:

BusinessObject bo = new BusinessObject();

bo.setName("");

bo.setAlternativeName(null); // throws a ConstraintsViolatedException because parameter is null

If you like to apply the constraints of all fields to their corresponding setter methods you can

alternatively set the applyFieldConstraintsToSetters property of the

Guarded annotation to true. This is especially useful if you have

a lot of setter methods and you are following the JavaBean convention. Important: The setter method

must be declared within the same class as the property.

@Guarded(applyFieldConstraintsToSetters=true)

public class BusinessObject

{

@NotNull

@NotEmpty

@Length(max=10)

private String name;

public void setName(String name)

{

this.name = name;

}

...

}

Another convenience option is the applyFieldConstraintsToConstructors property of the

Guarded annotation. If set to true, OVal applies the specified field constraints to the

corresponding parameters of the declared constructors within the same class. In this context, a corresponding

parameter is a constructor parameter with the same name and type as the field.

Similar to the above described @net.sf.constraint.Assert constraint annotation for

fields you can annotate a method with @net.sf.guard.Pre allowing you to express

conditional constraints using a scripting language.

@Guarded

public class Transaction

{

private BigDecimal amount;

@Pre(expr = "_this.amount!=null && amount2add > _this.amount", lang = "groovy")

public void increase(BigDecimal amount2add)

{

amount = amount.add(amount2add);

}

}

The expr parameter holds the script to be evaluated. If the script returns

true the constraint is satisfied. OVal provides special variables for use

within the expression:

_args[] - array holding the method arguments

_this - is a reference to the current object

additionally variables matching the parameter names are available

The lang parameter specifies the scripting language you want to use.

In case the required libraries are loaded, OVal is aware of these languages:

bsh or beanshell for BeanShell,

groovy for Groovy,

jexl for JEXL,

js or javascript for JavaScript (via Mozilla Rhino),

mvel for MVEL,

ognl for OGNL, or

ruby or jruby for Ruby (via JRuby)

You can globally disable or enable the checking of preconditions via the

Guard.setPreConditionsEnabled(boolean) method.

Example usage:

MyAspect.aspectOf().getGuard().setPreConditionsEnabled(false);

By adding constraint annotations to a non-void method you can specify constraints for the method's

return value. When the method is invoked and the return value does not satisfy all constraints a

ConstraintsViolatedException is thrown.

Note: Despite the thrown exception the method code still has been executed,

you have to rollback the changes performed by this method manually.

If a non-void, non-parameterized method is also annotated with @IsInvariant

it's constraints will also be checked when calling the Validator.validate(Object)

method on an object of this type.

@Guarded

public class BusinessObject

{

private String name = null;

@IsInvariant

@NotNull

@Length(max = 4)

public String getName()

{

return name;

}

@NotNull

@Length(max = 4)

public String getNameOrDefault(String default)

{

return name == null ? default : name;

}

...

}

Example usage:

BusinessObject bo = new BusinessObject();

bo.getName();

// throws a ConstraintsViolatedException because the field "name" is null and therefore the default parameter will be returned which has a length < 4 characters

bo.getNameOrDefault("abc");

Validator validator = new Validator();

List violations = validator.validate(bo);

For declaring scripted postconditions you can use the @net.sf.guard.Post annotation

which works similar to @net.sf.guard.Pre for preconditions.

@Guarded

public class Transaction

{

private BigDecimal amount;

@Post(expr = "_this.amount>_old", old = "_this.amount", lang = "groovy")

public void increase(BigDecimal amount2add)

{

amount = amount.add(amount2add);

}

}

The expr parameter holds the script to be evaluated. If the script returns

true the constraint is satisfied. OVal provides special variables for use within the

expression:

_args[] - array holding the method arguments

_this - is a reference to the current object

_returns - the method's return value

_old - see the description of the old parameter below

additionally variables matching the parameter names are available

The lang parameter specifies the scripting language you want to use.

In case the required libraries are loaded, OVal is aware of these languages:

bsh or beanshell for BeanShell,

groovy for Groovy,

jexl for Groovy,

js or javascript for JavaScript (via Mozilla Rhino),

mvel for MVEL,

ognl for OGNL, or

ruby or jruby for Ruby (via JRuby)

The old parameter is optionally, it can hold another expression that is evaluated

before the method is executed. The result is made available in the post constraint expression as a special

variable called _old. The old expression can also return an array or a map allowing you

to store multiple values. This way you can "remember" the old state of multiple properties of an object.

An expression like old = "[amount:_this.amount, date:_this.date]" in Groovy returns a map

with the keys amount and date holding the values of the object's properties

amount and date. These values then can be used in the constraint expression

like this: expression = "_this.amount>_old.amount && _this.date>_old.date".

You can globally disable or enable the checking of postconditions via the

Guard.setPostConditionsEnabled(boolean) method.

Example usage:

MyAspect.aspectOf().getGuard().setPostConditionsEnabled(false);

By default OVal checks class invariants before and after calls to any non-private method of guarded

classes and after constructor execution. If required you can globally disable the automatic checking of

invariants via the Guard.setInvariantsEnabled(boolean) method or for all objects of a

specific class using the Guard.setInvariantsEnabled(Class>, boolean) method.

Example usage:

MyAspect.aspectOf().getGuard().setInvariantsEnabled(false);

If you disabled the automatic check of class invariants you can still enable the checking of the

invariants prior calls to a certain method by annotating the respective method with

@net.sf.oval.guard.PreValidateThis.

In case of constraint violations a ConstraintsViolatedException is thrown and the method will not be executed.

@Guarded

public class BusinessObject

{

@NotNull

private String name = null;

@PreValidateThis

public void save()

{

}

...

}

Example usage:

BusinessObject bo = new BusinessObject();

bo.save();

If you disabled the automatic check of class invariants you can still enable the checking of the

invariants after an object has been instantiated by annotating the constructors of the corresponding class

with @net.sf.oval.guard.PostValidateThis.

In case of constraint violations the constructor will throw a ConstraintsViolatedException

which effectively means the code trying to instantiate the object cannot get hold of a reference to the object

being in an invalidate state and the invalid object will get garbage collected.

@Guarded

public class BusinessObject

{

@NotNull

private String name;

/**

* constructor

*/

@PostValidateThis

public BusinessObject()

{

super();

}

...

}

Example usage:

BusinessObject bo = new BusinessObject();

If you disabled the automatic check of class invariants you can still enable the checking of the

invariants after a method has been executed by annotating the method with

@net.sf.oval.guard.PostValidateThis.

In case of constraint violations the method will throw an ConstraintsViolatedException.

Note: Despite the thrown exception the method code still has been executed,

you have to manually rollback the changes performed by this method.

@Guarded

public class BusinessObject

{

@Length(max=10)

private String name = "12345";

@PostValidateThis

public appendToName(String appendix)

{

name += appendix;

}

...

}

Example usage:

BusinessObject bo = new BusinessObject();

bo.appendToName("123456");

OVal provides a so called probe mode in which you can execute all methods of an object and the guard will

only check the preconditions (e.g. parameter constraints) and not execute the method.

This is especially useful if you want to test input values received from the end user in the UI layer

against the setter methods of a business object. You can simply pass the values to the corresponding setters and

have any detected violations collect by a ConstraintsViolatedListener. Afterwards you can

report all violations back to the UI layer and have them displayed to the end user.

Example business object:

@Guarded

public class Person

{

@NotNegative

private int age;

@Min(5)

private String name = "";

@Length(min=5, max=5)

private String zipCode = "";

public void setAge(@AssertFieldConstraints int age)

{

this.age = age;

}

public void setName(@AssertFieldConstraints String name)

{

this.name = name;

}

public void setZipCode(@AssertFieldConstraints String zipCode)

{

this.zipCode = zipCode;

}

...

}

Example usage:

inputForm.setName("1234");

inputForm.setAge(-4);

inputForm.setZipCode("123");

...

public Person createPerson(PersonInputForm inputForm) throws ConstraintsViolatedException

{

Person person = new Person();

Guard guard = MyGuardAspect.aspectOf().getGuard();

guard.enableProbeMode(person);

// simulate applying the values to the person bean

person.setName(inputForm.getName());

person.setAge(inputForm.getAge());

person.setZipCode(inputForm.getZipCode());

ProbeModeListener result = guard.disableProbeMode(person);

// check if any constraint violations occured

if(result.getConstraintViolations().size() > 0)

{

throw new ConstraintsViolatedException(result.getConstraintViolations());

}

else

{

result.commit();

dao.save(person);

return person;

}

}

When calling methods on guarded objects these methods will throw

ConstraintsViolatedExceptions in case any pre- or postconditions are violated. Their might be

good reasons why you may want to have other exceptions thrown instead of OVal's proprietary exceptions, e.g. JRE

standard exceptions such as IllegalArgumentException or IllegalStateException.

OVal's Guard class allows you to register an exception translator. The exception translator defines a

translateException() method that is executed for all occurring exceptions during runtime validation.

This allows you to translate any OValException thrown during validation into another

RuntimeException which will be thrown instead. As an example have a look at the

net.sf.oval.exception.ExceptionTranslatorJDKExceptionsImpl class how an implementation could look like.

Example usage:

public aspect MyAspect extends GuardAspect

{

public MyAspect()

{

super();

getGuard().setExceptionTranslator(new net.sf.oval.exception.ExceptionTranslatorJDKExceptionsImpl());

}

}

Developing custom annotation based constraints is fairly easy. All you need to do is:

Create a constraint check class that implements net.sf.oval.AnnotationCheck or extends

net.sf.oval.AbstractAnnotationCheck.

public class UpperCaseCheck extends AbstractAnnotationCheck

{

public boolean isSatisfied(Object validatedObject, Object valueToValidate, OValContext context, Validator validator)

{

if (valueToValidate == null) return true;

String val = valueToValidate.toString();

return val.equals(val.toUpperCase());

}

}

Create an annotation for your constraint and annotated it with @net.sf.oval.configuration.annotation.Constraint.

Specify your check class as value for parameter "check".

@Retention(RetentionPolicy.RUNTIME)

@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})

@net.sf.oval.configuration.annotation.Constraint(checkWith = UpperCaseCheck.class)

public @interface UpperCase

{

/**

* message to be used for the ConstraintsViolatedException

*

* @see ConstraintsViolatedException

*/

String message() default "must be upper case";

}

Use the custom constraint annotation in your code.

public class BusinessObject

{

@UpperCase

private String userId;

...

}

Localization of the constraint violation message can be achieved as follows:

Specify a unique message key for the default message string of the constraint annotation, e.g.

@Retention(RetentionPolicy.RUNTIME)

@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})

@net.sf.oval.configuration.annotation.Constraint(checkWith = UpperCaseCheck.class)

public @interface UpperCase

{

/**

* message to be used for the ConstraintsViolatedException

*

* @see ConstraintsViolatedException

*/

String message() default "UpperCase.violated";

}

Create custom message bundles (one per language) and specify the translated sting in each bundle:

UpperCase.violated={context} must be upper case

There exist two default variables that can be used in the message string:

{context} = the validation context (e.g. a field, a method return value or a

constructor/method parameter

{invalidValue} = the value that has been checked

If required, you can introduce additional variables - e.g. which reflect additional configuration

properties of your constraint such as {max}, {min}, {size} - by overriding the

createMessageVariables method of your custom check class:

@Override

public Map createMessageVariables()

{

Map messageVariables = new HashMap(2)

messageVariables.put("max", Integer.toString(max));

messageVariables.put("min", Integer.toString(min));

return messageVariables;

}

The message variables can then be used in the corresponding message strings.

For performance reasons the createMessageVariables method is only executed once and the returned map is cached by OVal for this constraint check instance.

If you change one of the variables you need to invalidate the cache and require rebuilding of the variables map by calling requireMessageVariablesRecreation.

For the built-in constraints requireMessageVariablesRecreation is invoked in each setter on the constraint check implementations, e.g.:

public void setMax(final int max)

{

this.max = max;

requireMessageVariablesRecreation();

}

Register your message bundle with OVal:

ResourceBundleMessageResolver resolver = (ResourceBundleMessageResolver) Validator.getMessageResolver();

resolver.addMessageBundle(ResourceBundle.getBundle("mypackage/CustomMessages"));

If you would like to store your message strings other than in message bundles (e.g. in a database):

Either implement the MessageResolver interface or extend the ResourceBundleMessageResolver

and then configure OVal using the static Validator.setMessageResolver(...) method to use an instance of

your custom message resolver instead.

If you have to express a rather complex constraint that is used only within one class you might not want to

implement it as a custom constraint. You have the following two alternatives expressing such class specific constraints

in a convenient way.

You can write a method within the class that has a single parameter to receive the value to validate and that

returns true if the constraint is satisfied and false if it is violated.

Example:

private static class TestEntity

{

@Min(1960)

private int year = 1977;

@Range(min=1, max=12)

private int month = 2;

@ValidateWithMethod(methodName = "isValidDay", parameterType = int.class)

private int day = 31;

private boolean isValidDay(int day)

{

GregorianCalendar cal = new GregorianCalendar();

cal.setLenient(false);

cal.set(GregorianCalendar.YEAR, year);

cal.set(GregorianCalendar.MONTH, month - 1);

cal.set(GregorianCalendar.DATE, day);

try {

cal.getTimeInMillis();

} catch (IllegalArgumentException e) {

return false;

}

return true;

}

}

You can write an inner static class extending

net.sf.oval.constraint.CheckWithCheck.SimpleCheck which then is referenced via

a @net.sf.oval.constraint.CheckWith constraint annotation.

Example:

private static class DayEntity

{

@Min(1960)

private int year;

@Range(min=1, max=12)

private int month;

@CheckWith(DayCheck.class)

private int day;

private static class DayCheck implements CheckWithCheck.SimpleCheck

{

public boolean isSatisfied(Object validatedObject, Object value)

{

try {

GregorianCalendar cal = new GregorianCalendar();

cal.setLenient(false);

cal.set(GregorianCalendar.YEAR, ((DayEntity) validatedObject).year);

cal.set(GregorianCalendar.MONTH, ((DayEntity) validatedObject).month - 1);

cal.set(GregorianCalendar.DATE, ((DayEntity) validatedObject).day);

cal.getTimeInMillis();

} catch (IllegalArgumentException e) {}

return false;

}

}

}

By default the constraints configuration is done by adding annotations representing the constraints to the

respective locations in the source code. Alternatively constraints can also be declared via XML - either for a

complete configuration or to overwrite the annotations based constraint configurations for specific classes, fields, etc.

You can used the net.sf.oval.configuration.xml.XMLConfigurer for loading constraint definitions from an XML file:

XMLConfigurer xmlConfigurer = new XMLConfigurer(new File("oval-config.xml"));

Guard guard = new Guard(xmlConfigurer);

Here is an example XML configuration:

xmlns="http://oval.sf.net/oval-configuration"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://oval.sf.net/oval-configuration http://oval.sourceforge.net/oval-configuration.xsd">

You may come across the requirement to turn on or off the checking of certain constraints across your

domain model, e.g. based on some global configuration settings of the application. OVal helps you to implement

this by introducing constraint profiles. For each declared constraint you can specify an infinite number of

profiles this constraint belongs to. During runtime you then can enable or disable all constraints associated

with a given profile by using the disableProfile , and enableProfile

methods of the Validator instance. Constraints not having any profiles declared are

automatically assigned a profile named default.

public class Person

{

@NotNull(profiles = {"profile1"})

public String firstName;

@NotNull(profiles = {"profile1"})

public String lastName;

@NotNull(profiles = {"profile2", "profile3"})

public String zipCode;

}

Example usage:

Validator v = new Validator();

v.disableProfile("profile1");

Person p = new Person();

v.validate(p);

In this case only the null value zipCode property will result in a

ConstraintViolation. The @NotNull constraints of firstName

and lastName are ignored since they are associated with profile1

and profile1 has been disabled.

OVal instantiates all internally used collections indirectly via a CollectionFactory.

OVal comes with three different implementations of the collection factory (Javolution Collections,

GNU Trove Collections, and JDK Collections). If the Javolution or GNU Trove collection classes are detected

in the classpath, OVal automatically uses the respective CollectionFactory otherwise the collection factory

for standard JDK collections is used.

The Collection Factory to be used by OVal can be configured via the static

Validator.setCollectionFactory(factory) method.

You can implement the net.sf.oval.collection.CollectionFactory interface to

support other collection implementations.

If you want to express constraints in a scripting language not supported by OVal out of the box, you need

to implement the net.sf.oval.expression.ExpressionLanguage interface for the desired language

and register your implementation with OVal using the Validator.addExpressionLanguage(languageId, expressionLanguage)

method. Then you can use the specified languageId with expression language aware constraint annotations such as

@Assert, @Pre, or @Post and start expressing constraints

in the new expression language.

The class net.sf.oval.integration.spring.SpringValidator provides an implementation of Spring's

org.springframework.validation.Validator interface and thus can be used for

Spring Validation.

It is possible to use OVal's programming by contract feature with AOP solutions other than AspectJ.

Spring for example uses the AOP Alliance API in conjunction with JDK or CGLib proxies to provide certain

features of AOP to Spring managed beans.

With the class net.sf.oval.guard.GuardInterceptor we provide an AOP Alliance

implementation of the Guard aspect that enables you to use OVal's guarding feature in conjunction with

Spring managed beans without the need for AspectJ.

Here is an example how to configure the guarding of the methods of a Spring managed service.

This configuration requires CGLIB to be on the classpath.

ovalGuardInterceptor

To have Spring beans injected automatically into Check classes you need to:

annotated the required fields in your Check implementation class with @Autowired

add an instance of net.sf.oval.integration.spring.BeanInjectingCheckInitializationListener to the configurer

AnnotationConfigurer myConfigurer = new AnnotationConfigurer();

myConfigurer.addCheckInitializationListener(BeanInjectingCheckInitializationListener.INSTANCE);

Validator myValidator = new Validator(myConfigurer);

enable annotation-based configuration in your Spring application context configuration:

setup an SpringInjector bean in your Spring application context configuration:

You can instantiate OVal validators with Spring like any other Spring managed bean.

Here is an example setting up a validator with XML based constraint configuration:

Musachy Barroso has developed an OVal Plug-in for Apache Struts 2, which is documented at

http://cwiki.apache.org/confluence/display/S2PLUGINS/OVal+Plugin

You can browse OVal's Javadoc here .

YourKit is kindly supporting open source projects with its full-featured Java Profiler.

YourKit, LLC is creator of innovative and intelligent tools for profiling Java and .NET applications.

Take a look at YourKit's leading software products: YourKit Java Profiler

and YourKit .NET Profiler.

Java™ and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other

countries, or both. For more information please refer to: http://www.oracle.com/html/3party.html

This site is independent of Oracle Corporation.

All other trademarks are the sole property of their respective owners.

177cc31bd688edb37ab71ae4643bb1f8.png

© 著作权归原作者所有

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值