Testing your Hibernate Annotation Mapping

To test if I my mappings are correct, I use the following Java Application which uses SchemaExport. It gives me the SQL-statements and executes them against a database.
To protect the production database, you can either set the second parameter of create() to false and/or change the connection string to a test database.
configuration.setProperty(Environment.URL, "jdbc:mysql://localhost/test");

package starter;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.cfg.Environment;
import org.hibernate.tool.hbm2ddl.SchemaExport;

public class SchemaTester {
    
    public static void main(String[] args) throws ClassNotFoundException {
        AnnotationConfiguration configuration = new AnnotationConfiguration();
        
        List<Class> classes = findClasses(new File("src/domain"), "domain");
        for (Class clazz : classes) {
            configuration.addAnnotatedClass(clazz);
        }
        
        configuration.configure();
        configuration.setProperty(Environment.URL, "jdbc:mysql://localhost/test");
        
        SchemaExport schemaExport = new SchemaExport(configuration);
        schemaExport.create(true, true);        
        // schemaExport.execute(true, false, false, true); // to see just create statements
    }
    
    private static List<Class> findClasses(File directory, String packageName) 
                                                                throws ClassNotFoundException  {
        List<Class> classes = new ArrayList<Class>();
        if (!directory.exists()) {
            return classes;
        }
        File[] files = directory.listFiles();
        for (File file : files) {
            System.out.println(file);
            if (file.isDirectory()) {
                if(!file.getName().contains(".")) {
                    classes.addAll(findClasses(file, packageName + "." + file.getName()));                    
                }
            } else if (file.getName().endsWith(".java")) {
                String javaName = file.getName().substring(0, file.getName().length() - ".java".length());
                classes.add(Class.forName(packageName + '.' + javaName));
            }
        }
        return classes;
    }
}

Resources

Advertisements

@Transactional not always works on methods

Although I had annoted my method as @Transactional no transaction was started. Situation was the following:

applicationContext.xml

...
<!-- Enable @Transactional support -->
<tx:annotation-driven transaction-manager="transactionManager" />
...

Test.java

class Test {
    public static void main(String args[]) throws Exception {
        ...
        Test test = factory.getBean("test");
        test.run();
    }

    public void run() {
        // code before transaction
        runTransactional();
        // code after transaction
    }

    @Transactional
    public void runTransactional() {
        // code in transaction
    }
}

I found the reason in a little hint in the Spring Documenation (Using @Transactional):

Note: In proxy mode (which is the default), only ‘external’ method calls coming in through the proxy will be intercepted. This means that ‘self-invocation’, i.e. a method within the target object calling some other method of the target object, won’t lead to an actual transaction at runtime even if the invoked method is marked with @Transactional!

So the solution is either to use aspectj instead of proxy-mode or to make an ‘external’ method call. I used the second. So I head to move the code from run() to main() so that I have an ‘external’ method call to runTransactional().

Test.java

class Test {
    public static void main(String args[]) throws Exception {
        ...
        Test test = factory.getBean("test");
        // code before transaction
        test.runTransactional();
        // code after transaction
    }

    @Transactional
    public void runTransactional() {
        // code in transaction
    }
}