Java reflecting subclasses - java

I have a class in Java, I wish to reflect all subclasses of this class, how would I do this?
In this specific case, all subclasses are in the same package, and only subclasses are in this package, so an equivalent solution is to fetch all classes in a package.

I think you could do this using spring's org.springframework.core.io.support.PathMatchingResourcePatternResolver. At least I know you can use it to find all classes with a certain annotation. Finding subclasses seems to be a very similar problem I'd expect to work as well.
Here's some (untested) code to get you started:
PathMatchingResourcePatternResolver match = new PathMatchingResourcePatternResolver();
MetadataReaderFactory f = new SimpleMetadataReaderFactory();
List<Class<?>> matches = ...;
for (Resource r : match.getResources("classpath*:com/example/**/*.class")) {
AnnotationMetadata meta = f.getMetadataReader(r).getAnnotationMetadata();
if (meta.getAnnotationsTypes().contains(MyAnnotation.class.getName()) {
matches.add(Class.forName(meta.getClassName()));
}
}
return matches;
As you might see, it's basically the idea describe by Stephen C

See this answer how to locate all classes in a package.
Next, you'll need a list of all packages which isn't trivial in the general case. But if you only use the standard classloader (which solely relies on the classpath), you can get the system property java.class.path and analyze that to get all JARs. Open them to list the content and then you'll know the class names.

It is possible to do (messily) in some cases; e.g. if your application's classes are loaded from local directories or JAR files. Basically, you need to map the package name to a pathname and use the File and/or ZipFile APIs to look for files in the relevant "directory" whose name ends with ".class". Then you use Class.forName() load the corresponding classes (trying to avoid initializing them), and use clazz.isAssignableFrom(subclazz) to see which of them are subclasses.
But this won't work in all cases. One problem is that the ClassLoader API does not support iterating over all of the classes / packages that it could load.
I would recommend that you find an alternative approach to the problem you are tying to address.
EDIT - in response to this comment.
It seems this is a massive fault in the java reflection API
I understand that the omission is deliberate. If the classloader API did include a method to give all classes in a package, it would limit the schemes that can be used for classloading. For example, URLClassLoader would not be implementable for 'http:' URLs because the HTTP protocol does not provide a standard way to retrieve the entries in a directory.
Besides, there are few situations where a production application really needs to reflectively find all classes in a package.

Related

How to write the names of all the content in a package with annotation processors?

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.
There are two utterly unrelated parts to this task:
The compile-time aspect: How to create and maintain the text file(s) that list the resources.
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);
}
}
}

Java: find classes with certain base type on program startup

I have a Java program (an Eclipse plug-in to be specific), which is using several JAR files (which I can control). One of the core JAR files defines an abstract class called Strategy. When the user starts the program, the program needs to know all sub classes of Strategy, that are on the program ClassPath.
As I described in this StackOverflow question, I tried to use static initializer blocks on the sub classes, so that they auto-register themselves in a registry. This approach is not working since the static initalizers are not executed before I explicitly use the class.
Is there any other way to find all classes with a certain base type that are on the current ClassPath?
I can think of the following solutions:
traverse all JARs in a specific directory and check the classes they contain
create a file which is loaded on program start-up and read the class names from that
I can implement both of them myself (so I do not ask for any code samples here). I merely want to know if there is another option I am missing. Any in-class solution (like the one I tried with static initializers) would be greatly appreciated.
If you're open to using a third-party library, Reflections seems to be the best fit here. It's a Java runtime metadata analysis library and is like geared to do this. From their website:
Using Reflections you can query your metadata such as:
get all subtypes of some type
get all types/constructos/methods/fields annotated with some annotation, optionally with annotation parameters matching
get all resources matching matching a regular expression
get all methods with specific signature including parameters, parameter annotations and return type
All you need is to create a configured instance of Reflections in your StrategyRegistrar class as
Reflections reflections = new Reflections(
new ConfigurationBuilder()
.setUrls(ClasspathHelper.forPackage("com.your.app.strategies.pkg"))
.setScanners(new SubTypesScanner())
);
And, then simply fire a query like
Set<Class<? extends Strategy>> strategies =
reflections.getSubTypesOf(com.your.app.strategies.pkg.Strategy.class);

ClassLoader.getResourceAsStream() confusion

