Added patch by Joachim Van der Auwera to support package level annotations
authorKai Moritz <km@juplo.de>
Sat, 25 Oct 2014 15:29:41 +0000 (17:29 +0200)
committerKai Moritz <km@juplo.de>
Sun, 26 Oct 2014 10:21:37 +0000 (11:21 +0100)
pom.xml
src/it/hibernate4-maven-plugin-envers-sample/src/main/resources/spring-persistence-context.xml
src/it/schemaexport-example/schema.sql
src/it/schemaexport-example/schemaexport-example-domain/pom.xml
src/it/schemaexport-example/schemaexport-example-domain/src/main/java/de/test/schemaexport/domain/Department.java
src/it/schemaexport-example/schemaexport-example-domain/src/main/java/de/test/schemaexport/domain/EnumUserType.java [new file with mode: 0644]
src/it/schemaexport-example/schemaexport-example-domain/src/main/java/de/test/schemaexport/domain/Gender.java [new file with mode: 0644]
src/it/schemaexport-example/schemaexport-example-domain/src/main/java/de/test/schemaexport/domain/package-info.java [new file with mode: 0644]
src/it/schemaexport-example/schemaexport-example-persistence-impl/src/main/resources/META-INF/persistence.xml
src/main/java/de/juplo/plugins/hibernate4/Hbm2DdlMojo.java
src/main/java/de/juplo/plugins/hibernate4/ValidationConfiguration.java

diff --git a/pom.xml b/pom.xml
index 6433f6f..272a1ea 100644 (file)
--- a/pom.xml
+++ b/pom.xml
       <name>Claus Graf</name>
       <email>clausgraf@gmail.com</email>
     </contributor>
+    <contributor>
+      <name>Joachim Van der Auwera</name>
+      <email>joachim@progs.be</email>
+    </contributor>
   </contributors>
 
   <distributionManagement>
index 78f8111..0cff8cc 100644 (file)
@@ -24,6 +24,7 @@
           p:persistenceUnitName="${jpa.persistence.context.name}"
           p:persistenceXmlLocation="classpath:META-INF/persistence-jpa.xml"
           p:dataSource-ref="dataSource"
+          p:packagesToScan="de.test.schemaexport.domain"
             >
 
         <property name="jpaVendorAdapter">
index e8f93ba..bd7142c 100644 (file)
@@ -8,6 +8,7 @@
 
     create table ABTEILUNG (
         OID bigint generated by default as identity (start with 1),
+        gender varchar(255),
         name varchar(255) not null,
         primary key (OID)
     );
index c2bc2d8..43b71b3 100644 (file)
                        <artifactId>hibernate-validator</artifactId>\r
                        <scope>provided</scope>\r
                </dependency>\r
+               <dependency>\r
+                       <groupId>org.hibernate</groupId>\r
+                       <artifactId>hibernate-core</artifactId>\r
+               </dependency>\r
        </dependencies>\r
        \r
 </project>\r
index b523659..64ff133 100644 (file)
@@ -6,6 +6,7 @@ import javax.persistence.GeneratedValue;
 import javax.persistence.GenerationType;\r
 import javax.persistence.Id;\r
 import javax.persistence.Table;\r
