0

The goal is for a Java app to access a list of all the resources contained in one of its packages, at run time. The use case: files containing properties in plain text in a package, that need to be accessed by the app to do its thing.

An answer (https://stackoverflow.com/a/67092012/798502) indicates that annotations could be the way to go. The app should be able to create at compile time a text file listing the names of the contents of a given package, using annotation processors. At run time, the app would access this list of names and would hence be able to walk through and access this content. I have browsed about this approach but could not find a way, this is why I don't provide a code sample here.

seinecle
  • 10,118
  • 14
  • 61
  • 120

1 Answers1

1

There are two utterly unrelated parts to this task:

  1. The compile-time aspect: How to create and maintain the text file(s) that list the resources.

  2. The run-time aspect: How to read these files.

Annotation Processors are just one way to solve the first problem. The simple way is to just write these text files yourself. This works fine and is simple. The only downside is the extra work: If you make a new resource you have to remember to also put it in the text file, or it isn't picked up by your system as existing at all.

When we're speaking about classes as resources (for example, you have an abstract class named Shield and a whole bunch of classes that represent shields with various unique properties, and you add another fun shield for a new release of your game), then that class comes from source code, and then an annotation processor can be used to generate and maintain the text file listing the shield classes automatically.

If we're not talking about classes, annotation processors do not make any sense whatsoever here.

Even if we are talking classes, it's just a convenience. You can also manually write these files. Annotation Processors simply give you a way to have your codebase have the following property: You just.. make a new class InvulnerabilityGrantingShield extends Shield, annotate it with e.g. @Provides(Shield.class), and then the text file listing all shield classes just happens, automatically. That's all it would do. Convenience. Nothing more.

If we're talking non-classes, you could consider build system plugins that do the equivalent of:

ls src/main/resources/icons/*.png > build/icons/list_of_all_icons.txt

as part of the build. You'll have to look up the docs of your build system if it can do that; I gather that most cannot.

At run-time

At run-time, all you need to do if the resources are classes, is to use the baked-into-java ServiceLoader.

If they aren't classes, you'd have to write this yourself. This has nothing whatsoever to do with annotation processors - that is JUST for making the text files, not for reading them.

Doing so is fairly easy:

ClassLoader loader = MyClass.class.getClassLoader();
Enumeration<URL> resources = loader.getResources("icons/all_icons.txt");
while (resources.hasMoreElements()) {
    URL url = resource.nextElement();
    try (InputStream in = url.openStream()) {
        for (String line : new String(in.readAllBytes(), StandardCharsets.UTF_8).split("\\R")) {

            line = line.trim();
            if (line.isEmpty() || line.startsWith("#")) continue;
            URL res = loader.getResource(line);
            loadTheResource_WriteThisYourself(res);
        }
    }
}
rzwitserloot
  • 85,357
  • 5
  • 51
  • 72