验证记录的构造函数参数值

问题描述 投票:0回答:1

我正在使用像 17 或 21 这样的现代 java 版本以及基于 Maven 的项目,我想知道是否有任何方法可以获取构造函数参数值并简单地打印它们或验证它们并最终抛出异常?

为了向您提供更多详细信息,我发布了我当前拥有的代码:

聚合运行验证:

public record User(
        Id id,
        Email email,
        Password password
) {
    public User {
        try (ValidatorFactory factory = Validation.buildDefaultValidatorFactory()) {
            Validator validator = factory.getValidator();
            Map<String, String> validationErrorMessages = new HashMap<>();

            String idViolations = validator.validate(id).stream().map(ConstraintViolation::getMessage).toList().toString();
            if (!idViolations.equals("[]")) {
                validationErrorMessages.put(id.toString(), idViolations);
            }

            String emailViolations = validator.validate(id).stream().map(ConstraintViolation::getMessage).toList().toString();
            if (!emailViolations.equals("[]")) {
                validationErrorMessages.put(email.toString(), emailViolations);
            }

            String passwordViolations = validator.validate(id).stream().map(ConstraintViolation::getMessage).toList().toString();
            if (!passwordViolations.equals("[]")) {
                validationErrorMessages.put(password.toString(), passwordViolations);
            }

            if (!validationErrorMessages.isEmpty()) {
                throw new ValidationException(validationErrorMessages.toString());
            }
        }
    }
}

和值对象:

public record Id(@NotNull Long value) {}

@GroupSequence({Email.class, Additional.class})
public record Email(
        @NotNull
        @Pattern(regexp = "^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+$",
                groups = Additional.class,
                message = "Invalid e-mail format")
        String value
) {
}

@GroupSequence({Password.class, Additional.class})
public record Password(
        @NotNull
        @Size(min = 12,
                message = "must be at least {min} characters long")
        @Pattern(regexp = ".*[a-z].*",
                groups = Additional.class,
                message = "must contain a small letter")
        @Pattern(regexp = ".*[A-Z].*",
                groups = Additional.class,
                message = "must contain a capital letter")
        @Pattern(regexp = ".*\\d.*",
                groups = Additional.class,
                message = "must contain a digit")
        @Pattern(regexp = ".*[#?!].*",
                groups = Additional.class,
                message = "must contain one of special characters: [#, ?, !]")
        String value
) {
}

我想要实现的是注释(也许用@Aggregate?)用户记录并在后台完成验证:

@Aggregate
public record User(
    Id id,
    Email email,
    Password password
) {}

或者甚至放弃注释,将存储在特定包内的每条记录都进行验证,而无需重复代码或注释。

我读过一些关于注释处理器、byte buddy 插件的内容,或者看过一些关于 java 21 构造函数钩子的内容,但读得越多,我就越不明白哪种解决方案适合我的需求。

请帮助我。 :)

java maven domain-driven-design
1个回答
0
投票

这是概念验证测试。

项目树

  • Maven
  • JDK 17
  • 雅加达验证-api
  • 雅加达埃尔
  • 休眠验证器
UserValidation
├── pom.xml
└── src
    └── main
        └── java
            └── com
                └── example
                    ├── Email.java
                    ├── EMailTestMain.java
                    ├── Id.java
                    ├── Password.java
                    ├── PasswordTestMain.java
                    ├── User.java
                    └── UserTestMain.java

可以直接查看UserTestMain.java和测试3-测试用户验证的测试结果是否是你想要的。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>Jakarta Validation Project</description>
    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>jakarta.validation</groupId>
            <artifactId>jakarta.validation-api</artifactId>
            <version>3.0.2</version>
        </dependency>
        <!-- Hibernate Validator (Provider) -->
        <dependency>
            <groupId>org.hibernate.validator</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>7.0.5.Final</version>
        </dependency>

        <!-- Logging for Hibernate Validator -->
        <!-- For EL expression parsing -->
        <dependency>
            <groupId>org.glassfish</groupId>
            <artifactId>jakarta.el</artifactId>
            <version>4.0.0</version>
        </dependency>
    </dependencies>
    <build>
        <finalName>app</finalName>
    </build>
</project>

密码.java

package com.example;

import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;

public class Password {
    @NotNull(message = "Password cannot be null")
    @Size(min = 12, message = "Password must be at least {min} characters long")
    @Pattern(regexp = ".*[a-z].*", message = "Password must contain a lowercase letter")
    @Pattern(regexp = ".*[A-Z].*", message = "Password must contain an uppercase letter")
    @Pattern(regexp = ".*\\d.*", message = "Password must contain a digit")
    @Pattern(regexp = ".*[#?!].*", message = "Password must contain one of the special characters: [#, ?, !]")
    private String value;

    public Password(String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }
}

密码测试Main.java

package com.example;

import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validation;
import jakarta.validation.Validator;
import jakarta.validation.ValidatorFactory;

import java.util.Set;

public class PasswordTestMain {
    public static void main(String[] args) {
        // Creating a Validator Factory
        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        Validator validator = factory.getValidator();

        // Example password (test passwords that do not conform to the rules)
        //Password password = new Password("Short1!");
        Password password = new Password("AAAAA");

        // Perform verification
        Set<ConstraintViolation<Password>> violations = validator.validate(password);

        if (!violations.isEmpty()) {
            System.out.println("Password validation failed:");
            for (ConstraintViolation<Password> violation : violations) {
                System.out.println(violation.getMessage());
            }
        } else {
            System.out.println("Password is valid!");
        }
    }
}