I am new to Java.
I have a requirement to load a configuration file (only one time, at app start up). What is the best way to do this? I have the following ideas:
Thread.currentThread().getContextClassLoader().getResourceAsStream(resourceName);
getClass().getClassLoader().getResourceAsStream(resourceName);
Out of these two which is the best and why?
Say for example, I have a method like below
public void loadConfig(String name) {
InputStream streamByContextClassLoader = Thread.currentThread().getContextClassLoader().getResourceAsStream(name);
}
If I call this method multiple times, is the config file loaded multiple times? Can any Please clarify my doubt?
I recommend using the first approach as it will work in cases when the second approach will not:
Thread.currentThread().getContextClassLoader().getResourceAsStream(resourceName);
I once initially used the second approach in a JUnit test and then we had to change it to use context class loader to allow running the test from IDE.
See: Difference between thread's context class loader and normal classloader , particularly this line
'In this case the object needs to use Thread.currentThread().getContextClassLoader() directly if it wants to load resources that are not available on its own classloader.'
Java uses several class loaders during runtime. It would be much simpler to use explicit file declaration instead of resources. Take a look on Commons Configuration.
On java class loaders you can read in Oracle official docs. If you pack configuration within your classes (into jar file) - you can use YourClass.class.getResourceAsStream(...). In other cases - prefer use explicit configuration file.
And yes, multiple calls to getResourceAsStream will load this resource multiple times. To clarify this take a look on java.net.URLClassLoader#getResourceAsStream sources.

Java .policy file - how to prevent java.util.Date() from being accessible

I am playing around with the java .policy file and was wondering how I could go about doing something like preventing calls to java.util.Date(), as an example.
I just want to get a better sense of the .policy file works and how it can be used to sandbox code.
You'll be out of luck there I'm afraid.
As PaĆ­lo Ebermann says, package.access can block out package hierarchies. You can be more precise about this with a custom SecurityManager, which is usually a damn good indication you are doing something really dodgy.
In general you can make a ClassLoader that doesn't always delegate to its parent. Technically against the current Java SE spec, although the Java EE spec encourages it. You could block out java.util.Date. It's still accessible through reflection if any other class references it, or you can get an instance of it. You could block out the transitive closure of uses of Date, including those that in some way return a Date. However, to complete the scheme with your minimal date you'd have to load a java.util.Date in your class loader, which you can't along with all other java.* classes.
So, err, replace the java.util.Date class in rt.jar (possibly using a Java Agent), and substitute in any class you don't want to restrict new Date() with new Date(System.currentTimeMillis()).
(Btw, +1 to anything that reduces the dependency on System.currentTimeMillis() and other magic methods.)
To restrict access to certain packages, you have actually to change not the .policy file, but the security.properties. There is an entry package.access=... which lists the packages for which RuntimePermissions are needed. So, you can't restrict specifically the access to a single class, only to a whole package (including subpackages, if needed), i.e. java.util.
(You can alternatively access this by the Security.?etProperty methods.)
If you did this, you later can add the right RuntimePermission to the Policy to let the "good" code use it.
I think quite a good part of the JRE would cease working if you restrict access to java.util, so better try another class for testing.
The way the sandbox mostly works is that there are calls from classes that do security-sensitive stuff to the current SecurityManager to check whether or not such a call should succeed. Since the Date class isn't perceived to be security-sensitive, no such calls exist in it's code and that's why - as explained by Tom and Paulo - it is very difficult to restrict it.
For example, in contrast: File operations are perceived to be security sensitive and that's why the File class has calls to the SecurityManager. As an example the delete method:
public boolean delete() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkDelete(path);
}
return fs.delete(this);
}
And thanks to the SecurityManager check in the File class you can restrict File delete operations in the .policy file with more ease.

Find Java classes implementing an interface [duplicate]