+import org.hibernate.annotations.Type;\r
 \r
 /**\r
  * Abteilungsklasse (Generator-Beispielcode).\r
@@ -25,6 +26,9 @@ public class Department {
        @Column(name = "name", nullable = false)\r
        private String name;\r
 \r
+       @Type(type = "genderType")\r
+       private Gender gender;\r
+\r
        public long getOid() {\r
                return oid;\r
        }\r
diff --git a/src/it/schemaexport-example/schemaexport-example-domain/src/main/java/de/test/schemaexport/domain/EnumUserType.java b/src/it/schemaexport-example/schemaexport-example-domain/src/main/java/de/test/schemaexport/domain/EnumUserType.java
new file mode 100644 (file)
index 0000000..6e59890
--- /dev/null
@@ -0,0 +1,110 @@
+package de.test.schemaexport.domain;
+
+import org.hibernate.HibernateException;
+import org.hibernate.engine.spi.SessionImplementor;
+import org.hibernate.usertype.EnhancedUserType;
+import org.hibernate.usertype.ParameterizedType;
+
+import java.io.Serializable;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.Properties;
+
+/**
+ * This Hibernate UserType is used to map JDK 5 Enums directly in a column.
+ * Define this UserType in your hbm.xml mapping file like the following example:
+ */
+public class EnumUserType implements EnhancedUserType, ParameterizedType {
+
+    private Class<Enum> enumClass;
+
+    @Override
+    public void setParameterValues(Properties parameters) {
+        String enumClassName = parameters.getProperty("enumClassName");
+        try {
+            enumClass = (Class<Enum>) Class.forName(enumClassName);
+        } catch (ClassNotFoundException cnfe) {
+            throw new HibernateException("Enum class not found", cnfe);
+        }
+    }
+
+    @Override
+    public Object assemble(Serializable cached, Object owner) throws HibernateException {
+        return cached;
+    }
+
+    @Override
+    public Object deepCopy(Object value) throws HibernateException {
+        return value;
+    }
+
+    @Override
+    public Serializable disassemble(Object value) throws HibernateException {
+        return (Enum) value;
+    }
+
+    @Override
+    public boolean equals(Object x, Object y) throws HibernateException {
+        return x == y;
+    }
+
+    @Override
+    public int hashCode(Object x) throws HibernateException {
+        return x.hashCode();
+    }
+
+    @Override
+    public boolean isMutable() {
+        return false;
+    }
+
+    @Override
+    public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor sessionImplementor, Object owner)
+            throws HibernateException, SQLException {
+        String name = rs.getString(names[0]);
+        return rs.wasNull() ? null : Enum.valueOf(enumClass, name);
+    }
+
+    @Override
+    public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor sessionImplementor)
+            throws HibernateException, SQLException {
+        if (value == null) {
+            st.setNull(index, Types.VARCHAR);
+        } else {
+            st.setString(index, ((Enum) value).name());
+        }
+    }
+
+    @Override
+    public Object replace(Object original, Object target, Object owner) throws HibernateException {
+        return original;
+    }
+
+    @Override
+    public Class returnedClass() {
+        return enumClass;
+    }
+
+    @Override
+    public int[] sqlTypes() {
+        return new int[]{Types.VARCHAR};
+    }
+
+    @Override
+    public Object fromXMLString(String xmlValue) {
+        return Enum.valueOf(enumClass, xmlValue);
+    }
+
+    @Override
+    public String objectToSQLString(Object value) {
+        return '\'' + ((Enum) value).name() + '\'';
+    }
+
+    @Override
+    public String toXMLString(Object value) {
+        return ((Enum) value).name();
+    }
+
+}
diff --git a/src/it/schemaexport-example/schemaexport-example-domain/src/main/java/de/test/schemaexport/domain/Gender.java b/src/it/schemaexport-example/schemaexport-example-domain/src/main/java/de/test/schemaexport/domain/Gender.java
new file mode 100644 (file)
index 0000000..dca1d00
--- /dev/null
@@ -0,0 +1,23 @@
+package de.test.schemaexport.domain;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+/**
+ * Abteilungsklasse (Generator-Beispielcode).
+ * 
+ * copyright
+ *
+ */
+public enum Gender {
+
+       MALE,
+    FEMALE,
+    UNKNOWN,
+    OTHER
+       
+}
diff --git a/src/it/schemaexport-example/schemaexport-example-domain/src/main/java/de/test/schemaexport/domain/package-info.java b/src/it/schemaexport-example/schemaexport-example-domain/src/main/java/de/test/schemaexport/domain/package-info.java
new file mode 100644 (file)
index 0000000..d1491c6
--- /dev/null
@@ -0,0 +1,13 @@
+@TypeDefs({
+        @TypeDef(name = "genderType",
+                defaultForType = Gender.class,
+                typeClass = EnumUserType.class,
+                parameters = @Parameter(name = "enumClassName",
+                        value = "de.test.schemaexport.domain.Gender"))
+})
+package de.test.schemaexport.domain;
+
+import de.test.schemaexport.domain.EnumUserType;
+import org.hibernate.annotations.Parameter;
+import org.hibernate.annotations.TypeDef;
+import org.hibernate.annotations.TypeDefs;
\ No newline at end of file
index 7578472..0eaf2d3 100644 (file)
@@ -3,6 +3,7 @@
        xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">\r
        <persistence-unit name="swmtestappManagerTest">\r
                <!-- in practice configured via Spring LocalContainerEntityManagerFactoryBean - packagesToScan -->\r
+               <class>de.test.schemaexport.domain</class>\r
                <class>de.test.schemaexport.domain.Department</class>\r
                <class>de.test.schemaexport.domain.Employee</class>\r
                <properties>\r
index f73fa2b..73f0ab0 100644 (file)
@@ -58,7 +58,6 @@ import org.apache.maven.plugin.AbstractMojo;
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugin.MojoFailureException;
 import org.apache.maven.project.MavenProject;
