[Bean Validation] Constraints plural
by Emmanuel Bernard
I have added the following plural forms
AssertFalses
AssertTrues
//Digits to be redefined
Futures
Maxs
Mins
NotNulls
Nulls
Pasts
Patterns
Sizes
As you can see not all names are pretty. Any improvement proposal?
Alternatively, we could define inner annotations to define the plural,
ie
@interface Max {
String message() default "...";
Class<?> groups() default {};
public static @interface Plural {
Max[] value();
}
}
@Max.Plural( {
@Max(30, groups=JoeSixPack.class),
@Max(100, groups=PowerUser.class)
} )
WDYT?
15 years, 9 months
[BVAL-RI] Regarding @Size
by Alaa Mohsen
Hello Guys,
I was thinking about something. Why do we have the default value for
min() in the Size constraint set to Integer.MIN_VALUE and not zero? I know
that this won't make any difference at all for the validation framework, but
I don't think that it's logical to say that there is a negative size for a
String, Collection, Array or Map. Another thing is that my company is
working on tag files for client side validations by reading the annotations,
and having a minimum size of -2147483648 in the markup doesn't make any
sense. As I have mentioned before, this won't make any difference in the
bean validation framework, but I guess that it makes more sense.
Thanks & Best Regards,
Alaa Nassef
15 years, 9 months
[BVAL-RI] Unit Test Failure
by Alaa Mohsen
Hello Guys,
A unit test added in revision 16012 is failing during our builds. The
test I'm talking about is org.hibernate.validation.engine.groups.GroupTest
.testGroupSequenceFollowedByGroup(). When I debugged, the iterator defined
in line 281 always has the constraint violation for phoneNumber before that
of defaultCreditCard. When I exchanged the locations of the asserts, the
test succeeded, but of course I don't think that this is a good solution,
since I'm sure that the tests run successfully on other machines.
Regards
Alaa Nassef
15 years, 9 months
Group sequence adjustments
by Emmanuel Bernard
Hi everyone,
Several questions have been raised around groups recently. I have
adjusted the spec to answer them. Can you review the wording (esp the
addition to the formal rules)? I put changes in red.
The idea is:
- an interface representing a group sequence cannot have inherited
groups
- a constraint declaration cannot use a group reprensenting a group
sequence
- when a group A is sequenced before B, all groups composing A (via
inheritance or group sequence) are sequenced before B
- if a circularity arise, an exception happens
3.4. Group and group sequence
A group defines a subset of constraints. Instead of validating all
constraints for a given object graph, only a subset is validated
depending on the group targeted. Each constraint declaration defines
the list of groups it belongs to. If no group is explicitly declared,
a constraint belongs to the Default group.
Groups are represented by interfaces.
Example 3.1. Definition of groups
/**
* Validation group checking a user is billable
*/
public interface Billable {}
/**
* customer can buy without harrassing checking process
*/
public interface BuyInOneClick {
}
A constraint can belong to one or more groups.
Example 3.2. Assign groups to constraints
/**
* User representation
*/
public class User {
@NotNull
private String firstname;
@NotNull(groups = Default.class)
private String lastname;
@NotNull(groups = {Billable.class, BuyInOneClick.class})
private CreditCard defaultCreditCard;
}
During the validation call, one or more groups are validated. All the
constraints belonging to this set of group is evaluated on the object
graph. In Example 3.2, “Assign groups to constraints”,@NotNull is
checked on defaultCreditCard when either the Billable or BuyInOneClick
group is validated. @NotNull on firstname and on lastname are
validated when the Default group is validated. Reminder: constraints
held on superclasses and interfaces are considered.
Default is a group predefined by the specification
package javax.validation.groups;
/**
* Default Bean Validation group
*
* @author Emmanuel Bernard
*/
public interface Default {
}
3.4.1. Group inheritance
In some situations, a group is a super set of one or more groups. This
can be described by Bean Validation. A group can inherit one or more
groups by using interface inheritance.
Example 3.3. Groups can inherit other groups
/**
* Customer can buy without harrassing checking process
*/
public interface BuyInOneClick extends Default, Billable {
}
For a given interface Z, constraints marked as belonging to the group
Z (ie where the annotation groups property contains the interface Z)
or any of the super interfaces of Z (inherited groups) are considered
part of the group Z.
In the following example:
Example 3.4. Use of a inherited group
/**
* User representation
*/
public class User {
@NotNull
private String firstname;
@NotNull(groups = Default.class)
private String lastname;
@NotNull(groups = {Billable.class})
private CreditCard defaultCreditCard;
}
validating the group BuyInOneClick will lead to the following
constraints checking:
@NotNull on firstname and lastname
@NotNull on defaultCreditCard
because Default and Billable are subinterfaces of BuyInOneClick.
3.4.2. Group sequence
By default, constraints are evaluated in no particular order and this
regardless of which groups they belong to. It is however useful in
some situations to to control the order of constraints evaluation.
There are often scenarios where a preliminary set of constraints
should be evaluated prior to other constraints. Here are two examples:
The second group depends on a stable state to run properly. This
stable state is verified by the first previous group.
The second group is a heavy consumer of time, CPU or memory and its
evaluation should be avoided if possible.
To implement such ordering, a group can be defined as a sequence of
other groups. Each group in a group sequence must be processed
sequentially in the order defined by(a)GroupSequence.value when the
group defined as a sequence is requested. Note that a group member of
a sequence can itself be composed of several groups via inheritance or
sequence definition. In this case, each composed group must respect
the sequence order as well.
Processing a group is defined in Section 3.5, “Validation routine” ;
if one of the groups processed in the sequence generates one or more
constraint violation, the groups following in the sequence must not be
processed. This ensure that a set of constraint is evaluated only if
another set of constraint is valid.
Groups defining a sequence and groups composing a sequence must not be
involved in a cyclic dependency either directly or indirectly, either
through cascaded sequence definition or group inheritance.
Groups defining a sequence should not directly inherit other groups.
In other words, the interface hosting the group sequence should not
have any super interface.
Groups defining a sequence should not be used directly in constraint
declarations. In other words, the interface hosting the group sequence
should not be used in a constraint declaration.
To define a group as a sequence, the interface must be annotated with
the @GroupSequence annotation.
@Target({TYPE})
@Retention(RUNTIME)
public @interface GroupSequence {
Class<?>[] value();
}
Here is a usage example
Example 3.5. Make use of group sequence
@ZipCodeCoherenceChecker(groups = Address.HighLevelCoherence.class)
public class Address {
@NotNull @Size(max = 50)
private String street1;
@ZipCode
private String zipcode;
@NotNull @Size(max = 30)
private String city;
/**
* check conherence on the overall object
* Needs basic checking to be green first
*/
public interface HighLevelCoherence {}
/**
* check both basic constraints and high level ones.
* high level constraints are not cheked if basic constraints fail
*/
@GroupSequence({Default.class, HighLevelCoherence.class})
public interface Complete {}
}
In Example 3.5, “Make use of group sequence”, when the
Address.Complete group is validated, all constraints belonging to the
Default group are validated. If any of them fail, the validation skips
the HighLevelCoherence group. If all Default constraints pass,
HighLevelCoherence constraints are evaluated.
Note
A given constraint can belong to two groups ordered by a sequence. In
this case, the constraint is evaluated as part of the first group and
ignored in the subsequent group(s). SeeSection 3.5, “Validation
routine” for more informations.
3.4.3. Redefining the Default group for a class
In Example 3.5, “Make use of group sequence”, validating the Default
group does not validate HighLevelCoherence constraints. To ensure a
complete validation, a user must use the Completegroup. This breaks
some of the encapsulation you could expect. You can work around this
by redefining what the Default group means for a given class. To
redefine Default for a class, place a@GroupSequence annotation on the
class ; this sequence expresses the sequence of groups that does
substitute Default for this class.
Example 3.6. Redefining Default group for Address
@GroupSequence({Address.class, HighLevelCoherence.class})
@ZipCodeCoherenceChecker(groups = Address.HighLevelCoherence.class)
public class Address {
@NotNull @Size(max = 50)
private String street1;
@ZipCode
private String zipcode;
@NotNull @Size(max = 30)
private String city;
/**
* check conherence on the overall object
* Needs basic checking to be green first
*/
public interface HighLevelCoherence {}
}
In Example 3.6, “Redefining Default group for Address”, when an
address object is validated for the group Default, all constraints
belonging to the group Default and hosted on Address are evaluated. If
none fails, all HighLevelCoherence constraints present on Address are
evaluated. In other words, when validating the Default group for
Address, the group sequence defined on the Address class is used.
Since sequences cannot have circular dependencies, using Default in
the declaration of a sequence is not an option. Constraints hosted on
a class A and belonging to the Default group (by default or
explicitly) implicitly belong to the group A.
A sequence defined on a class A (ie. redefining the Default groups for
the class) must contain the group A. In other words, the default
constraints hosted on a class must be part of the sequence definition.
3.4.4. Implicit grouping
It is possible to implicitly group some constraints in the same group
without explicitly listing such a group in the constraint declaration.
Every constraint hosted on an interface Z and part of theDefault group
(implicitly or explicitly) belongs to the group Z. This is useful to
validate the partial state of an object based on a role represented by
an interface.
Example 3.7. Example of interface / group hosting constraints
/**
* Auditable object contract
*/
public interface Auditable {
@NotNull String getCreationDate();
@NotNull String getLastUpdate();
@NotNull String getLastModifier();
@NotNull String getLastReader();
}
/**
* Represents an order in the system
*/
public class Order implements Auditable {
private String creationDate;
private String lastUpdate;
private String lastModifier;
private String lastReader;
private String orderNumber;
public String getCreationDate() {
return this.creationDate;
}
public String getLastUpdate() {
return this.lastUpdate;
}
public String getLastModifier() {
return this.lastModifier;
}
public String getLastReader() {
return this.lastReader;
}
@NotNull @Size(min=10, max=10)
public String getOrderNumber() {
return this.orderNumber;
}
}
When an Order object is validated on the Default group, the following
constraints are validated: @NotNull on getCreationDate, getLastUpdate,
getLastModifier, getLastReader,getOrderNumber and @Size on
getOrderNumber as all belong to the Default group.
When an Order object is validated on the Auditable group, the
following constraints are validated: @NotNull on getCreationDate,
getLastUpdate, getLastModifier, getLastReader. Only the constraints
present on Auditable (and any of its super interfaces) and belonging
to the Default group are validated when the group Auditable is
requested. It allows the caller to validate that a given object can be
safely audited even if the object state itself is not valid.
3.4.5. Formal group definitions
The formal rules defining groups are as followed. Text in italic are
comments about the rules.
For every class X:
A. For each superclass Y of X, the group Y contains all constraints of
the group Y of Y
this rule prepares formal concepts for recursive discovery
B. The group X contains the following constraints:
group X is a group used on sequences redefining the default group on a
class (see Section 3.4.3, “Redefining the Default group for a class”)
every constraint declared by the class X which does not declare a
group or does declare the group Default explicitly.
all Default constraints hosted on X
every constraint declared by any interface implemented by X and not
annotated @GroupSequence which does not explicitly declare a group or
does declare the group Default explicitly.
all Default constraints hosted on interfaces of X: constraints are
inherited by the class hierarchy. Interfaces marked as @GroupSequence
are ignored.
if X has a direct superclass Y, every constraint in the group Y
all Default constraints hosted on the superclasses of X: constraints
are inherited by the class hierarchy
C. If X has no @GroupSequence annotation, the group Default contains
the following constraints:
this rule defines which constraints are evaluated when validating
Default on X.
every constraint in the group X
if X has a direct superclass Y, every constraint in the group Default
of Y
this rule is necessary in case Y redefines the group Default
D. If X does have a @GroupSequence annotation, the group Default
contains every constraint belonging to every group declared by the
@GroupSequence annotation.
this rule describes how a class can redefine the group Default for
itself (see Section 3.4.3, “Redefining the Default group for a class”)
the @GroupSequence annotation must declare the group X
E. For every interface Z, the group Z contains the following
constraints:
this rule defines how non Default groups are defined
every constraint declared by the interface Z which does not explicitly
declare a group or does declare the group Default explicitly.
all Default constraints hosted on Z: this rule formally defines
implicit grouping per interface (see Section 3.4.4, “Implicit grouping”)
every constraint declared by any superinterface not annotated
@GroupSequence of the interface Z which does not explicitly declare a
group
all Default constraints hosted on interfaces of Z: groups can be
inherited (see Section 3.4.1, “Group inheritance”)
every constraint declared by the class X which explicitly declares the
group Z
every constraint hosted by X and marked as belonging to the group Z
every constraint declared by any interface implemented by X and not
annotated @GroupSequence which explicitly declares the group Z
every constraint hosted by any interface of X and marked as belonging
to the group Z
if X has a direct superclass Y, every constraint in the group Z of Y
every constraint hosted by any superclass of X and marked as belonging
to the group Z
F. For every interface Z annotated @GroupSequence, the group Z
contains every constraint belonging to every group declared by the
@GroupSequence annotation.
defines the composition side of group sequence but does not define the
ordering behavior of sequence (see Section 3.4.2, “Group sequence”)
When a given group G (represented by an interface G) is requested for
the validation of a class X:
constraints belonging to the group G are evaluated
if the interface G is not annotated @GroupSequence, every group
represented by the super interface of G are requested for validation
if the interface G is annotated with @GroupSequence, every group
represented by the interfaces declared by the @GroupSequence
annotation are requested for validation
the validation of groups declared to the @GroupSequence must happen in
the sequencing order declared by @GroupSequence: the sequencing order
is propagated to the groups composing the sequenced group (via
inheritance or group sequence)
if a group validation triggers the failure of one or more constraints,
groups following in the sequence must not be evaluated.
if the group G represents the Default group of X overridden by
@GroupSequence, operations are equivalent
When the Default group of a given class X is overridden via
@GroupSequence, its validation is as followed:
every group represented by the interfaces declared by the
@GroupSequence annotation are requested for validation
the validation of groups declared to the @GroupSequence must happen in
the sequencing order declared by @GroupSequence: the sequencing order
is propagated to the groups composing the sequenced group (via
inheritance or group sequence)
if a group validation triggers the failure of one or more constraints,
groups following in the sequence must not be evaluated.
Unless defined by a @GroupSequence, evaluation ordering is not
constrained. In particular, several groups can be validated in the
same pass. If a group definition leads to a circular sequencing order
between groups, an exception is raised.
Note
A group G sequenced (directly or indirectly) to be executed before
itself is not considered a circular reference.
15 years, 9 months
hibernate-tools jira HBX-577
by Ing. Arturo Frappé Muñoz
Hi,
This is my proposal to solve JIRA issue HBX-577
"hbm2java for annotation from existing inheritance mapping"
I figured out how-to do "joined-subclass" and
"table-per-class-herarchy" but couldn't test it.
This solution relies on <meta> tag, example:
<class name="Nota" mutable="false"
table="NOTA"
schema="dbo" catalog="DATA"
discriminator-value="not null">
<meta
attribute="class-inheritance-type">single-table-per-class-herarchy</meta>
15 years, 9 months
Exception model
by Emmanuel Bernard
I spent a long time scrutinizing the spec for exception cases. This
email list exceptional cases and propose to associate specific
exceptions to them or not. Please review and tell me:
- if you think I forgot cases that needs additional consideration.
- which model you favor (see B)
A. EXCEPTION CASES
I described the error cases and a fine grained Exception model (see B)
and have a few questions see ???
1. Error report
Use for other frameworks to report violation reports
**
* Report the result of constraint violations
*
* @author Emmanuel Bernard
*/
public class ConstraintViolationException extends ValidationException {
private final Set<ConstraintViolation> constraintViolations;
/**
* Creates a constraint violation report
*
* @param message error message
* @param constraintViolations Set of ConstraintViolation
*/
public ConstraintViolationException(String message,
Set<ConstraintViolation> constraintViolations) {
super( message );
this.constraintViolations = constraintViolations;
}
/**
* Creates a constraint violation report
*
* @param constraintViolations Set of ConstraintViolation
*/
public ConstraintViolationException(Set<ConstraintViolation>
constraintViolations) {
super();
this.constraintViolations = constraintViolations;
}
/**
* Set of constraint violations reported during a validation
*
* @return Set of CosntraintViolation
*/
public Set<ConstraintViolation> getConstraintViolations() {
return constraintViolations;
}
}
2. Execution exceptions
ie during validator.validate(...);
Constraint Declaration
These can be found a compilation time with an annotation processor or
an IDE
??? UnsupportedTypeException or should it be
AmbiguousConstraintUsageException
More than one ConstraintValidator targeting the same type
declared property type property has too many matches
UnsupportedTypeException
declared property type property has no match
ConstraintDefinitionException
composition parameter overriding (name, composing constraint
or incompatible parameter types)
constraint composed of itself
Constraint implementation
ConstraintInitializationException
??? initialize() must raise a RTE will be wrapped OR should we
not wrap
UnsupportedTypeException
isValid incompatible type (detected by impl) => same as
"declared property type property has no match"
ConstraintExcecutionException
isValid throws a RTE will be wrapped into
ConstraintValidatorExecutionException
ConstraintCreationException
ConstraintValidatorFactory fails with RTE. Wraps it.
??? should we collapse that into a ConstraintExecutionException or
even ValidationException
Groups
Can be checked at built time by an IDE or an AnnotationProcessor
GroupDefinitionException
cyclic dependency between groups sequences and group
inheritance
missing group X on a Default group overriding
Group sequence name used in a constraint declaration
group is not an interface
Various
IllegalArgumentException
if object to validate is null, or empty set?
??? Calls to SPi like MessageInterpolator / TraversableResolver
should be wrapped?
3. Bootstrap
ProviderNotFoundException
cannot find matching provider
cannot find any provider
ConfigurationException
cannot read XML cong
more than one XML conf
no no-arg constructor on classes described by XML
MappingException
cannot read XML mapping
entity described more than once
field/getter described more than once
Wrong class / field / getter name
Wrong constraint declaration
Wrong constraint definition
B. EXCEPTION MODEL
We have three approaches:
1. specialize an exception when the application can do something about
it
In this case all exceptions are ValidationException except
ConstraintViolationException
2. specialize exceptions to provide informations to the user
ValidationException (root)
ConstraintViolationException
AmbiguousConstraintUsageException
UnsupportedTypeException
ConstraintDefinitionException
ConstraintInitializationException
ConstraintExcecutionException
ConstraintCreationException
GroupDefinitionException
ProviderNotFoundException
ConfigurationException
MappingException
3. a man in the middle approach with some exception collapsing
ValidationException (root)
ConstraintViolationException
ConstraintDeclarationException (instead of UnsupportedTypeException
and AmbiguousConstraintUsageException)
ConstraintDefinitionException
ConstraintExcecutionException
GroupDefinitionException
ConfigurationException
15 years, 9 months
Fwd: [hibernate-dev] Hibernate Search: configure the LockingFactory
by Emmanuel Bernard
Begin forwarded message:
> From: Sanne Grinovero <sanne.grinovero(a)gmail.com>
> Date: February 18, 2009 15:41:06 CEST
> To: Emmanuel Bernard <emmanuel(a)hibernate.org>
> Subject: Re: [hibernate-dev] Hibernate Search: configure the
> LockingFactory
>
> 2009/2/18 Emmanuel Bernard <emmanuel(a)hibernate.org>:
>>
>> On Feb 18, 2009, at 11:49, Sanne Grinovero wrote:
>>
>>> The "none" doesn't protect at all, so you have to make sure to
>>> never open
>>> a second indexwriter or use any indexwriter when you are using an
>>> indexreader
>>> to make changes.
>>> Sounds a bit dangerous IMHO but I don't think we should stop people
>>> shooting
>>> at their own feet.
>>> As we are enforcing a single indexwriter and all our indexreaders
>>> are
>>> readonly since
>>> last release, you may want to use it: I think the current design of
>>> H.Search
>>> doesn't stop us from offering this option.
>>> I've added a note in the docs to use it only if you really
>>> understand it.
>>
>> Well, if you are only using Hibernate Search to access indexes (90%
>> of our
>> user base) and you deploy on one server (80% of our user base),
>> none is a
>> compelling solution right? (that's 70% of deployments :))
>>
>>
> yes I think it could be used; but I don't think the speed
> improvement is anything you could measure, and it is dangerous.
> Bad things will happen to your index if you don't know about it and
> are in the
> unlucky 30% of deployments.
> Also I'm not sure what crazy things could be using the "Native
> Lucene" APIs
> exposed...
> But now at least we don't stop anybody from trying it.
15 years, 9 months
Hibernate Search: configure the LockingFactory
by Sanne Grinovero
Hi all,
to solve HSEARCH-284 (Lucene locks left around in application restart/crash)
I am investigating the differences in all Lucene's LockFactory implementations;
some of them are interesting and I would like to add a configuration option to
replace the default one in Hibernate Search.
1) property name:
I'm naming the property key "locking_strategy", scoped for each
DirectoryProvider.
2) values:
At first I was planning to use the usual design to be able to specify
any implementation
by specifying the qualified class name, but actually only 4
implementations make sense
and if someone really needed the flexibility to implement their own
they can define
their own DirectoryProvider and use whatever they want.
Also 2 of the base Lucene implementations are missing a public no-args
constructor,
so I would use only simple names:
simple -> org.apache.lucene.store.SimpleFSLockFactory
native -> org.apache.lucene.store.NativeFSLockFactory
single -> org.apache.lucene.store.SingleInstanceLockFactory
none -> org.apache.lucene.store.NoLockFactory
3) support for "none":
I don't think we should let the user select something which is not compatible
with H.Searche's design, so I am still trying to figure out if the NoLockFactory
could be an option in case Search is the only process accessing the index.
Currently inside search the IndexReaders/Searchers are read-only, and at most
one IndexWriter is using the DP, so the locking strategy could be set
to "none" IMHO.
opinions?
4) default:
The current default is "simple", which has the problem as reported in
HSEARCH-284,
so I was puzzled by the idea to define the "native" as the default one to have
Search beginners avoid the locking problem, but I am hitting some
problems under load testing,
so I think the default should stay to "simple" at least for now.
Sanne
15 years, 9 months
hibernate-tools JUnit template
by Ing. Arturo Frappé Muñoz
Good evening Lords & Ladies:
This is a simple .ftl template
to generate a trivial JUnit test code.
Any ideas &
improvements are welcome ;)
15 years, 9 months