spring boot/기술 적용

jpa comment를 custom annotation으로 만들기

ballde 2022. 7. 20. 13:37

배경

보통 jpa를 할 때 comment를 달기 위해서는 @Column(columnDefinition = ...) 이렇게 해야한다.

@Entity
public class Person {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @Column(columnDefinition = "varchar(10) not null comment '이름'")
    private String name;

    private String description;

}

코드에 주석처리로 처리 할 수 있겠지만 DB에 설명이 있기 위해서는 코멘트를 적어야한다. (혼자 개발하는게 아니니까?)

아 근데 매번 저렇게 추가하는거 귀찮은데? 어노테이션으로 comment를 달아줄 수는 없을까?

 

Comment Custom Annotation을 만들기

Comment annotation 만들기

mysql 기준으로 기존 컬럼에 코멘트 추가해주기 위해서는

ALTER TABLE <<테이블 이름>> MODIFY <<컬럼 이름>> <<type>> COMMENT '...'
를 해줘야한다. 그래서 @Comment(value = '...', type = 'VARCHAR(255)') 와 같이 두가지를 넣어준다.

@Target({FIELD})
@Retention(RUNTIME)
public @interface Comment {

    // db comment annotation
    String value() default "";
    String type() default "varchar";

}

CommandLineRunner 만들기

@Configuration
public class CommentCommandLineRunner implements CommandLineRunner {

    @PersistenceContext
    private EntityManager entityManager;
    @Resource
    private JdbcTemplate jdbcTemplate;
    @Resource private HibernateProperties hibernateProperties;

    @Override
    public void run(String... args) {
        String ddlAuto = this.hibernateProperties.getDdlAuto();
        if (Objects.nonNull(ddlAuto) && "update".equalsIgnoreCase(ddlAuto)) {
            this.scanCommentAnnotationOnEntityAndCreate();
        }
    }

    private void scanCommentAnnotationOnEntityAndCreate() {
        EntityManagerFactory entityManagerFactory = this.entityManager.getEntityManagerFactory();
        SessionFactoryImpl sessionFactory = entityManagerFactory.unwrap(SessionFactoryImpl.class);
        Map<String, EntityPersister> persisterMap = sessionFactory.getMetamodel().entityPersisters();

        if (Objects.nonNull(persisterMap) && persisterMap.keySet().size() > 0) {
            for (Map.Entry<String, EntityPersister> entry: persisterMap.entrySet()) {
                Class<?> targetClazz = entry.getValue().getMappedClass();
                SingleTableEntityPersister persister = (SingleTableEntityPersister)entry.getValue();
                String tableName = persister.getTableName();
                Comment targetClazzAnno = targetClazz.getAnnotation(Comment.class);
                if (Objects.nonNull(targetClazzAnno)) {
                    String sql = String.format("ALTER TABLE %s COMMENT = '%s'", tableName, targetClazzAnno.value());
                    this.jdbcTemplate.execute(sql);
                }
                for (AttributeDefinition attributeDefinition : persister.getAttributes()) {
                    //Property name
                    String propertyName = attributeDefinition.getName();
                    if (propertyName.equalsIgnoreCase("_identifierMapper")) {
                        continue;
                    }
                    Field field;
                    try {
                        field = targetClazz.getDeclaredField(propertyName);
                        if (Objects.nonNull(field)) {
                            Comment anno = field.getAnnotation(Comment.class);
                            if (Objects.nonNull(anno)) {
                                String[] columns = persister.getPropertyColumnNames(propertyName);
                                String sql = String.format("alter table %s MODIFY %s %s comment '%s'", tableName, columns[0], anno.type(), anno.value());
                                this.jdbcTemplate.execute(sql);
                            }
                        }
                    } catch (NoSuchFieldException ex) {
                        //ex.printStackTrace();
                    }
                }
            }
        }
    }

}
@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
public class Banner extends BaseTimeEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Comment(value = "이름입니다.~", type = "VARCHAR(255)")
    private String name;

    @Comment(value = "설명입니다.~", type = "VARCHAR(255)")
    private String description;

 

위 사진처럼 잘 적용되는것을 알 수 있다.

그리고 더 좋은 방법이 있을 수도 있을 것 같다.

근데 @Column(columnDefinition = ...) 이거랑 뭐가 다르냐고 하는 의견도 있네요..

 

 

 

참고 블로그

https://busyman.tistory.com/406

 

오라클 Comment 자동 생성을 위한 Custom Annotation 만들기

SpringBoot 환경에서 오라클을 사용하는데, table은 자동으로 만들어 줘서 좋은데 Comment는 자동으로 안 넣어줘 이래 저래 찾다 보니 딱히 방법이 없었다. Mysql 같은 경우, table을 만들면서 comment를 추

busyman.tistory.com