如果是Hibernate,反向生成数据库大家肯定会想到hbm2ddl,但是ORMLite呢?ORMLite虽然提供了按照对象来反向生成表的方法,但还不够。因为我希望.新增一个表,不要额外单独写创建表、删除表的操作。
因此想到了Spring的packagesToScan,不过暂未深究Spring,只好找了个现成的类。实现非子目录的扫描:
import java.io.File; import java.io.IOException; import java.lang.annotation.Annotation; import java.net.URL; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; public class ReflectionUtil { private ReflectionUtil() {} public static List<Class<? extends Annotation>> getClassesWithAnnotation(String packageName, Class<? extends Annotation> annotationType) throws ClassNotFoundException, IOException{ List<Class<? extends Annotation>> annotatedClassList = new ArrayList<Class<? extends Annotation>>(); for(Class type: getClasses(packageName)){ if(type.getAnnotation(annotationType) != null){ annotatedClassList.add(type); } } return annotatedClassList; } /** * Scans all classes accessible from the context class loader which belong * to the given package and subpackages. * * @param packageName * The base package * @return The classes * @throws ClassNotFoundException * @throws IOException */ public static List<Class<?>> getClasses(String packageName) throws ClassNotFoundException, IOException { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); String path = packageName.replace('.', '/'); Enumeration<URL> resources = classLoader.getResources(path); List<File> dirs = new ArrayList<File>(); while (resources.hasMoreElements()) { URL resource = resources.nextElement(); dirs.add(new File(resource.getFile())); } List<Class<?>> classes = new ArrayList<Class<?>>(); for (File directory : dirs) { classes.addAll(findClasses(directory, packageName)); } return classes; } /** * Recursive method used to find all classes in a given directory and * subdirs. * * @param directory * The base directory * @param packageName * The package name for classes found inside the base directory * @return The classes * @throws ClassNotFoundException */ 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) { if (file.isDirectory()) { classes.addAll(findClasses(file, packageName + "." + file.getName())); } else if (file.getName().endsWith(".class")) { classes.add(Class.forName(packageName + '.' + file.getName().substring(0, file.getName().length() - 6))); } } return classes; } }
for(Class<? extends Annotation> type: ReflectionUtil.getClassesWithAnnotation("org.我的包.com", DatabaseTable.class)){ TableUtils.dropTable(connectionSource, type, true); TableUtils.createTable(connectionSource, type); }
<bean id="connectionSource" class="com.j256.ormlite.jdbc.DataSourceConnectionSource" init-method="initialize"> <property name="dataSource" ref="dataSource" /> <property name="databaseUrl" value="${dataSource.driverUrl}" /> </bean>
不知道如何采用spring package-scan机制完成,看看spring源码理论上应该是可行的。暂未深究,在此就算抛砖引玉了。
/* -------------------- 2016年的分割线 -------------------------- */
之前看过包扫描的代码,自己居然给忘了,这记性……
用包扫描来代替ReflectionUtil,写起来其实非常简单:
for(Class<? extends Annotation> type: ReflectionUtil.getClassesWithAnnotation("org.我的包.com", DatabaseTable.class)){
可以直接换成:
for(Class<? extends Annotation> type: scanOrmLiteClasses("classpath:org/我的包/com/*/xxxx/*.class")){
还支持部分路径匹配,方便极了。scanOrmLiteClasses的代码如下:
@SuppressWarnings({ "unchecked", "rawtypes" }) private List<Class<? extends Annotation>> scanOrmLiteClasses(String pattern) throws URISyntaxException, IOException, ClassNotFoundException{ List<Class<? extends Annotation>> annotatedClassList = new ArrayList<Class<? extends Annotation>>(); int pathLen = Thread.currentThread().getContextClassLoader().getResource(".").toURI().toString().length(); ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); for(Resource resources: resolver.getResources(pattern)){ String uriStr = resources.getURI().toString(); Class scanClass = Class.forName(uriStr.substring(pathLen, uriStr.length() - 6).replaceAll("/", ".")); if(scanClass.getAnnotation(DatabaseTable.class) != null){ annotatedClassList.add(scanClass); } } return annotatedClassList; }