-import org.hibernate.cfg.Configuration;
 import org.hibernate.cfg.NamingStrategy;
 import org.hibernate.envers.configuration.spi.AuditConfiguration;
 import org.hibernate.tool.hbm2ddl.SchemaExport;
@@ -670,7 +669,7 @@ public class Hbm2DdlMojo extends AbstractMojo
       throw new MojoFailureException("Hibernate configuration is missing!");
     }
 
-    final Configuration config = new ValidationConfiguration(hibernateDialect);
+    final ValidationConfiguration config = new ValidationConfiguration(hibernateDialect);
 
     config.setProperties(properties);
 
@@ -691,181 +690,191 @@ public class Hbm2DdlMojo extends AbstractMojo
       }
     }
 
-    getLog().debug("Adding annotated classes to hibernate-mapping-configuration...");
-    for (Class<?> annotatedClass : classes)
+    ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
+    Connection connection = null;
+    MavenLogAppender.startPluginLog(this);
+    try
     {
-      getLog().debug("Class " + annotatedClass);
-      config.addAnnotatedClass(annotatedClass);
-    }
+      /**
+       * Change class-loader of current thread, so that hibernate can
+       * see all dependencies!
+       */
+      Thread.currentThread().setContextClassLoader(classLoader);
 
-    if (hibernateMapping != null)
-    {
-      try
+      getLog().debug("Adding annotated classes to hibernate-mapping-configuration...");
+      // build annotated packages
+      Set<String> packages = new HashSet<String>();
+      for (Class<?> annotatedClass : classes)
       {
-        MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
-        for (String filename : hibernateMapping.split("[\\s,]+"))
+        String packageName = annotatedClass.getPackage().getName();
+        if (!packages.contains(packageName))
         {
-          // First try the filename as absolute/relative path
-          File file = new File(filename);
-          if (!file.exists())
+          getLog().debug("Add package " + packageName);
+          packages.add(packageName);
+          config.addPackage(packageName);
+          getLog().debug("type definintions" + config.getTypeDefs());
+        }
+        getLog().debug("Class " + annotatedClass);
+        config.addAnnotatedClass(annotatedClass);
+      }
+
+      if (hibernateMapping != null)
+      {
+        try
+        {
+          MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
+          for (String filename : hibernateMapping.split("[\\s,]+"))
           {
-            // If the file was not found, search for it in the resource-directories
-            for (Resource resource : project.getResources())
+            // First try the filename as absolute/relative path
+            File file = new File(filename);
+            if (!file.exists())
             {
-              file = new File(resource.getDirectory() + File.separator + filename);
-              if (file.exists())
-                break;
+              // If the file was not found, search for it in the resource-directories
+              for (Resource resource : project.getResources())
+              {
+                file = new File(resource.getDirectory() + File.separator + filename);
+                if (file.exists())
+                  break;
+              }
             }
-          }
-          if (file != null && file.exists())
-          {
-            InputStream is = new FileInputStream(file);
-            byte[] buffer = new byte[1024*4]; // copy data in 4MB-chunks
-            int i;
-            while((i = is.read(buffer)) > -1)
-              digest.update(buffer, 0, i);
-            is.close();
-            byte[] bytes = digest.digest();
-            BigInteger bi = new BigInteger(1, bytes);
-            String newMd5 = String.format("%0" + (bytes.length << 1) + "x", bi);
-            String oldMd5 = !md5s.containsKey(filename) ? "" : md5s.get(filename);
-            if (!newMd5.equals(oldMd5))
+            if (file != null && file.exists())
             {
-              getLog().debug("Found new or modified mapping-file: " + filename);
-              modified = true;
-              md5s.put(filename, newMd5);
+              InputStream is = new FileInputStream(file);
+              byte[] buffer = new byte[1024*4]; // copy data in 4MB-chunks
+              int i;
+              while((i = is.read(buffer)) > -1)
+                digest.update(buffer, 0, i);
+              is.close();
+              byte[] bytes = digest.digest();
+              BigInteger bi = new BigInteger(1, bytes);
+              String newMd5 = String.format("%0" + (bytes.length << 1) + "x", bi);
+              String oldMd5 = !md5s.containsKey(filename) ? "" : md5s.get(filename);
+              if (!newMd5.equals(oldMd5))
+              {
+                getLog().debug("Found new or modified mapping-file: " + filename);
+                modified = true;
+                md5s.put(filename, newMd5);
+              }
+              else
+              {
+                getLog().debug(oldMd5 + " -> mapping-file unchanged: " + filename);
+              }
+              getLog().debug("Adding mappings from XML-configurationfile: " + file);
+              config.addFile(file);
             }
             else
-            {
-              getLog().debug(oldMd5 + " -> mapping-file unchanged: " + filename);
-            }
-            getLog().debug("Adding mappings from XML-configurationfile: " + file);
-            config.addFile(file);
+              throw new MojoFailureException("File " + filename + " could not be found in any of the configured resource-directories!");
           }
-          else
-            throw new MojoFailureException("File " + filename + " could not be found in any of the configured resource-directories!");
+        }
+        catch (NoSuchAlgorithmException e)
+        {
+          throw new MojoFailureException("Cannot calculate MD5 sums!", e);
+        }
+        catch (FileNotFoundException e)
+        {
+          throw new MojoFailureException("Cannot calculate MD5 sums!", e);
+        }
+        catch (IOException e)
+        {
+          throw new MojoFailureException("Cannot calculate MD5 sums!", e);
         }
       }
-      catch (NoSuchAlgorithmException e)
+
+      Target target = null;
+      try
       {
-        throw new MojoFailureException("Cannot calculate MD5 sums!", e);
+        target = Target.valueOf(this.target.toUpperCase());
       }
-      catch (FileNotFoundException e)
+      catch (IllegalArgumentException e)
       {
-        throw new MojoFailureException("Cannot calculate MD5 sums!", e);
+        getLog().error("Invalid value for configuration-option \"target\": " + this.target);
+        getLog().error("Valid values are: NONE, SCRIPT, EXPORT, BOTH");
+        throw new MojoExecutionException("Invalid value for configuration-option \"target\"");
       }
-      catch (IOException e)
+      Type type = null;
+      try
       {
-        throw new MojoFailureException("Cannot calculate MD5 sums!", e);
+        type = Type.valueOf(this.type.toUpperCase());
+      }
+      catch (IllegalArgumentException e)
+      {
+        getLog().error("Invalid value for configuration-option \"type\": " + this.type);
+        getLog().error("Valid values are: NONE, CREATE, DROP, BOTH");
+        throw new MojoExecutionException("Invalid value for configuration-option \"type\"");
       }
-    }
-
-    Target target = null;
-    try
-    {
-      target = Target.valueOf(this.target.toUpperCase());
-    }
-    catch (IllegalArgumentException e)
-    {
-      getLog().error("Invalid value for configuration-option \"target\": " + this.target);
-      getLog().error("Valid values are: NONE, SCRIPT, EXPORT, BOTH");
-      throw new MojoExecutionException("Invalid value for configuration-option \"target\"");
-    }
-    Type type = null;
-    try
-    {
-      type = Type.valueOf(this.type.toUpperCase());
-    }
-    catch (IllegalArgumentException e)
-    {
-      getLog().error("Invalid value for configuration-option \"type\": " + this.type);
-      getLog().error("Valid values are: NONE, CREATE, DROP, BOTH");
-      throw new MojoExecutionException("Invalid value for configuration-option \"type\"");
-    }
 
