I tried using this class:
Hibernate/JPA: Check generated sql before updating DB Schema (like .NET EF migrations)
I have the following code:
package com.mypackage.jpa.util;
import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.cfg.Configuration;
import org.hibernate.tool.hbm2ddl.SchemaExport;
public class SchemaGenerator {
private Configuration cfg;
public static void main(String[] args) throws Exception {
File f = new File(".");
String directory = f.getAbsoluteFile() + "/src/main/resources/ddl/generated/";
String packageName[] = { "com.mypackage.jpa", "com.mypackage.jpa.legacy", "com.mypackage.jpa.local",
"com.mypackage.jpa.local.impl" };
SchemaGenerator gen = new SchemaGenerator(packageName);
gen.generate(Dialect.MYSQL, directory);
}
@SuppressWarnings("rawtypes")
public SchemaGenerator(String[] packagesName) throws Exception {
cfg = new Configuration();
cfg.setProperty("hibernate.hbm2ddl.auto", "create");
for (String packageName : packagesName) {
for (Class clazz : getClasses(packageName)) {
cfg.addAnnotatedClass(clazz);
}
}
}
@SuppressWarnings("rawtypes")
private List<Class> getClasses(String packageName) throws Exception {
File directory = null;
try {
ClassLoader cld = getClassLoader();
URL resource = getResource(packageName, cld);
directory = new File(resource.getFile());
} catch (NullPointerException ex) {
throw new ClassNotFoundException(packageName + " (" + directory + ") does not appear to be a valid package");
}
return collectClasses(packageName, directory);
}
private ClassLoader getClassLoader() throws ClassNotFoundException {
ClassLoader cld = Thread.currentThread().getContextClassLoader();
if (cld == null) {
throw new ClassNotFoundException("Can't get class loader.");
}
return cld;
}
private URL getResource(String packageName, ClassLoader cld) throws ClassNotFoundException {
String path = packageName.replace('.', '/');
URL resource = cld.getResource(path);
if (resource == null) {
throw new ClassNotFoundException("No resource for " + path);
}
return resource;
}
@SuppressWarnings("rawtypes")
private List<Class> collectClasses(String packageName, File directory) throws ClassNotFoundException {
List<Class> classes = new ArrayList<>();
if (directory.exists()) {
String[] files = directory.list();
for (String file : files) {
if (file.endsWith(".class")) {
// removes the .class extension
classes.add(Class.forName(packageName + '.' + file.substring(0, file.length() - 6)));
}
}
} else {
throw new ClassNotFoundException(packageName + " is not a valid package");
}
return classes;
}
private void generate(Dialect dialect, String directory) {
cfg.setProperty("hibernate.dialect", dialect.getDialectClass());
SchemaExport export = new SchemaExport(cfg);
export.setDelimiter(";");
export.setOutputFile(directory + "ddl_" + dialect.name().toLowerCase() + ".sql");
export.setFormat(true);
export.execute(true, false, false, false);
}
private static enum Dialect {
ORACLE("org.hibernate.dialect.Oracle10gDialect"), MYSQL("org.hibernate.dialect.MySQLDialect"), HSQL(
"org.hibernate.dialect.HSQLDialect"), H2("org.hibernate.dialect.H2Dialect");
private String dialectClass;
private Dialect(String dialectClass) {
this.dialectClass = dialectClass;
}
public String getDialectClass() {
return dialectClass;
}
}
}
And I get the following error:
Exception in thread "main" java.lang.UnsupportedOperationException: Attempt to use unsupported SchemaExport constructor accepting org.hibernate.cfg.Configuration; one of the forms accepting org.hibernate.boot.spi.MetadataImplementor should be used instead at org.hibernate.tool.hbm2ddl.SchemaExport.(SchemaExport.java:250) at cu.x.util.SchemaGenerator.generate(SchemaGenerator.java:116) at cu.x.util.SchemaGenerator.main(SchemaGenerator.java:32) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:497) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
I change my code with the following:
ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(cfg.getProperties()).build();
MetadataImplementor metadataImplementor = (MetadataImplementor)
new MetadataSources(serviceRegistry).buildMetadata();
SchemaExport export = new SchemaExport(metadataImplementor);
But it generates an empty .sql file. I'm using annotated classes. What could be happening?
Apparently the Configuration class can not be used. We must use the MetadataSources class to add the annotated classes.
private void generate(Dialect dialect, String directory, String[] packagesName) throws Exception {
MetadataSources metadata = new MetadataSources(
new StandardServiceRegistryBuilder()
.applySetting("hibernate.dialect", dialect.getDialectClass())
.build());
for (String packageName : packagesName) {
log.info("packageName: " + packageName);
for (Class clazz : getClasses(packageName)) {
log.info("Class: " + clazz);
metadata.addAnnotatedClass(clazz);
}
}
SchemaExport export = new SchemaExport(
(MetadataImplementor) metadata.buildMetadata()
);
export.setDelimiter(";");
export.setOutputFile(directory + "ddl_" + dialect.name().toLowerCase() + ".sql");
export.setFormat(true);
export.execute(true, false, false, false);
}
The solution of felix don't work anymore on hibernate 5.2 here is a version which is compatible
private void generate(Class dialect, String directory, String... packagesName) throws Exception {
MetadataSources metadata = new MetadataSources(
new StandardServiceRegistryBuilder()
.applySetting("hibernate.dialect", dialect.getName())
.build());
for (String packageName : packagesName) {
LOG.info("packageName: " + packageName);
for (Class clazz : getClasses(packageName)) {
LOG.info("Class: " + clazz);
metadata.addAnnotatedClass(clazz);
}
}
MetadataImplementor metadataImplementor = (MetadataImplementor) metadata.buildMetadata();
SchemaExport export = new SchemaExport();
export.setDelimiter(";");
String filename = directory + "ddl_" + dialect.getSimpleName().toLowerCase() + ".sql";
export.setOutputFile(filename);
export.setFormat(true);
//can change the output here
EnumSet<TargetType> enumSet = EnumSet.of(TargetType.STDOUT);
export.execute(enumSet, SchemaExport.Action.CREATE, metadataImplementor);
}
Normally tools that dumps the JPA schema are based on SchemaExport tool, which reads only the static metadata.
There is a Maven/Gradle plugin https://github.com/Devskiller/jpa2ddl which generates the JPA schema. In includes all properties, namings strategies, user types, etc.
You can also use it to generate automated schema migrations for Flyway.
I wrote a class for generating sql script depends on packages with entites.
Used version of hibernate is '5.3.7.Final'
public final class HibernateExporter {
private static final Logger LOG = LoggerFactory.getLogger(HibernateExporter.class);
private static final String OUTPUT_FILE = "schema.sql";
private static final String DIALECT = "org.hibernate.dialect.H2Dialect";
private List<String> entityPackages;
private HibernateExporter(List<String> entityPackages) {
this.entityPackages = entityPackages;
}
public static void main(String[] args) {
final List<String> entityPackages = Collections.singletonList("pakage.with.entites");
HibernateExporter exporter = new HibernateExporter(entityPackages);
exporter.export();
}
private void export() {
SchemaExport export = new SchemaExport();
export.setOutputFile(OUTPUT_FILE);
export.setFormat(true);
export.setDelimiter(";");
EnumSet<TargetType> types = EnumSet.of(TargetType.SCRIPT);
Metadata metadata = createMetadataSources().buildMetadata();
export.execute(types, Action.CREATE, metadata);
}
private MetadataSources createMetadataSources() {
MetadataSources metadata = new MetadataSources(
new StandardServiceRegistryBuilder()
.applySetting("hibernate.dialect", DIALECT)
.build());
for (String entityPackage : entityPackages) {
final Reflections reflections = new Reflections(entityPackage);
for (Class<?> cl : reflections.getTypesAnnotatedWith(MappedSuperclass.class)) {
metadata.addAnnotatedClass(cl);
LOG.info(String.format("Mapped = %s", cl.getName()));
}
for (Class<?> cl : reflections.getTypesAnnotatedWith(Entity.class)) {
metadata.addAnnotatedClass(cl);
LOG.info(String.format("Mapped = %s", cl.getName()));
}
}
return metadata;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With