Backend Development 12 min read

SpEL Validator: A Comprehensive Parameter Validation Component for Java Backend

This article introduces a powerful Java parameter‑validation library based on Spring Expression Language, explains its features, supported annotations, usage examples, configuration steps, and how to extend it with custom constraints, providing a complete guide for backend developers.

Code Ape Tech Column
Code Ape Tech Column
Code Ape Tech Column
SpEL Validator: A Comprehensive Parameter Validation Component for Java Backend

Hello everyone, I’m Chen.

Parameter validation is often simple and can be handled with annotations like @NotNull and @Size , but some scenarios require more advanced handling, which can lead to multi‑layer validation that hurts maintainability.

To address this, I created a nearly universal parameter‑validation component that is easy to use.

GitHub address is provided at the end of the article.

💡 What problems does it solve?

Enum field validation: @SpelAssert(assertTrue = " T(cn.sticki.enums.UserStatusEnum).getByCode(#this.userStatus) != null ", message = "User status is illegal") private Integer userStatus;

Multi‑field joint validation: @NotNull private Integer contentType; @SpelNotNull(condition = "#this.contentType == 1", message = "Audio content cannot be null") private Object audioContent; @SpelNotNull(condition = "#this.contentType == 2", message = "Video content cannot be null") private Object videoContent;

Complex logic validation using static methods: // Chinese counts as two characters, English as one, total length must not exceed 10 // Call external static method for validation @SpelAssert(assertTrue = "T(cn.sticki.util.StringUtil).getLength(#this.userName) <= 10", message = "Username length cannot exceed 10") private String userName;

Calling Spring beans (requires @EnableSpelValidatorBeanRegistrar to enable): // Simple example, not recommended for production @SpelAssert(assertTrue = "@userService.getById(#this.userId) != null", message = "User does not exist") private Long userId;

More usage scenarios are welcome.

📝 Features

Powerful validation covering almost all scenarios.

Extends javax.validation without modifying it, seamless integration.

Based on Spring Expression Language (SpEL) for complex logic.

Supports calling Spring beans within expressions.

Object‑level validation enabling cross‑field checks.

Customizable validation annotations.

Validation failures are reported through the standard javax.validation exception hierarchy.

Simple usage similar to javax.validation , low learning curve.

🎈 Environment

Tested on JDK 8; theoretically works on JDK 8+.

📦 Quick Start

Add dependencies (latest version 0.0.2‑beta): <dependency> <groupId>cn.sticki</groupId> <artifactId>spel-validator</artifactId> <version>Latest Version</version> </dependency> <dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>${hibernate-validator.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>${spring-boot-starter-web.version}</version> </dependency>

Use @Valid or @Validated on controller method parameters: @RestController @RequestMapping("/example") public class ExampleController { /** Simple validation example */ @PostMapping("/simple") public Resp simple(@RequestBody @Valid SimpleExampleParamVo simpleExampleParamVo) { return Resp.ok(null); } }

Annotate entity classes with @SpelValid and fields with constraints such as @SpelNotNull : @Data @SpelValid public class SimpleExampleParamVo { @NotNull private Boolean switchAudio; /** When switchAudio is true, audioContent must not be null */ @SpelNotNull(condition = "#this.switchAudio == true", message = "Audio content cannot be null") private Object audioContent; }

Add a global exception handler for validation errors: @RestControllerAdvice public class ControllerExceptionAdvice { @ExceptionHandler({BindException.class, MethodArgumentNotValidException.class}) public Resp handleBindException(BindException ex) { String msg = ex.getFieldErrors().stream() .map(error -> error.getField() + " " + error.getDefaultMessage()) .reduce((s1, s2) -> s1 + "," + s2) .orElse(""); return new Resp<>(400, msg); } }

Send a request to see validation results.

📖 Usage Guide

Note: This component is not meant to replace javax.validation annotations but to extend them for special scenarios. Use javax.validation where possible; spel-validator incurs some performance overhead.

Enabling Constraint Validation

Both of the following conditions must be met for annotated elements to be validated:

Apply @Valid or @Validated on controller method parameters.

Apply @SpelValid on the entity class.

If only the first condition is satisfied, only standard annotations such as @NotNull , @NotEmpty , @NotBlank are validated.

If only the second condition is satisfied, no validation occurs because @SpelValid relies on the presence of @Valid or @Validated to trigger the SpEL processor.

Supported Constraint Annotations

The library provides the following annotations (each mirrors a standard javax.validation constraint):

Annotation

Description

Corresponding javax.validation

@SpelAssert

Logical assertion validation

None

@SpelNotNull

Non‑null validation

@NotNull
@SpelNotEmpty

Collection/String/Array non‑empty validation

@NotEmpty
@SpelNotBlank

String non‑blank validation

@NotBlank
@SpelNull

Must be null validation

@Null
@SpelSize

Collection/String/Array size validation

@Size

Each constraint annotation includes three default attributes:

message : error message when validation fails.

group : grouping condition (supports SpEL); validation runs only when the group condition is satisfied.

condition : activation condition (supports SpEL); validation runs when the expression is empty or evaluates to true.

Calling Spring Beans in SpEL

By default the parser cannot resolve Spring beans. Add @EnableSpelValidatorBeanRegistrar to the main application class to enable bean access:

@EnableSpelValidatorBeanRegistrar
@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

Custom Constraint Annotations

Annotate your custom annotation with @SpelConstraint and specify the validator.

Add the three fixed fields message , group , and condition to the annotation.

Implement the validator logic (see cn.sticki.validator.spel.SpelConstraint for reference).

Images in the original article illustrate the definition and implementation of a custom constraint.

📦 Example Project

A simple example project is available at:

https://github.com/stick-i/spel-validator-example

Final Notes

Performance

The current implementation uses a lot of reflection, which adds overhead; caching strategies are planned to mitigate the impact.

A Strange Phenomenon

When using SpEL in the project, only the condition attribute is recognized by IntelliJ IDEA 2024.1 for @Language("SpEL") annotations, while assertTrue is not. This may be an IDE bug.

GitHub address: https://github.com/stick-i/spel-validator
backendJavaSPELSpring BootParameter Validationcustom annotations
Code Ape Tech Column
Written by

Code Ape Tech Column

Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.