Validating queries against model
cjalmeida May 22, 2009 11:54 PMSince there's no Criteria API for JPA, I've created a simple helper class that scans my sources for queries created using EntityManager.createQuery
and prepares them against my entityManager instance. I use that for unit testing - it assures me that no refactoring breakes them.
The entityManager instance is acquired through the documented integration testing way.
Below is the code for the validator:
package com.pf;
import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.StreamTokenizer; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import javax.persistence.EntityManager; public class QueryValidator { private EntityManager entityManager; private List<File> files = new LinkedList<File>(); public static void main(String[] args) throws Exception { QueryValidator qv = new QueryValidator(new String[] {"src/action", "src/model"}); qv.run(); } public QueryValidator() { } public QueryValidator(String[] srcs) { for (String src : srcs) { File srcdir = new File(src); findRecursive(srcdir,files); } } private void findRecursive(File dir, List<File> col) { for (File child : dir.listFiles()) { if (!child.isDirectory() && child.getName().endsWith(".java")){ col.add(child); System.out.println(child.getAbsolutePath()); }else if (child.isDirectory()) findRecursive(child, col); } } public void run() throws Exception { Map<String, File> queries = new HashMap<String, File>(); for (File file : files){ for(String q : findQueries(file)) queries.put(q, file); } for(String query : queries.keySet()) { try { entityManager.createQuery(query); } catch (Exception e) { throw new Exception("Error on file '" + queries.get(query) + "' for query: " + query,e); } } } private List<String> findQueries(File file) throws Exception { StreamTokenizer tokenizer = new StreamTokenizer(new FileReader(file)); tokenizer.slashSlashComments(true); tokenizer.slashStarComments(true); int ttype; String queryMethod="createQuery"; boolean queryFound = false; StringBuffer queryBuf = null; List<String> queries = new LinkedList<String>(); while((ttype = tokenizer.nextToken()) != StreamTokenizer.TT_EOF) { // We found a method if(tokenizer.ttype == -3 && tokenizer.sval.contains(queryMethod)) { queryFound = true; queryBuf = new StringBuffer(); // Query part } else if (queryFound && tokenizer.ttype == 34) { queryBuf.append(tokenizer.sval); // Method closed - we found a ")" } else if (queryFound && tokenizer.ttype == 41) { String q = queryBuf.toString(); if (!q.trim().equals("")) queries.add(q); queryFound=false; } } return queries; } private String read(File f) throws Exception { BufferedReader reader = new BufferedReader(new FileReader(f)); String line; StringBuffer buff = new StringBuffer(); while ((line = reader.readLine()) != null) buff.append(line); return buff.toString(); } public EntityManager getEntityManager() { return entityManager; } public void setEntityManager(EntityManager entityManager) { this.entityManager = entityManager; } public List<File> getFiles() { return files; } public void setFiles(List<File> files) { this.files = files; } }
and that's the a sample usage in a SeamTest class:
import javax.persistence.EntityManager; import org.jboss.seam.mock.SeamTest; import org.testng.annotations.Test; public class QueryValidationTest extends SeamTest{ @Test public void testQueries() throws Exception { new ComponentTest() { @Override protected void testComponents() throws Exception { QueryValidator qv = new QueryValidator(new String[] {"src/action", "src/model"}); qv.setEntityManager((EntityManager) getValue("#{entityManager}")); qv.run(); } }.run(); } }