-    if (target.equals(Target.SCRIPT) || target.equals(Target.NONE))
-    {
-      project.getProperties().setProperty(EXPORT_SKIPPED_PROPERTY, "true");
-    }
-    if (
-        !modified
-        && !target.equals(Target.SCRIPT)
-        && !target.equals(Target.NONE)
-        && !force
-      )
-    {
-      getLog().info("No modified annotated classes or mapping-files found and dialect unchanged.");
-      getLog().info("Skipping schema generation!");
-      project.getProperties().setProperty(EXPORT_SKIPPED_PROPERTY, "true");
-      return;
-    }
+      if (target.equals(Target.SCRIPT) || target.equals(Target.NONE))
+      {
+        project.getProperties().setProperty(EXPORT_SKIPPED_PROPERTY, "true");
+      }
+      if (
+          !modified
+          && !target.equals(Target.SCRIPT)
+          && !target.equals(Target.NONE)
+          && !force
+        )
+      {
+        getLog().info("No modified annotated classes or mapping-files found and dialect unchanged.");
+        getLog().info("Skipping schema generation!");
+        project.getProperties().setProperty(EXPORT_SKIPPED_PROPERTY, "true");
+        return;
+      }
 
-    getLog().info("Gathered hibernate-configuration (turn on debugging for details):");
-    for (Entry<Object,Object> entry : properties.entrySet())
-      getLog().info("  " + entry.getKey() + " = " + entry.getValue());
+      getLog().info("Gathered hibernate-configuration (turn on debugging for details):");
+      for (Entry<Object,Object> entry : properties.entrySet())
+        getLog().info("  " + entry.getKey() + " = " + entry.getValue());
 
