When using the JobOperator from the Java EE 7 API, I noticed that it returns only the jobs which were already previously started. At least on jBeret, the Batch implementation used in Wildfly. A different approach was needed to get a list of all available batch jobs.

The previous solution, in my case, was to use the Reflections library, as all of the jobs were started from a unique class hierarchy. But since this was the only place I was using the Reflections library, and it was bringing about 2MB of dependencies, I decided to get rid of it. The next obvious solution is to go directly to the source of information, the same place used by the JobOperator: META-INF/batch-jobs.

To get a list of files from this directory in an exploded deployment is quite easy, as the files are available on the real file system, so, a simple lookup for a resource would return the URL to it, which can be converted into an URI and read via File. But to get those from inside the WAR file was tricky, as those are not real files, and the path to it is not a real path.

The solution that works in the latest Wildfly is:

private List<String> getFileNamesFromBatchJobs() {
    List<String> fileNames = new ArrayList<>();
    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    InputStream directoryIs = classLoader.getResourceAsStream("/META-INF/batch-jobs");

    if (directoryIs instanceof JarInputStream) {
        try {
            JarInputStream jis = (JarInputStream) directoryIs;
            JarEntry entry;
            while ((entry = jis.getNextJarEntry()) != null) {
        } catch (IOException ex) {
            throw new RuntimeException(ex);

    return fileNames;

This works because directoryIs is actually a VirtualJarInputStream, which is a subclass of JarInputStream. This way, the code is still free of a dependency on Wildfly, while still able to deal with VFS, which is Wildfly-specific. As my target is indeed to deploy on Wildfly, I don’t need any extra conditions on checking the type of the directoryIs, but it would not be hard to add specific conditions based on the deployment target.