Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
107 views
in Technique[技术] by (71.8m points)

How to implement domain strong typing using Java annotations

Problem

Working with anemic domain objects with multiple foreign keys stored as Long's. Trying to protect against transposing the values with some kind of strong typed domain types.

For example given the following product review class:

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

I'd like to prevent myself from accidentally transposing the wrong foreign key to any of the Long's:

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

Solution(s)

Inheritance

An obvious solution is to implement a simple class hierarchy for domain types.

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

The downside to this solution is that the actual type is contained and therefore laborious to marshal it to/from JSON and in/out of the database requiring me to write lots of custom serializers.

Generics

Another solution I've seen done is using generics but adds verbose syntax and still having to write custom serializers just to get at a simple type.

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

Annotations?

Anyone pull this off with Java annotations? What was involved? The documentation landscape for Java annotations is sparse once you get past the hello world examples. What I have found gave only a passing reference that the system is pluggable and that I'd have to write my own maven plug-in to do the type checking. I'm very interested in this as a possible solution as I don't expect to have to write custom serializers among other boilerplate as the types are just plain Java reference types that are greatly supported by most JSON and database libraries.

@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
question from:https://stackoverflow.com/questions/65623179/how-to-implement-domain-strong-typing-using-java-annotations

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

The Checker Framework is an annotation-based approach, as you requested.

The Checker Framework permits you to specify domain properties with type annotations, and it enforces those properties at compile time. It is used at companies such as Amazon, Google, Uber, and many others.

You can use a pre-built type system, or you can build your own which can be as little as 4 lines of code (example). You do not need to write a Maven plug-in.

For more information, see the Checker Framework manual.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...