java - 为什么注释成员不支持静态方法引用类型?

标签 java annotations

我想创建自己的日期时间验证注释

import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.LocalDateTime;
import java.time.ZonedDateTime;
import java.time.temporal.TemporalQuery;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

@Constraint(validatedBy = DateTimeValidator.class)
public @interface DateTime {
    String message() default "{com.example.constraints.DateTime.message}";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};

    TemporalQuery<?>[] queries() default {ZonedDateTime::from, LocalDateTime::from};
}

public class DateTimeValidator implements ConstraintValidator<DateTime, String> {

    private DateTime dateTime;
    private TemporalQuery<?>[] queries;

    @Override
    public void initialize(DateTime dateTime) {
        queries = dateTime.queries();
    }

    @Override
    public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
        try {
            DateTimeFormatter.ISO_DATE_TIME.parseBest(s, queries);
        } catch (DateTimeParseException e) {
            return false;
        }
        return true;
    }
}

注解类型不支持静态方法引用有什么原因吗?否则实现我的目标的最佳方式是什么?

最佳答案

简而言之,因为语言禁止这样做。

Java 语言规范JLS Chapter 9 中做了区分在普通接口(interface)注解类型之间。

虽然普通接口(interface)允许标准的MethodHeaderMethodBody 产品,根据定义 注释类型方法的限制要多得多。具体来说,注释的值被实现为虚拟方法,其return types are limited to :

  • 原语
  • 字符串
  • 类(class)
  • 枚举类型
  • 其他注解(除了自身,或那些允许循环路径返回自身的注解)
  • 上述的数组

因此,根据语言 规范,如果您尝试使用任何其他类型,javac 必须生成编译时错误。这种语言限制的基本原理来自注释值在字节码中的存储方式所施加的实际限制。

当您在元素上放置注释时,元素的字节码必须引用值而不需要访问任何其他 类。具体来说,所有注释值都真正存储在封闭类常量池中。

常量池的用途很多,但它是一种相对简单的数据结构,不宜用它来编码复杂的数据。通常条目是类名、方法名、方法签名等。注解参数在池中编码的当前方式建议一个方法句柄至少需要三 (3) 个这样的条目对于上述内容,不考虑这些方法是静态的、虚拟的、构造函数的还是来自接口(interface)的复杂性。它们是否涉及泛型?等等

你能做什么

如上所述,允许 类型之一是任何枚举。如果您希望支持的 TemporalQuery 实现在编译时可以被限制为一个固定集合,那么您可以定义一个枚举来包含一个每个支持的实现的静态成员并将其用作间接层:

public enum TemporalQueryValidation {
    ZONED_DATE_TIME(ZoneDateTime::from),
    LOCAL_DATE_TIME(LocalDateTime::from),
    // ... more ...
    ;

    private final TemporalQuery<?> query;

    private TemporalQueryValidation (TemporalQuery<?> q) {
        this.query = q;
    }

    TemporalQuery<?> getQuery() {
        return query;
    }
}

@Constraint(validatedBy = DateTimeValidator.class)
public @interface DateTime {
    // ... other annotation values ...
    TemporalQueryValidation[] queries() default { ZONED_DATE_TIME, LOCAL_DATE_TIME };
}

public class DateTimeValidator implements ConstraintValidator<DateTime, String> {

    private DateTime dateTime;
    private TemporalQuery<?>[] queries;

    @Override
    public void initialize(DateTime dateTime) {
        TemporalQueryValidation[] validations = dateTime.queries();
        queries = new TemporalQuery<?>[validations.length];
        for (int i = 0; i < queries.length; i++) {
            queries[i] = validations[i].getQuery();
        }
    }

    @Override
    public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
        try {
            DateTimeFormatter.ISO_DATE_TIME.parseBest(s, queries);
        } catch (DateTimeParseException e) {
            return false;
        }
        return true;
    }
}

关于java - 为什么注释成员不支持静态方法引用类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29984211/

相关文章:

java - @InitBinder 的 value 元素的用途是什么?

java - 使用 jaxb 注释映射 XML 子子项

Swift 4 Mapview 没有调用委托(delegate)方法 f

java - 即使客户端未发送证书,SSL 套接字连接仍能正常工作?

java - 如何构建服务以及如何在 CQ5 中激活服务

java - 当项目部署到 tomcat 时,sql 查询不记录到文件

java - Spring注入(inject)和注解

java - 如何返回Id插入存储过程+mybatis

java - 从 Grails 应用程序使用 JNI native 库时出现 UnsatisfiedLinkError

java - 没有注释的 JAXB Unmarshal