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 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…