-    Connection connection = null;
-    try
-    {
-      /**
-       * The connection must be established outside of hibernate, because
-       * hibernate does not use the context-classloader of the current
-       * thread and, hence, would not be able to resolve the driver-class!
-       */
-      getLog().debug("Target: " + target + ", Type: " + type);
-      switch (target)
+      try
       {
-        case EXPORT:
-        case BOTH:
-          switch (type)
-          {
-            case CREATE:
-            case DROP:
-            case BOTH:
-              Class driverClass = classLoader.loadClass(properties.getProperty(DRIVER_CLASS));
-              getLog().debug("Registering JDBC-driver " + driverClass.getName());
-              DriverManager.registerDriver(new DriverProxy((Driver)driverClass.newInstance()));
-              getLog().debug(
-                  "Opening JDBC-connection to "
-                  + properties.getProperty(URL)
-                  + " as "
-                  + properties.getProperty(USERNAME)
-                  + " with password "
-                  + properties.getProperty(PASSWORD)
-                  );
-              connection = DriverManager.getConnection(
-                  properties.getProperty(URL),
-                  properties.getProperty(USERNAME),
-                  properties.getProperty(PASSWORD)
-                  );
-          }
+        /**
+         * The connection must be established outside of hibernate, because
+         * hibernate does not use the context-classloader of the current
+         * thread and, hence, would not be able to resolve the driver-class!
+         */
+        getLog().debug("Target: " + target + ", Type: " + type);
+        switch (target)
+        {
+          case EXPORT:
+          case BOTH:
+            switch (type)
+            {
+              case CREATE:
+              case DROP:
+              case BOTH:
+                Class driverClass = classLoader.loadClass(properties.getProperty(DRIVER_CLASS));
+                getLog().debug("Registering JDBC-driver " + driverClass.getName());
+                DriverManager.registerDriver(new DriverProxy((Driver)driverClass.newInstance()));
+                getLog().debug(
+                    "Opening JDBC-connection to "
+                    + properties.getProperty(URL)
+                    + " as "
+                    + properties.getProperty(USERNAME)
+                    + " with password "
+                    + properties.getProperty(PASSWORD)
+                    );
+                connection = DriverManager.getConnection(
+                    properties.getProperty(URL),
+                    properties.getProperty(USERNAME),
+                    properties.getProperty(PASSWORD)
+                    );
+            }
+        }
+      }
+      catch (ClassNotFoundException e)
+      {
+        getLog().error("Dependency for driver-class " + properties.getProperty(DRIVER_CLASS) + " is missing!");
+        throw new MojoExecutionException(e.getMessage());
+      }
+      catch (Exception e)
+      {
+        getLog().error("Cannot establish connection to database!");
+        Enumeration<Driver> drivers = DriverManager.getDrivers();
+        if (!drivers.hasMoreElements())
+          getLog().error("No drivers registered!");
+        while (drivers.hasMoreElements())
+          getLog().debug("Driver: " + drivers.nextElement());
+        throw new MojoExecutionException(e.getMessage());
       }
-    }
-    catch (ClassNotFoundException e)
-    {
-      getLog().error("Dependency for driver-class " + properties.getProperty(DRIVER_CLASS) + " is missing!");
-      throw new MojoExecutionException(e.getMessage());
-    }
-    catch (Exception e)
-    {
-      getLog().error("Cannot establish connection to database!");
-      Enumeration<Driver> drivers = DriverManager.getDrivers();
-      if (!drivers.hasMoreElements())
-        getLog().error("No drivers registered!");
-      while (drivers.hasMoreElements())
-        getLog().debug("Driver: " + drivers.nextElement());
-      throw new MojoExecutionException(e.getMessage());
-    }
-
-    ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
-    MavenLogAppender.startPluginLog(this);
-    try
-    {
-      /**
-       * Change class-loader of current thread, so that hibernate can
-       * see all dependencies!
-       */
-      Thread.currentThread().setContextClassLoader(classLoader);
 
       config.buildMappings();
 
index 6748ba5..99ff137 100644 (file)
@@ -56,4 +56,9 @@ public class ValidationConfiguration extends Configuration
       throw new RuntimeException(e);
     }
   }
+
+  public String getTypeDefs()
+  {
+    return typeDefs.entrySet().toString();
+  }
 }