Как применить аннотации компонента DynamoDB к объектам POJO другого проекта с помощью дженериков?
Я пытаюсь настроить в своем приложении микросхему для устранения дублирования кода (принцип «СУХОЙ»). В частности, мне нужно использовать аннотации из моего проекта в сочетании с несколькими классами POJO, которые находятся в другом проекте (это ниже) и которые не разделяют мои зависимости.
Итак, я начал с этого:
public abstract class DynamoRepo<T> {
@DynamoDbBean
public static class Entity<T> {
private Number id;
private T bean;
@DynamoDbPartitionKey
@DynamoDbConvertedBy(IdConverter.class)
public Number getId() {
return id;
}
public void setId(Number id) {
this.id = id;
}
@DynamoDbFlatten
public T getBean() {
return bean;
}
public void setBean(T bean) {
this.bean = bean;
}
...
... аннотации требуются во время выполнения для кода ниже
private DynamoDbTable<Entity<?>> table;
... с небольшой настройкой в конструкторе ...
table = enhancedClient.table(tableName, TableSchema.fromBean(new Entity<? extends T>() {}.getClass()));
... Я бы хотел принять
<T>
что не требует, чтобы звонящий знал о
Entity
:
public void putItem(T item) {
table.putItem(new Entity<T>(item));
}
Увы, этот код не компилируется. Здесь есть несколько проблем, и любые небольшие изменения приводят к другой ошибке компиляции.
Как я могу сделать эту работу, не добавляя
@DynamoDb
аннотации к базовым POJO (которые не входят в мой проект и не имеют DynamoDB в качестве зависимости) или должны вручную создавать подклассы, которые расширяют каждый из POJO (и выкидывают DRY из окна, создавая целую иерархию параллельных объектов)?
Этот вопрос касается ясности кода. Пожалуйста, не беспокойтесь о накладных расходах.
1 ответ
Недавно я реализовал абстрактный DAO (репозиторий) в стиле Spring Data и реактивным способом с помощью WebFlux для AWS DynamoDB. Не идеально, но отлично работает и, как я предполагаю, подходит для вашего случая:
Первая часть — это абстрактный DAO. Общий интерфейс выглядит так:
public interface DynamoDbRepository<T> {
/** Constant prefix for logging purposes */
String SN = "[DynamoDbRepository]";
Mono<PutItemEnhancedResponse<T>> insert(final T object);
Mono<T> getById(final String id);
Flux<T> getAll();
}
Класс реализации логики, расширяющий DynamoDbRepository :
@Log4j2
@Repository
public abstract class EntityDynamoDbRepository<T> implements DynamoDbRepository<T> {
private final Class<T> clazz;
private DynamoDbAsyncTable<T> dynamoDbAsyncTable;
@Autowired
@SneakyThrows
public final void setAsyncClient(DynamoDbEnhancedAsyncClient asyncClient) {
DynamoDbTable tableName = AnnotationUtils.getAnnotation(clazz, DynamoDbTable.class);
this.dynamoDbAsyncTable =
asyncClient.table(tableName.value(), TableSchema.fromBean(this.clazz));
}
@SuppressWarnings("unchecked")
@SneakyThrows
public EntityDynamoDbRepository() {
clazz =
(Class<T>) GenericTypeResolver.resolveTypeArgument(getClass(), DynamoDbRepository.class);
if (clazz == null) {
throw new Exception("Not possible to resolve generic type");
}
}
@Override
public Mono<PutItemEnhancedResponse<T>> insert(final T object) {
final PutItemEnhancedRequest<T> putItemEnhancedRequest =
PutItemEnhancedRequest.builder(this.clazz)
.item(object)
.build();
return Mono.fromFuture(dynamoDbAsyncTable.putItemWithResponse(putItemEnhancedRequest));
}
public Mono<T> getById(final String id) {
return Mono.fromFuture(dynamoDbAsyncTable.getItem(getKeyBuild(id)));
}
public Flux<T> getAll() {
return Flux.from(dynamoDbAsyncTable.scan().items());
}
private Key getKeyBuild(final String id) {
return Key.builder().partitionValue(id).build();
}
}
И, наконец, реализовать конкретный репозиторий:
@Repository
@Log4j2
public class ConcreteRepository extends EntityDynamoDbRepository<ConcreteEntity> {}
Вы могли заметить метод setAsyncClient , который определяет DynamoDbAsyncTable . Из-за того, что @DynamoDbBean использует имя класса сущностей в качестве имени таблицы DynamoDB, я помещаю пользовательскую аннотацию, чтобы назначить там имя пользовательской таблицы:
@Retention(RetentionPolicy.RUNTIME)
@DynamoDbBean
public @interface DynamoDbTable {
String value();
}
Отвечая на ваш вопрос: вы можете добавить/вызвать все, что хотите, внутри конструктора EntityDynamoDbRepository , чтобы обернуть ваш <POJO> любой возможной логикой.
ps: я не вставлял bean-компонент DynamoDbEnhancedAsyncClient, но на GitHub есть много примеров