电子邮件.java

package com.example;

import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;

public class Email {
    @NotNull(message = "Email cannot be null")
    @Pattern(
            regexp = "^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+$",
            message = "Invalid e-mail format"
    )
    private String value;

    public Email(String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }
}

EMailTestMain.java

package com.example;

import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validation;
import jakarta.validation.Validator;
import jakarta.validation.ValidatorFactory;

import java.util.Set;

public class EMailTestMain {
    public static void main(String[] args) {
        // Creating a Validator Factory
        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        Validator validator = factory.getValidator();

        // Sample emails (testing valid and invalid emails)
        Email validEmail = new Email("[email protected]");
        Email invalidEmail = new Email("example@@example.com");

        // Verify valid email
        System.out.println("Valid Email Test: >>>> " + validEmail);
        validateEmail(validator, validEmail);

        // Verify invalid email
        System.out.println("\nInvalid Email Test: >>>> " + invalidEmail);
        validateEmail(validator, invalidEmail);
    }

    private static void validateEmail(Validator validator, Email email) {
        Set<ConstraintViolation<Email>> violations = validator.validate(email);

        if (!violations.isEmpty()) {
            System.out.println("Validation failed:");
            for (ConstraintViolation<Email> violation : violations) {
                System.out.println(violation.getMessage());
            }
        } else {
            System.out.println("Validation passed: " + email.getValue());
        }
    }
}

Id.java

package com.example;

import jakarta.validation.constraints.NotNull;

public class Id {

    @NotNull(message = "Id value cannot be null")
    private Long value;

    public Id(Long value) {
        this.value = value;
    }

    public Long getValue() {
        return value;
    }

    public void setValue(Long value) {
        this.value = value;
    }
}

用户.java

package com.example;

import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;

public class User {

    @NotNull(message = "Id cannot be null")
    private Id id;

    @Valid
    @NotNull(message = "Email cannot be null")
    private Email email;

    @Valid
    @NotNull(message = "Password cannot be null")
    private Password password;

    public User(Id id, Email email, Password password) {
        this.id = id;
        this.email = email;
        this.password = password;
    }

    public Id getId() {
        return id;
    }

    public void setId(Id id) {
        this.id = id;
    }

    public Email getEmail() {
        return email;
    }

    public void setEmail(Email email) {
        this.email = email;
    }

    public Password getPassword() {
        return password;
    }

    public void setPassword(Password password) {
        this.password = password;
    }
}

UserTestMain.java

package com.example;

import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validation;
import jakarta.validation.Validator;
import jakarta.validation.ValidatorFactory;

import java.util.Set;

public class UserTestMain {
    public static void main(String[] args) {
        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        Validator validator = factory.getValidator();

        // Testing for a valid User object
        System.out.println("Test Validation User >>>>");
        Id validId = new Id(12345L);
        Email validEmail = new Email("[email protected]");
        Password validPassword = new Password("ValidPassword123!");

        User validUser = new User(validId, validEmail, validPassword);
        validateUser(validator, validUser);

        // Testing for invalid User objects
        System.out.println("Test Invalid User >>>>");
        Id invalidId = null;
        Email invalidEmail = new Email("invalid-email");
        Password invalidPassword = new Password("short");

        User invalidUser = new User(invalidId, invalidEmail, invalidPassword);
        validateUser(validator, invalidUser);
    }

    private static void validateUser(Validator validator, User user) {
        Set<ConstraintViolation<User>> violations = validator.validate(user);

        if (!violations.isEmpty()) {
            System.out.println("Validation failed:");
            for (ConstraintViolation<User> violation : violations) {
                System.out.println(violation.getPropertyPath() + ": " + violation.getMessage());
            }
        } else {
            System.out.println("Validation passed for user.");
        }
    }
}

构建和测试

构建

mvn clean package

下载库

mvn dependency:copy-dependencies -DoutputDirectory=target/libs

测试

测试 1 - 测试密码验证

java -cp "target/libs/*:target/app.jar" com.example.PasswordTestMain
  • 密码password = 新密码("AAAAA");

结果:

Password validation failed:
Password must contain a digit
Password must be at least 12 characters long
Password must contain a lowercase letter
Password must contain one of the special characters: [#, ?, !]

测试 2 - 测试电子邮件验证

java -cp "target/libs/*:target/app.jar" com.example.EMailTestMain

结果:

Valid Email Test: >>>> com.example.Email@1534f01b
Validation passed: [email protected]

Invalid Email Test: >>>> com.example.Email@4218d6a3
Validation failed:
Invalid e-mail format

测试 3 - 测试用户验证

java -cp "target/libs/*:target/app.jar" com.example.UserTestMain

结果 - 1 - 验证用户:

Test Validation User >>>>
Validation passed for user.

结果 - 2 - 无效用户:

Test Invalid User >>>>
Validation failed:
password.value: Password must be at least 12 characters long
password.value: Password must contain a digit
password.value: Password must contain an uppercase letter
email.value: Invalid e-mail format
id: Id cannot be null
password.value: Password must contain one of the special characters: [#, ?, !]
© www.soinside.com 2019 - 2024. All rights reserved.