Hibernate Validator vs Regex vs Manual Validation: Which One Is Faster?
Inspired by coding for a performance backend competition, this article follows a test to find the fastest validator for Java applications.
Join the DZone community and get the full member experience.
Join For FreeWhile I was coding for a performance back-end competition, I tried a couple of tricks, and I was wondering if there was a faster validator for Java applications, so I started a sample application.
I used a very simple scenario: just validate the user's email.
Controller With Hibernate Validator
Hibernate Validator needs an object to put its rules to, so we have this:
public record User(
@NotNull
@Email
String email
){}
This is used in the HibernateValidatorController
class, which uses the jakarta.validation.Validator
(which is just an interface for the Hibernate Validator implementation):
@RestController
@Validated
public class HibernateValidatorController {
@Autowired
private Validator validator;
@GetMapping("/validate-hibernate")
public ResponseEntity<String> validateEmail(@RequestParam String email) {
Using the validate
method, we can check if this user's email is valid and get a proper HTTP response.
var user = new User(email);
var violations = validator.validate(user);
if (violations.isEmpty()) {
return ResponseEntity.ok("Valid email: 200 OK");
} else {
var violationMessages = new StringBuilder();
for (ConstraintViolation<User> violation : violations) {
violationMessages.append(violation.getMessage()).append("\n");
}
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body("Invalid email: 400 Bad Request\n" + violationMessages.toString());
}
Controller With Regular Expression
For validation with regex, we need just the email regex and a method to validate:
static final String EMAIL_REGEX = "^[A-Za-z0-9+_.-]+@(.+)$";
boolean isValid(String email) {
return email != null && email.matches(EMAIL_REGEX);
}
The regexController
class just gets an email from the request and uses the isValid
method to validate it.
@GetMapping("/validate-regex")
public ResponseEntity<String> validateEmail(@RequestParam String email) {
if (isValid(email)) {
return ResponseEntity.ok("Valid email: 200 OK");
} else {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Invalid email: 400 Bad Request");
}
}
Controller With Manual Validation
We won't use any framework or libs to validate, just plain old String
methods:
boolean isValid(String email) {
if (email == null) return false;
int atIndex = email.indexOf("@");
int dotIndex = email.lastIndexOf(".");
return atIndex > 0 && dotIndex > atIndex + 1 && dotIndex < email.length() - 1;
}
The programmaticController
class just gets an email from the request and uses the isValid
method to validate it.
@GetMapping("/validate-programmatic")
public ResponseEntity<String> validateEmail(@RequestParam String email) {
if (isValid(email)) {
return ResponseEntity.ok("Valid email: 200 OK");
} else {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Invalid email: 400 Bad Request");
}
}
Very Simple Stress Test
We are using Apache JMeter to test all 3 APIs.
Our simulation runs with 1000 concurrent users in a loop for 100 times sending a valid email each request.
Running it on my desktop machine got similar results for all APIs, but the winner is Hibernate Validator.
| API | avg | 99% | max | TPS | |--------------------------------|-----|-----|------|--------| | Regex API Thread Group | 18 | 86 | 254 | 17784 | | Programmatic API Thread Group | 13 | 67 | 169 | 19197 | | Hibernate API Thread Group | 10 | 59 | 246 | 19960 |
Conclusion
Before this test, I thought that my own code should perform way better than somebody else's code, but actually, Hibernate Validator was the best option for my test.
You can also run this test and check the source code in my GitHub.
Opinions expressed by DZone contributors are their own.
Comments