#java #annotations #strong-typing
#java #аннотации #строгая типизация
Вопрос:
Проблема
Работа с анемичными объектами домена с несколькими внешними ключами, хранящимися как длинные. Попытка защитить от переноса значений с помощью каких-то строго типизированных доменных типов.
Например, учитывая следующий класс обзора продукта:
public class Review {
private Long id;
private Long productId;
private int rating;
private String title;
private String body;
private Long createdById;
private Date createdAt;
//...
}
Я бы хотел, чтобы я не мог случайно перенести неправильный внешний ключ в любой из длинных ключей:
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? Что было задействовано?Область документации для аннотаций Java становится скудной, как только вы пройдете примеры hello world. То, что я нашел, дало только мимолетную ссылку на то, что система подключаема и что мне придется написать свой собственный плагин 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
Комментарии:
1. Аннотации обычно предназначены для аспектного программирования. Почему аннотации, а не строго типизированные поля? Например, класс ProductID, который имеет одно длинное значение.
2. Как объяснено в разделе Решения> Наследование в вопросе, для его анализа в JSON и из базы данных потребуется шаблон.
Ответ №1:
Платформа проверки — это подход, основанный на аннотациях, как вы и просили.
Платформа проверки позволяет указывать свойства домена с аннотациями типов и обеспечивает соблюдение этих свойств во время компиляции. Он используется в таких компаниях, как Amazon, Google, Uber и многих других.
Вы можете использовать предварительно созданную систему типов или создать свою собственную, которая может содержать всего 4 строки кода (пример). Вам не нужно писать подключаемый модуль Maven.
Для получения дополнительной информации см. Руководство Checker Framework .