Code changes the world. This article has been https://www.yourbatman.cn included, along with all the inside have Spring technology stack, MyBatis, middleware, such as the JVM, small and beautiful column study for free. Pay attention to the public number [BAT utopia] one by one to break, in-depth grasp,
The foreword ✍
Hi, I’m YourBatman. Another year 1024 Programmers Day, are you happy? Are you working overtime?
The last article introduced you to the five core components of the Validator. By combining this with the previous articles, you should have an overview of Bean Validation.
This article will be useful because it will cover Bean Validation at four levels, covering all aspects of your usage.
Version of the agreement
- Bean Validation version:
2.0.2
- Hibernate Validator
6.1.5. The Final
✍ body
The Jakarta Bean’s validation constraints are expressed declaratively (annotations) and we know that Java annotations can be annotated almost anywhere (can you believe that annotations can be annotated on a package?). What do Jakarta Beans support?
Jakarta Beans support four levels of constraints:
- Field constraints
- Property constraints
- Container Element constraints
- Class constraints (Class)
It is important to note that not all constraint annotations can be annotated at the above four levels. The reality is that all of the 22 standard constraints that come with Bean Validation support level 1/2/3, and none of them support level 4 (class level) constraints. Of course, as a supplement of Hibernate Validator – it provides some notes specially used for class level constraints, such as org.. Hibernate Validator. Constraints. @ ScriptAssert is a common case.
Note: To simplify the following sample code, the common tool code is shown as follows in advance:
public abstract class ValidatorUtil {
public static ValidatorFactory obtainValidatorFactory(a) {
return Validation.buildDefaultValidatorFactory();
}
public static Validator obtainValidator(a) {
return obtainValidatorFactory().getValidator();
}
public static ExecutableValidator obtainExecutableValidator(a) {
return obtainValidator().forExecutables();
}
public static <T> void printViolations(Set<ConstraintViolation<T>> violations) {
violations.stream().map(v -> v.getPropertyPath() + v.getMessage() + ", but your value is:+ v.getInvalidValue()).forEach(System.out::println); }}Copy the code
1. Field level constraints (Field)
This is the most common form of constraint we use:
public class Room {
@NotNull
public String name;
@AssertTrue
public boolean finished;
}
Copy the code
Write test cases:
public static void main(String[] args) {
Room bean = new Room();
bean.finished = false;
ValidatorUtil.printViolations(ValidatorUtil.obtainValidator().validate(bean));
}
Copy the code
Run the program, output:
Finished only fortrue, but your value is:falseThe name cannot benull, but your value is:null
Copy the code
When a constraint is annotated on a Field Field, Bean Validation uses the Field’s access policy to validate it, and does not call any methods, even if you provide the corresponding GET /set methods.
Voice: use Field#get() to get the value of the field
Using the details
- Field constraints can be applied to any field that accesses a modifier
- Static field constraints are not supported
If your object is going to be enhanced by bytecode, instead of using the Field constraint, it is more appropriate to use the property-level constraint described below.
Reason: Enhanced classes do not necessarily get their values through field reflection
Most of the time, constraints on Field fields are POJOs that are unlikely to be enhanced, so this approach is recommended and looks refreshing.
2. Property level constraint
If a Bean follows the Java Bean specification, attribute constraints can also be used instead of field constraints. For example, the above example can be rewritten as follows:
public class Room {
public String name;
public boolean finished;
@NotNull
public String getName(a) {
return name;
}
@AssertTrue
public boolean isFinished(a) {
returnfinished; }}Copy the code
Execute the same test case above with the output:
Finished only fortrue, but your value is:falseThe name cannot benull, but your value is:null
Copy the code
The effect was “exactly” the same.
When a constraint is annotated on a Property Property, the Property access strategy is used to obtain the value to be validated. In plain English: your Method is called to get the value to be checked.
Using the details
- The constraint is placed on get rather than set so that read-only properties (without a GET method) can still perform the constraint logic
- Do not annotate both attributes and fields, or you will repeat the constraint logic (as many annotations as possible)
- Do not annotate constraint annotations on both get and set methods of attributes
Container Element constraints
Another very, very common validation scenario is validating (each) element in a container, which validates the parameterized Type. {List
= List
= List
= List
= List
= List
List<Room> beans = new ArrayList<>();
for(Room bean : beans) { validate(bean); . }Copy the code
Obviously, there are at least two drawbacks to doing this:
- Validation logic is intrusive
- Validation logic is black box (you can’t know what constraints you have without looking at the internal source code), non-declarative
We learned in the first of this column that container element Validation has been supported since Bean Validation 2.0 (version 2.02 is used in this column), so let’s try it out:
public class Room {
@NotNull
public String name;
@AssertTrue
public boolean finished;
}
Copy the code
Write test cases:
public static void main(String[] args) {
List<@NotNull Room> rooms = new ArrayList<>();
rooms.add(null);
rooms.add(new Room());
Room room = new Room();
room.name = "YourBatman";
rooms.add(room);
ValidatorUtil.printViolations(ValidatorUtil.obtainValidator().validate(rooms));
}
Copy the code
Run the program with no output, that is, no validation of the elements of the Rooms facade. There is a misconception here: The Bean Validator validates based on Java Beans, where your rooms is just a variable of container type and therefore not validated.
It treats the List as a Bean that validates the properties/methods in the List marked with constrained annotations. Obviously, there is no constraint annotation in the List, so no output
For validation to work, we just need to do this:
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Rooms {
private List<@Valid @NotNull Room> rooms;
}
public static void main(String[] args) {
List<@NotNull Room> beans = new ArrayList<>();
beans.add(null);
beans.add(new Room());
Room room = new Room();
room.name = "YourBatman";
beans.add(room);
// Must be based on Java beans for validation to take effect
Rooms rooms = new Rooms(beans);
ValidatorUtil.printViolations(ValidatorUtil.obtainValidator().validate(rooms));
}
Copy the code
Run the program, output:
rooms[0].<list element> cannot benull, but your value is:null
rooms[2]. Finished for onlytrue, but your value is:false
rooms[1]. The name can't fornull, but your value is:null
rooms[1]. Finished for onlytrue, but your value is:false
rooms[1]. Finished for onlytrue, but your value is:false
Copy the code
As you can see from the logs, the validation order of the elements is not guaranteed.
Tip: In versions prior to HV 6.0, @valid is required when validating container elements, that is, List< @valid@notnull Room> rooms. The @valid annotation is not required after HV 6.0
Using the details
- If the constraint annotation wants to be annotated on the container element, then the annotation definition
@Target
Must containTYPE_USE
(new in Java8) this type- All BV and HV annotations (except Class level) can be annotated on container elements
- BV specifies that elements in a container can be validated, and HV provides the implementation. It supports the following container types by default:
java.util.Iterable
Implementation of List, Setjava.util.Map
Support key and valuejava.util.Optional/OptionalInt/OptionalDouble...
- The deployment headaches
javafx.beans.observable.ObservableValue
- Customizing container types (customizing is important; see the next article)
4, Class level constraint (Class)
Constraint validation at the class level is an area that many students are not familiar with, but it is important.
Hibernate-Validator has some built-in capabilities, but it may not be enough, and many scenarios need to be handled elegantly yourself. To demonstrate the importance of this part, I decided to write a special article describing, and of course, validation of custom container types, which WE’ll see below.
The difference between field constraints and attribute constraints
Field VS Property itself belongs to a pair of “synonyms”. In most cases, we do not distinguish them verbally, because in POJOs, they usually exist at the same time, so they can communicate with each other in most cases. Such as:
@Data
public class Room {
@NotNull
private String name;
@AssertTrue
private boolean finished;
}
Copy the code
The difference between fields and attributes
- The field has storage function: the field is a member of the class, and the value exists in memory. Properties, which have no storage, are a term abstracted from the Java Bean specification
- Fields are typically used for classesinternal(usually private), while properties are externally accessible (usually get/set is public)
- This refers to the general rule
- The essence of a Field is Field, and the essence of an attribute is Method
- Properties andDon’t depend onFields exist, but they usually come in pairs
- Such as
getClass()
You can think of it as a property named class, but it doesn’t have a field named class
- Such as
Knowing the difference between field and attribute, it is easy to understand the difference between field constraint and attribute constraint. The difference between them is only reflected in the difference of value access strategy to be verified:
- Field constraint: directly reflect the value of the access field -> Field#get (will not execute the get method body)
- Attribute constraint: Call attribute get method -> getXXX (executes get method body)
Tip: If you want to output a log when validation is performed, or if your POJO is enhanced by bytecode, attribute constraints are better for you. Otherwise, field constraints are recommended
✍ summary
Well, this article is not bad, the general browsing down the line is simple, but the content is still quite dry ha, after all, 1024 sections, do not come to the point of the stem of the heart feel guilty.
As the first part of this sister, it is necessary for every student to master the way of use. The next one, I think, should be more exciting. After all, that’s where the bonus points are. 1024, roll up your sleeves and get on with it.
✔
- The first article will improve your understanding of Bean Validation data Validation
- Validates method parameters and return values
- 3. On the usage side, Bean Validation is the standard interface that you need to be familiar with
- Every one of the five core components of a Validator should be included