2

下面的方法应该从某个目录中读取类/文件。在eclipse中调试方法时它工作正常。但是在使用 ant 构建它之后,scannedDir 不再是一个目录。有谁知道如何更改它以使其在部署后仍然有效?提前致谢!

private static List<Class<?>> find(String scannedPackage) {

    logger.trace("Scanned package='{}'", scannedPackage);
    String scannedPath = scannedPackage.replace(DOT, SLASH);
    logger.trace("Scanned path='{}'", scannedPath);
    URL scannedUrl = Thread.currentThread().getContextClassLoader().getResource(scannedPath);
    logger.trace("Scanned url='{}'", scannedUrl);

    if (scannedUrl == null) {
        throw new IllegalArgumentException(String.format(BAD_PACKAGE_ERROR, scannedPath, scannedPackage));
    }

    File scannedDir = new File(scannedUrl.getFile());
    logger.trace("scannedDir.isDirecory='{}'", scannedDir.isDirectory());
    List<Class<?>> classes = new ArrayList<Class<?>>();

    for (File file : scannedDir.listFiles()) {
        logger.trace("currentFile='{}'", file.getAbsolutePath());
        classes.addAll(find(file, scannedPackage));
    }

    return classes;
}

如此详细:当我使用 eclipse debug mode 运行它时scannedDir.isDirectory=true。但是建好之后scannedDir.isDirectory=false

干杯!

编辑:

scannedDir.getAbsolutePath()返回jar:file:/C:/Users/xxx.xxx/AppData/Local/XBRLGEN/app/xbrl_s2.jar!/eu/europa/eiopa/xbrl/s2c/dict/dom

4

1 回答 1

0

您不能像Files 那样对待 jar 文件中的条目,这将永远无法工作。你也误解了这个问题。仅仅因为File它不是一个目录并不意味着它是一个普通文件,它根本不存在,因为您提取了jar:URL 的一部分并将其解释为普通文件。

这是您处理不需要普通文件的抽象的任务的解决方案:

private static Set<Class<?>> getClasses(String pkg)
  throws IOException, URISyntaxException {
    ClassLoader cll = Thread.currentThread().getContextClassLoader();

    URI clURI = cll.getResource(pkg.replace('.', '/')).toURI();
    if(!clURI.getScheme().equals("file")) try {
        FileSystems.getFileSystem(clURI);
    } catch(FileSystemNotFoundException ex) {
        FileSystems.newFileSystem(clURI, Collections.emptyMap());
    }
    return Files.list(Paths.get(clURI))
        .map(p->p.getFileName().toString())
        .filter(s->s.endsWith(".class"))
        .map(s->s.substring(0, s.length()-6))
        .map(s-> { try {
            return cll.loadClass(pkg+'.'+s);
          } catch(ClassNotFoundException ex) { return null; } })
        .filter(Objects::nonNull)
        .collect(Collectors.toSet());
}

但它是不可靠的,因为jar文件根本不需要目录条目。在不存在条目的情况下,目录的存在仅暗示存在该目录中的常规文件的条目这一事实,例如,条目foo/bar暗示存在目录foo。在这种情况下,getResource对该目录的尝试将失败。

查询包的最安全方法是在该包中选择一个类并对其执行查找,因为相关资源肯定存在。然后你可以遍历它的父级,即使它的存在只是暗示:

private static Set<Class<?>> getClasses(Class<?> context)
    throws IOException, URISyntaxException {

    ClassLoader cll = context.getClassLoader();

    URI clURI = context.getResource(context.getSimpleName()+".class").toURI();
    if(!clURI.getScheme().equals("file")) try {
        FileSystems.getFileSystem(clURI);
    } catch(FileSystemNotFoundException ex) {
        FileSystems.newFileSystem(clURI, Collections.emptyMap());
    }
    String pkg=context.getPackage().getName();
    return Files.list(Paths.get(clURI).getParent())
        .map(p->p.getFileName().toString())
        .filter(s->s.endsWith(".class"))
        .map(s->s.substring(0, s.length()-6))
        .map(s-> { try {
            return Class.forName(pkg+'.'+s, false, cll);
          } catch(ClassNotFoundException ex) { return null; } })
        .filter(Objects::nonNull)
        .collect(Collectors.toSet());
}
于 2015-03-27T13:03:34.107 回答