Last active
March 13, 2023 16:04
-
-
Save sbcoba/e4264f4b4217746767e682c61f9dc3a6 to your computer and use it in GitHub Desktop.
JPA Entity to DDL Generator ( Hibernate 5.x )
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import org.hibernate.boot.MetadataSources; | |
import org.hibernate.boot.registry.StandardServiceRegistry; | |
import org.hibernate.boot.registry.StandardServiceRegistryBuilder; | |
import org.hibernate.boot.spi.MetadataImplementor; | |
import org.hibernate.dialect.Dialect; | |
import org.hibernate.dialect.MySQL5InnoDBDialect; | |
import org.hibernate.tool.hbm2ddl.SchemaExport; | |
import org.springframework.core.io.Resource; | |
import org.springframework.core.io.support.PathMatchingResourcePatternResolver; | |
import org.springframework.core.type.classreading.MetadataReader; | |
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory; | |
import org.springframework.util.FileCopyUtils; | |
import org.springframework.util.StreamUtils; | |
import org.springframework.util.StringUtils; | |
import javax.persistence.Entity; | |
import java.io.File; | |
import java.io.FileInputStream; | |
import java.io.IOException; | |
import java.lang.annotation.Annotation; | |
import java.nio.charset.Charset; | |
import java.text.SimpleDateFormat; | |
import java.util.*; | |
import java.util.stream.Collectors; | |
/** | |
* JPA Entity 클래스를 가지고 DDL 쿼리를 생성할 수 있는 클래스 | |
* | |
* @author sbcoba | |
*/ | |
public class JpaEntityDdlExport { | |
/** | |
* 생성될 파일명 | |
*/ | |
private static final String SCHEMA_SQL = "schema_%s.sql"; | |
/** | |
* 도메인 클래스 경로 위치 ( 범위가 넓어도 @Entity 를 가지는 class만 찾음 ) | |
*/ | |
private final static String PATTERN = "classpath*:**/*.class"; | |
/** | |
* DDL 생성할 DB타입 | |
* org.hibernate.dialect.* 패키지 참조* | |
* | |
* - 오라클 Oracle10gDialect.class | |
* - H2 H2Dialect.class | |
* ... | |
* | |
*/ | |
private final static Class<? extends Dialect> DIALECT_CLASS = MySQL5InnoDBDialect.class; | |
public static void main(String[] args) { | |
Map<String, Object> settings = new HashMap<>(); | |
settings.put("hibernate.dialect", DIALECT_CLASS); | |
settings.put("hibernate.format_sql", true); | |
settings.put("hibernate.physical_naming_strategy","org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy"); | |
settings.put("hibernate.implicit_naming_strategy","org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy"); | |
settings.put("hibernate.id.new_generator_mappings", false); | |
StandardServiceRegistry standardServiceRegistry = new StandardServiceRegistryBuilder() | |
.applySettings(settings) | |
.build(); | |
MetadataSources metadata = new MetadataSources(standardServiceRegistry); | |
String pattern = getPattern(args); | |
List<Class<?>> classes = getClassesByAnnotation(Entity.class, pattern); | |
classes.forEach(metadata::addAnnotatedClass); | |
MetadataImplementor metadataImplementor = (MetadataImplementor) metadata.getMetadataBuilder().build(); | |
SchemaExport schema = new SchemaExport(metadataImplementor); | |
String outputFile = getOutputFilename(args); | |
schema.setOutputFile(outputFile); | |
schema.create(true, false); | |
appendSemicolon(outputFile); | |
appendMetaData(outputFile, settings); | |
} | |
private static String getPattern(String[] args) { | |
String pattern = PATTERN; | |
if(args != null && args.length >= 3 | |
&& StringUtils.hasText(args[2])) { | |
pattern = args[2]; | |
} | |
return pattern; | |
} | |
private static void appendMetaData(String outputFile, Map<String, Object> settings) { | |
String charsetName = "UTF-8"; | |
File ddlFile = new File(outputFile); | |
try { | |
StringBuilder sb = new StringBuilder(); | |
sb.append("/* Generate Environment\n"); | |
for (Map.Entry<String, Object> entry : settings.entrySet()) { | |
sb.append(entry.getKey().toString() + ": " + entry.getValue() + "\n"); | |
} | |
sb.append("*/\n"); | |
String ddlFileContents = StreamUtils.copyToString(new FileInputStream(ddlFile), Charset.forName(charsetName)); | |
sb.append(ddlFileContents); | |
FileCopyUtils.copy(sb.toString().getBytes(charsetName), ddlFile); | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} | |
} | |
/** | |
* 쿼리의 끝 부분에 세미콜론(;) 추가 | |
* @param outputFile | |
*/ | |
private static void appendSemicolon(String outputFile) { | |
String charsetName = "UTF-8"; | |
File ddlFile = new File(outputFile); | |
try { | |
String ddlFileContents = StreamUtils.copyToString(new FileInputStream(ddlFile), Charset.forName(charsetName)); | |
ddlFileContents = ddlFileContents.replaceAll("\n\n", ";\n\n"); | |
ddlFileContents = ddlFileContents.replaceAll("\n.*(?![\f\n\r])$", ";\n"); | |
FileCopyUtils.copy(ddlFileContents.getBytes(charsetName), ddlFile); | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} | |
} | |
private static List<Class<?>> getClassesByAnnotation(Class<? extends Annotation> annotation, String pattern) { | |
return getResources(pattern).stream() | |
.map(r -> metadataReader(r)) | |
.filter(Objects::nonNull) | |
.filter(mr -> mr.getAnnotationMetadata().hasAnnotation(annotation.getName())) | |
.map(mr -> entityClass(mr)) | |
.filter(Objects::nonNull) | |
.collect(Collectors.toList()); | |
} | |
/** | |
* 패턴에 해당하는 리소스 정보를 가져 온다. | |
* @param pattern | |
* @return | |
*/ | |
private static List<Resource> getResources(String pattern) { | |
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); | |
Resource[] resources; | |
try { | |
resources = resolver.getResources(pattern); | |
} catch (IOException e) { | |
throw new RuntimeException(e); | |
} | |
return Arrays.asList(resources); | |
} | |
private static Class<?> entityClass(MetadataReader mr) { | |
String className = mr.getClassMetadata().getClassName(); | |
Class<?> clazz; | |
try { | |
clazz = Class.forName(className); | |
} catch (ClassNotFoundException e) { | |
System.err.printf("%s Class not found", className); | |
return null; | |
} | |
return clazz; | |
} | |
private static MetadataReader metadataReader(Resource r) { | |
MetadataReader mr; | |
try { | |
mr = new SimpleMetadataReaderFactory().getMetadataReader(r); | |
} catch (IOException e) { | |
System.err.printf(e.getMessage()); | |
return null; | |
} | |
return mr; | |
} | |
private static String getOutputFilename(String[] args) { | |
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss"); | |
String currentDate = sdf.format(Calendar.getInstance().getTime()); | |
if(args != null && args.length > 0 | |
&& StringUtils.hasText(args[0])) { | |
String customSchemaName = args[0]; | |
if(customSchemaName.contains("%s")) { | |
return String.format(customSchemaName, currentDate); | |
} | |
return customSchemaName; | |
} | |
return String.format(SCHEMA_SQL, currentDate); | |
} | |
} |
Thank you for the code. However, I get a large number of exceptions when I run it. Here is an example:
java.lang.ClassNotFoundException: org.springframework.hateoas.config.EnableHypermediaSupport$HypermediaType
java.lang.ClassNotFoundException: org.jboss.logging.annotations.Message$Format
I am not using JBoss.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
하이버네이트 5.x 이상