JPA를 사용할 때부터 계속 하려고 했던건데, 이번에 소기의 목적에서 아주 일부분은 달성하여
진행했던 과정을 기록차원에서 남긴다.
선요약
- 지정한 패키지의
@Entity
annotation이 선언된 클래스를 검색하여 DDL script를 파일로 생성한다.
- DDL script 생성시 column comment도 함께 생성한다(제일 고민을 많이 함).
@Embedded
annotation이 달린 항목도 comment를 생성한다.
TODO
- Table comment 추가
- Embedded 순환 처리
구현부
작업의 흐름
- 우선 Reflections을 이용하여 지정한 package안에 존재하는 클래스 중
@Entity
annotation이 선언된 클래스를 검색한다.
- 검색된 클래스 목록에서 클래스내에 정의된
Field
를 추출한다.
- 추출된 클래스별
Field
에서 @Column
, @JoinColumn
및 @Embedded
annotation이 선언된 Field
를 검사한다.
- 3가지의 annotation중 하나가 선언된
Field
에서 내가 작성한 annotation(@ColumnComment
)이 선언되어 있는지 확인한다.
만약 @ColumnComment
annotation이 선언되어 있다면 Hibernate가 가지고 있는
org.hibernate.mapping.Column
객체의 setComment(String)
함수를 호출하여 column comment를 할당한다.
- 위의 과정을 거친
org.hibernate.boot.spi.MetadataImplementor
객체를
org.hibernate.tool.hbm2ddl.SchemaExport
클래스를 이용하여 지정된 파일로 저장한다.
1. @Entity
annotation이 선언된 클래스 목록 추출하기
String _basePackage = "net.clfif3.sample";
ConfigurationBuilder _builder = new ConfigurationBuilder();
FilterBuilder _filterBuilder = new FilterBuilder();
_builder.addUrls(ClassPathHelper.forPackage(_basePackage));
_filterBuilder = _filterBuilder.includePackage(_basePackage));
_builder.filterInputsBy(_filterBuilder);
_builder.setExpandSuperTypes(false);
Reflections _reflections = new Reflections(_builder);
//
// @Entity annotation이 선언된 클래스 검색 및 반환
//
Set<Class<?>> _entitySet = _reflections.getTypeAnnotatedWith(Entity.class);
//
// Meta data 생성
//
MetadataSources _metadata = new MetadataSources(
new StandardServiceRegistryBuilder()
.applySetting("hibernate.dialect", MySQL8Dialect.class.getName()).build()
);
//
// 검색된 클래스를 _metadata에 추가
//
_entitySet.forEach(_metadata::addAnnotatedClass);
//
// Meta data 기반으로 Hibernate에서 hbm2ddl을 처리하기 위한 변환된 데이터를 생성
// 해당 결과에서 실제 변환된 정보를 추출(`MetadataImpl#getEntityBindingMap()`)
//
MetadataImplementor _implementor = (MetadataImplementor)_metadata.buildMetadata();
Map<String, PersistentClass> _classMap = ((MetadataImpl)_implementor).getEntityBindingMap();
2. 검색된 클래스내에 정의된 Field
목록 추출
_classMap.forEach((key, value) => {
Class<?> _mappedClass = value.getMappedClass();
Field[] _declaredFields = _mappedClass.getDeclaredFields();
});
3. 추출된 Field
에서 @Column
, @JoinColumn
및 @Embedded
annotation이 선언된 항목 검색
중간의 checkExistColumn(org.hibernate.mapping.Column, Field)
함수는 마지막 전체 소스 참고