【问题标题】:How to implement domain strong typing using Java annotations如何使用 Java 注解实现域强类型
【发布时间】:2021-04-13 19:37:01
【问题描述】:

问题

使用存储为 Long 的多个外键的贫血域对象。试图防止使用某种强类型域类型转置值。

例如给定以下产品评论类:

public class Review {
  private Long id;
  private Long productId;
  private int rating;
  private String title;
  private String body;
  private Long createdById;
  private Date createdAt;
  //...
}

我想防止自己不小心将错误的外键转移到任何 Long 的:

ReviewDto dto = // some DTO that was parsed from JSON for example
Review review = new Review();
review.productId = dto.getCreatedById(); // see transpose error here as typical type checking doesn't catch it

解决方案

继承

一个明显的解决方案是为域类型实现一个简单的类层次结构。

public class LongId {
  private Long id;
  //...
}
//...
public class ReviewId extends LongId {...}
public class ProductId extends LongId {...}
//...
public class Review {
  private ReviewId id;
  private ProductId productId;
  //...
}
//...
ReviewDto dto = // some DTO that was parsed from JSON for example
Review review = new Review();
review.productId = dto.getCreatedById(); // compile error as types don't match

此解决方案的缺点是包含实际类型,因此很难将其编组到 JSON 和输入/输出数据库,需要我编写大量自定义序列化程序。

泛型

我见过的另一个解决方案是使用泛型,但增加了冗长的语法,并且仍然必须编写自定义序列化程序才能获得简单的类型。

public class LongId<T> {
  private Long id;
  //...
}
//...
public interface ReviewId {}
public interface ProductId {}
//...
public class Review {
  private LongId<ReviewId> id;
  private LongId<ProductId> productId;
  //...
}
//...
ReviewDto dto = // some DTO that was parsed from JSON for example
Review review = new Review();
review.productId = dto.getCreatedById(); // compile error as types don't match

注释?

有人用 Java 注释解决了这个问题吗?涉及到什么?一旦您了解了 hello world 示例,Java 注释的文档环境就会变得稀少。我发现只提供了一个传递参考,即系统是可插拔的,我必须编写自己的 maven 插件来进行类型检查。我对此非常感兴趣,因为我不希望在其他样板文件中编写自定义序列化程序,因为这些类型只是普通的 Java 引用类型,大多数 JSON 和数据库库都大力支持。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD, ElementType.LOCAL_VARIABLE, ElementType.PARAMETER })
@TypeQualifier(applicableTo = Long.class)
public @interface ReviewId {}
//...
public class Review {
  private @ReviewId Long id;
  private @ProductId Long productId;
  //...
}
//...
ReviewDto dto = // some DTO that was parsed from JSON for example
Review review = new Review();
review.productId = dto.getCreatedById(); // **magic** happens here so that both maven and IDE catch this at compile time

【问题讨论】:

  • 注解一般用于切面编程。为什么是注释而不是强类型字段?例如,具有单个 Long 值的 ProductId 类。
  • 如解决方案>问题中的继承中所述,它将需要样板文件来解析它进出 JSON 和数据库。

标签: java annotations strong-typing


【解决方案1】:

Checker Framework 是一种基于注释的方法,正如您所要求的那样。

Checker 框架允许您使用类型注释指定域属性,并在编译时强制执行这些属性。 它被亚马逊、谷歌、优步等公司使用。

您可以使用pre-built type system,也可以使用build your own,它可以少至4 行代码(example)。无需编写 Maven 插件。

有关详细信息,请参阅the Checker Framework manual

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-11-11
    • 2018-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-03
    • 2020-03-09
    相关资源
    最近更新 更多