최근 DynamoDB로 프로젝트를 진행하면서 수많은 시행착오와 불편함을 겪었다.
DynamoDB는 현재 Spring Data에서 공식적으로 지원하지 않는다.
DynamoDB는 Date만 지원해주고 있는데...
설명은 나중에 추가하겠다.
리플렉션을 이용한 Convertor
DynamoDBTypeConbertedTimestamp를 본따 만들어 보았다.
나는 개인적으로 코드 규칙을 비슷하게 만드는게 쉽게 파악해 쓰기 편하다 생각하므로 최대한 비슷하게 만들었다.
물론 실제로는 리플렉션이 아닌 Factory패턴으로 되어있으나 편의상, 그리고 LocalDate Type들의 변동이 없을 것이며 직접 Factorr에 추가해줄 수 있는 구조가 아니기에 간단하게 구현하였다.
거기에 비슷한 구조를 본따 만들면 이미 만들어져 있는 기능들을 유용하게 이용 가능했다.
@DynamoDBTypeConverted(converter = DynamoDBTypeConvertedLocalTimestamp.Converter.class)
@DynamoDBTyped(DynamoDBMapperFieldModel.DynamoDBAttributeType.S)
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface DynamoDBTypeConvertedLocalTimestamp {
String pattern() default "";
String timeZone() default "Asia/Seoul";
static final class Converter<T> implements DynamoDBTypeConverter<String, Object> {
private Class<T> targetType;
private DateTimeFormatter dateTimeFormatter;
public Converter(Class<T> targetType, DynamoDBTypeConvertedLocalTimestamp annotation) {
String pattern = annotation.pattern();
this.targetType = targetType;
this.dateTimeFormatter = StringUtils.isBlank(pattern) ? getDefaultDateTimeFormatter(targetType) : DateTimeFormatter.ofPattern(pattern);
this.dateTimeFormatter.withZone(ZoneId.of(annotation.timeZone()));
}
private DateTimeFormatter getDefaultDateTimeFormatter(Class<T> clazz) {
if (clazz.isAssignableFrom(LocalDate.class)) return DateTimeFormatter.ISO_LOCAL_DATE;
else if (clazz.isAssignableFrom(LocalTime.class)) return DateTimeFormatter.ISO_LOCAL_TIME;
else if (clazz.isAssignableFrom(LocalDateTime.class)) return DateTimeFormatter.ISO_LOCAL_DATE_TIME;
else throw new IllegalArgumentException("Type is not LocalDate, LocalTime, LocalDateTime!");
}
@SneakyThrows
@Override
public String convert(Object object) {
return (String) targetType.getMethod("format", DateTimeFormatter.class).invoke(object, dateTimeFormatter);
}
@SneakyThrows
@Override
public Object unconvert(String text) {
return targetType.getMethod("parse", CharSequence.class, DateTimeFormatter.class).invoke(null, text, dateTimeFormatter);
}
}
}
리플렉션을 이용한 AutoGenerated
이 역시 간단한게 구현했으며 해당 어노테이션으로 LocalDate 타입에 모두 사용가능하다
또한 DynamoDBAutoGenerateStategy를 이용해서 create update 등 원하는 시점만 골라 사용 가능하다.
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAutoGenerateStrategy;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAutoGenerated;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAutoGenerator;
import lombok.SneakyThrows;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@DynamoDBAutoGenerated(generator = DynamoDBAutoGeneratedLocalTimestamp.Generator.class)
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD})
public @interface DynamoDBAutoGeneratedLocalTimestamp {
DynamoDBAutoGenerateStrategy strategy() default DynamoDBAutoGenerateStrategy.ALWAYS;
static final class Generator<T> extends DynamoDBAutoGenerator.AbstractGenerator<Object> {
private final Class<T> targetType;
public Generator(Class<T> targetType, DynamoDBAutoGeneratedLocalTimestamp annotation) {
super(annotation.strategy());
this.targetType = targetType;
}
@SneakyThrows
@Override
public final Object generate(Object currentValue) {
return targetType.getMethod("now").invoke(null);
}
}
}
'JAVA > Spring Boot' 카테고리의 다른 글
LoggerFactory is not a Logback LoggerContext but Logback is on the classpath 해결방법(Spring + embedded redis) (1) | 2020.08.04 |
---|---|
Spring Boot의 application.propertise 또는 yaml (0) | 2020.04.23 |