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();
}
}