This question already has answers here:
How can I get a list of all the implementations of an interface programmatically in Java?
(11 answers)
Closed 9 years ago.
Some time ago, I came across a piece of code, that used some piece of standard Java functionality to locate the classes that implemented a given interface. I know the functions were hidden in some non-logical place, but they could be used for other classes as the package name implied. Back then I did not need it, so I forgot about it, but now I do, and I can't seem to find the functions again. Where can these functions be found?
Edit: I'm not looking for any IDE functions or anything, but rather something that can be executed within the Java application.
Awhile ago, I put together a package for doing what you want, and more. (I needed it for a utility I was writing). It uses the ASM library. You can use reflection, but ASM turned out to perform better.
I put my package in an open source library I have on my web site. The library is here: http://software.clapper.org/javautil/. You want to start with the with ClassFinder class.
The utility I wrote it for is an RSS reader that I still use every day, so the code does tend to get exercised. I use ClassFinder to support a plug-in API in the RSS reader; on startup, it looks in a couple directory trees for jars and class files containing classes that implement a certain interface. It's a lot faster than you might expect.
The library is BSD-licensed, so you can safely bundle it with your code. Source is available.
If that's useful to you, help yourself.
Update: If you're using Scala, you might find this library to be more Scala-friendly.
Spring can do this for you...
BeanDefinitionRegistry bdr = new SimpleBeanDefinitionRegistry();
ClassPathBeanDefinitionScanner s = new ClassPathBeanDefinitionScanner(bdr);
TypeFilter tf = new AssignableTypeFilter(CLASS_YOU_WANT.class);
s.addIncludeFilter(tf);
s.scan("package.you.want1", "package.you.want2");
String[] beans = bdr.getBeanDefinitionNames();
N.B. The TypeFilter is important if you want the correct results!
You can also use exclusion filters here instead.
The Scanner can be found in the spring-context jar, the registry in spring-beans, the type filter is in spring-core.
I really like the reflections library for doing this.
It provides a lot of different types of scanners (getTypesAnnotatedWith, getSubTypesOf, etc), and it is dead simple to write or extend your own.
The code you are talking about sounds like ServiceLoader, which was introduced in Java 6 to support a feature that has been defined since Java 1.3 or earlier. For performance reasons, this is the recommended approach to find interface implementations at runtime; if you need support for this in an older version of Java, I hope that you'll find my implementation helpful.
There are a couple of implementations of this in earlier versions of Java, but in the Sun packages, not in the core API (I think there are some classes internal to ImageIO that do this). As the code is simple, I'd recommend providing your own implementation rather than relying on non-standard Sun code which is subject to change.
Package Level Annotations
I know this question has already been answered a long time ago but another solution to this problem is to use Package Level Annotations.
While its pretty hard to go find all the classes in the JVM its actually pretty easy to browse the package hierarchy.
Package[] ps = Package.getPackages();
for (Package p : ps) {
MyAno a = p.getAnnotation(MyAno.class)
// Recursively descend
}
Then just make your annotation have an argument of an array of Class.
Then in your package-info.java for a particular package put the MyAno.
I'll add more details (code) if people are interested but most probably get the idea.
MetaInf Service Loader
To add to #erickson answer you can also use the service loader approach. Kohsuke has an awesome way of generating the the required META-INF stuff you need for the service loader approach:
http://weblogs.java.net/blog/kohsuke/archive/2009/03/my_project_of_t.html
You could also use the Extensible Component Scanner (extcos: http://sf.net/projects/extcos) and search all classes implementing an interface like so:
Set<Class<? extends MyInterface>> classes = new HashSet<Class<? extends MyInterface>>();
ComponentScanner scanner = new ComponentScanner();
scanner.getClasses(new ComponentQuery() {
#Override
protected void query() {
select().
from("my.package1", "my.package2").
andStore(thoseImplementing(MyInterface.class).into(classes)).
returning(none());
}
});
This works for classes on the file system, within jars and even for those on the JBoss virtual file system. It's further designed to work within standalone applications as well as within any web or application container.
In full generality, this functionality is impossible. The Java ClassLoader mechanism guarantees only the ability to ask for a class with a specific name (including package), and the ClassLoader can supply a class, or it can state that it does not know that class.
Classes can be (and frequently are) loaded from remote servers, and they can even be constructed on the fly; it is not difficult at all to write a ClassLoader that returns a valid class that implements a given interface for any name you ask from it; a List of the classes that implement that interface would then be infinite in length.
In practice, the most common case is an URLClassLoader that looks for classes in a list of filesystem directories and JAR files. So what you need is to get the URLClassLoader, then iterate through those directories and archives, and for each class file you find in them, request the corresponding Class object and look through the return of its getInterfaces() method.
Obviously, Class.isAssignableFrom() tells you whether an individual class implements the given interface. So then the problem is getting the list of classes to test.
As far as I'm aware, there's no direct way from Java to ask the class loader for "the list of classes that you could potentially load". So you'll have to do this yourself by iterating through the visible jars, calling Class.forName() to load the class, then testing it.
However, it's a little easier if you just want to know classes implementing the given interface from those that have actually been loaded:
via the Java Instrumentation framework, you can call Instrumentation.getAllLoadedClasses()
via reflection, you can query the ClassLoader.classes field of a given ClassLoader.
If you use the instrumentation technique, then (as explained in the link) what happens is that your "agent" class is called essentially when the JVM starts up, and passed an Instrumentation object. At that point, you probably want to "save it for later" in a static field, and then have your main application code call it later on to get the list of loaded classes.
If you were asking from the perspective of working this out with a running program then you need to look to the java.lang.* package. If you get a Class object, you can use the isAssignableFrom method to check if it is an interface of another Class.
There isn't a simple built in way of searching for these, tools like Eclipse build an index of this information.
If you don't have a specific list of Class objects to test you can look to the ClassLoader object, use the getPackages() method and build your own package hierarchy iterator.
Just a warning though that these methods and classes can be quite slow.

Categories

Resources