Notes
Introduction
This article explains the specification of Java Bean Validation's @Pattern.
I keep seeing many explanations that use incorrect examples, and reviewing code that references them is exhausting,
so I decided to stop expecting the world to provide correct information and to publish it myself.
The recent article is also part of that effort.
TL;DR
- You do not need to add
^at the beginning and$at the end of the regular expression specified in@Pattern'sregexp - Read the docs and confirm the specification
- Do not blindly trust personal blogs, Qiita, or Zenn (self-contradiction)
Incorrect implementation
If you search Google for how to apply regex validation with the @Pattern annotation in Spring Boot requests, you often see examples like this.
1@Value2@Builder3public class Example {45@Pattern(regexp = "^[A-Z][a-z]+$")6String name = "Name";7}
You can find examples that use both ^ and $, or only one of them, but they write regex for @Pattern's regexp in the form ^<regex>$.
This works and is not incorrect, but you do not need to use ^ and $.
People who deliberately add ^ and $ may not understand the @Pattern specification.
Jakarta Bean Validation
If you want to implement validation in Java, it is common to use a library compliant with Jakarta Bean Validation. Jakarta Bean Validation is the specification for Bean Validation, transferred from JSR 303, JSR 349, and JSR 380, and managed by the Eclipse Foundation. 1
In Java, there are cases where only the specification is defined independently, and multiple libraries implement it. For example, Hibernate Validator is the reference implementation for Jakarta Bean Validation. Hibernate Validator is commonly used, but there is also Apache BVal as a Jakarta Bean Validation-compliant implementation.
Hibernate Validator
PatternValidator
Validation for the @Pattern annotation is performed by PatternValidator.
1/*2* Hibernate Validator, declare and validate application constraints3*4* License: Apache License, Version 2.05* See the license.txt file in the root directory or <http://www.apache.org/licenses/LICENSE-2.0>.6*/7package org.hibernate.validator.internal.constraintvalidators.bv;89import java.lang.invoke.MethodHandles;10import java.util.regex.Matcher;11import java.util.regex.PatternSyntaxException;12import jakarta.validation.ConstraintValidator;13import jakarta.validation.ConstraintValidatorContext;14import jakarta.validation.constraints.Pattern;1516import org.hibernate.validator.constraintvalidation.HibernateConstraintValidatorContext;17import org.hibernate.validator.internal.engine.messageinterpolation.util.InterpolationHelper;18import org.hibernate.validator.internal.util.logging.Log;19import org.hibernate.validator.internal.util.logging.LoggerFactory;2021/**22* @author Hardy Ferentschik23*/24public class PatternValidator implements ConstraintValidator<Pattern, CharSequence> {2526\tprivate static final Log LOG = LoggerFactory.make(MethodHandles.lookup());2728\tprivate java.util.regex.Pattern pattern;29\tprivate String escapedRegexp;3031\t@Override32\tpublic void initialize(Pattern parameters) {33\t\tPattern.Flag[] flags = parameters.flags();34\t\tint intFlag = 0;35\t\tfor (Pattern.Flag flag : flags) {36\t\t\tintFlag = intFlag | flag.getValue();37\t\t}3839\t\ttry {40\t\t\tpattern = java.util.regex.Pattern.compile(parameters.regexp(), intFlag);41\t\t}42\t\tcatch (PatternSyntaxException e) {43\t\t\tthrow LOG.getInvalidRegularExpressionException(e);44\t\t}4546\t\tescapedRegexp = InterpolationHelper.escapeMessageParameter(parameters.regexp());47\t}4849\t@Override50\tpublic boolean isValid(CharSequence value, ConstraintValidatorContext constraintValidatorContext) {51\t\tif (value == null) {52\t\t\treturn true;53\t\t}5455\t\tif (constraintValidatorContext instanceof HibernateConstraintValidatorContext) {56\t\t\tconstraintValidatorContext.unwrap(HibernateConstraintValidatorContext.class).addMessageParameter("regexp", escapedRegexp);57\t\t}5859\t\tMatcher m = pattern.matcher(value);60\t\t61\t\treturn m.matches();62\t}63}
Whether validation succeeds is determined by the Matcher#matches method.
Matcher#matches checks whether the entire string matches the regular expression.
If only part of the string matches, validation fails.
Therefore, for the @Pattern annotation, validation succeeds if the entire string matches the regex even without ^ and $.
Correct (?) implementation
Even though adding ^ and $ does not change behavior, it is just noise, so it should be avoided.
Thus the earlier example can be rewritten like this.
1@Value2@Builder3public class Example {45@Pattern(regexp = "[A-Z][a-z]+")6String name = "Name";7}
Conclusion
When specifying a regular expression for @Pattern's regexp, you do not need to add ^ and $.
Older articles do not use ^$, but many recent articles seem to add them.
At some point incorrect information was written, and many people likely use code they find online as-is. Do not blindly trust information found online; it is important to read official documentation and confirm the specification.
Footnotes
-
For Java EE and Jakarta EE, see From Java EE to Jakarta EE. ↩

