Java Reflection with Child Classes - java

I'm attempting to use Reflections (as provided by org.reflections) to handle some heavy lifting, and so I don't need to manually create an instance for every class in a very long list. However, Reflections isn't targeting the classes in the way I'd expect, which is causing some issue.
My current Reflections code:
Reflections reflections = new Reflections(this.getClass().getPackage().getName() + ".command.defaults");
Set<Class<? extends Command>> commandClasses = reflections.getSubTypesOf(Command.class);
// Iterate through all the detected/found classes
for (Class c : commandClasses) {
// If a class is abstract, ignore it.
if (Modifier.isAbstract(c.getModifiers())) {
continue;
}
// Attempt to create an instance of the class/command whatever.
try {
c.newInstance();
} catch (InstantiationException | IllegalAccessException ex) {
// For once, the right thing to do is just ignore the exception.
// If a command is loaded but we can't create an instance or we
// can't access it, just skip. But, we'll at least log it (for now).
ex.printStackTrace();
}
}
Essentially, my program has all commands present in com.example.command.defaults, where they're divided up into a number of sub-packages just for visual grouping. Each command is in its own class, where it extends one of our three abstract classes in com.example.command: PlayerCommand, SimpleCommand, or just Command. PlayerCommand and SimpleCommand also extend Command.
From my understanding, reflections.getSubTypesOf(Command.class) should allow me to target any class that extends Command in any way, but it doesn't seem to be working that way. Using my debugger tool, I've noticed that only a single class (which extends just Command) is actually being read by the system.
How can I make my Reflections code target all classes that extend Command and any classes that extend a class that extends Command?

Acording to the API documentation, getSubTypesOf(Class<T> type)
gets all sub types in hierarchy of a given type but it also stats that this is "depends on SubTypesScanner configured".
The issue is that not all classes are loaded and known by the class loader in advanced and therefor you don't get it in the result list.

Related

Get all classes within constrains

Im trying to make a generic instance mapper from an SQLite DB to my project logic layer.
Each entry in the mapper is an instance of some class "DAL< name >" for example DALProduct all in the same package that extends class DALObject with the following structure:
public abstract class DALObject{
abstract String getCreate();
... //other logic
}
Using reflection I can easily call the getCreate method on each class and get what I need from it.
The issue is that I don't know how many child classes DALObject will have and i want a mapper that won't need to be touched when a new one is added.
I know that you can get all child classes of DALObjects that have been loaded but I run this code at the very start of my program before I load any of the classes.
Any ideas? I have a pretty big constraint case so maybe I can somehow hack it together.
Such task is only possible by scanning every class on the classpath (which, depending on how many libraries you use, are usually a lot) and see if it extends DALObject.
If you want to go that route, the org.reflections library can help you with that:
Reflections reflections = new Reflections("my.package",
Reflector.class.getClassLoader(), new SubTypesScanner(false));
Set<Class<? extends Module>> modules = reflections.getSubTypesOf(DALObject.class);
For performance reasons, I highly recommend doing this scan once during startup of your application and store the results.
As an alternative approach (I did not bother with generic type safety of Class here, this is to be implemented):
public abstract class DALObject {
public static List<Class> subTypes = new ArrayList<>();
public DALObject() {
DALObject.subTypes.add(this.getClass());
}
}
Obviously this only works if you instantiate objects of the subclasses somewhere, if your getCreate is meant to do that in the first place, my suggestion will obviously not work.
This would be a perfect instance of when to use an annotation. You could define the annotation before the declaration of each class, indicating that the class has some meta-data about 'DALObjects'. Then you could use Reflections or some similar library to easily find all Class objects with this annotation.
For example;
#Target(value=TYPE)
public #interface DALObject {
}
#DALObject
public class MyDALObject {
}
Reflections reflections = new Reflections(new ConfigurationBuilder()
.setScanners(new TypeAnnotationsScanner()));
Set<Class<?>> annotatedWithDALObject = reflections.getTypesAnnotatedWith(DALObject.class);
Last I know, Reflections isn't well supported (only minor changes in years) and still doesn't work with modules.
Instead, I'd recommend using ClassGraph, which is ultra-actively maintained, and works with modules, weird class loaders and what not.
You'd find DALObject implementations like this:
ScanResult scanResults = new ClassGraph()
.acceptPackages(packages) //skip to scan ALL packages
.enableAllInfo() //Not necessary but gives you more info to filter on, if needed
.initializeLoadedClasses()
.scan();
//You can cache, or serialize scanResults using scanResults.toJSON()
List<Class<?>> impls = scanResults.getAllClasses().stream()
.filter(impl -> impl.extendsSuperclass(DALObject.getName()))
// or impl.implementsInterface(DALObject.getName()) if DALObject is an interface
.flatMap(info -> info.loadClass()) //or load the class yourself if you need to customize the logic
.collect(Collectors.toList());

Create different Java classes based on runtime config text

I have a suite that can run a few operations with different parameters. The operations and their parameters are provided in an XML config file.
There is a separate class implementing each operation. All of these classes extend an abstract Operation class, so once the class is created it can be handled in the same way in the code, whatever the actual operation is.
However, I do need to create the classes. And so far I see two ways of doing it:
a switch statement:
Operation operation;
switch (operationName) {
case "OperationA":
operation = new OperationA();
break;
case "OperationB":
operation = new OperationB();
break;
default:
log.error("Invalid operation name: " + operationName);
return true;
}
A runtime lookup of a class name. I never tested this option, but it seems to be something like:
Operation operation = (Operation)Class.forName(operationName).newinstance();
The first option seems unwieldy. The second option seems to trust the config too much, though I am not sure about this.
Perhaps I should just verify that operationName is a member of a predefined set or list that contains all my operations (or else set thepossible values in stone in an XML schema and verify the config against it), then use the second option? Or is there something better?
I would prefer to use the second option.
An example class. (Note that the default constructor is required because it is called by .newInstance(). You can also refer to this question: Can I use Class.newInstance() with constructor arguments? if you want to create a new class and use a constructor with parameters.)
package com.mypackage;
public class SomeObject {
public SomeObject() {}
}
How to create an instance of that class:
try {
// you need to use the fully qualified name, not just the class name
SomeObject object = (SomeObject) Class.forName("com.mypackage.SomeObject").newInstance();
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
// here you can handle incorrect config in your XML file
}
You can also have a list of qualified names in another configuration file or property and check against that list before attempting to create a class.

GroovyClassLoader - adding parsed classes to classpath

I've got a library that allows clients to provide a list of text files, each of which contains groovy code for a class that extends java class Z. For instance file 'A.groovy' contains
package com.mypkg;
public class A extends Z {
#Override
public void someMethod() {
// do something A-ish
}
}
etc.
The library compiles each of these and (in this case) would return to the clients an instance of type Z.
My issue comes when a client needs something like this:
package com.mypkg;
public class B extends A { // extends A!
#Override
public void someMethod() {
// do something B-ish instead of A-ish
}
}
where B extends A, and class A was parsed before class B.
The issue is that the GroovyClassLoader can't seem to find class A, even though it just parsed A. Here's the code that compiles the scripts and creates the instances:
for (String fileName : listOfScriptFiles) {
InputStream in = getInputStreamFromFile(fileName);
CompilerConfiguration compConfig = new CompilerConfiguration();
GroovyClassLoader classLoader = new GroovyClassLoader(Thread.currentThread()
.getContextClassLoader(), compConfig);
Z service = null;
Class clazz = classLoader.parseClass(in);
service = (Z) clazz.newInstance();
return service;
}
Is there a way to 'register' class A with the runtime so that when Groovy tries to compile class B it will not complain that class A doesn't exist?
UPDATE
I was actually able to solve this by instantiating the GroovyClassLoader outside the loop that iterates through the client's code list, so the classloader that parses A is the same that parses B.
The question still stands, though, because I could envision a case where in one part of someone's code they parse A, and then in a completely different part, where the same classloader is unavailable, they parse B.
In my experience with the Groovy classloader (which is similar in behavior with Ant and beanshell's classloader in this respect) , you have to decide up front whether you are going to use the default system classloader, in which case you would build the classpath into the command that launches the Groovy script, OR on the other hand, you specify ONLY the groovy jar on the command line classpath and then you dynamically add classes at the beginning of your Groovy script on the custom classloader.
You aren't providing much information in your question, but my guess is that you put class "A" on the classpath before you launched the script and then your trying to load class "B" dynamically. That wouldn't work as far as I know.
NOTE: I myself have been trying to figure out how to do this kind of thing. It seems it would be possible but I still haven't figured it out.

Automatic factory registration

i'm just learning java, and i meet some problems.
Here we have simple factory pattern:
public class SomeFactory {
...
public static void registerProduct(String name, Class<? extends IProduct > f)
}
public SomeProduct implements IProduct {
static {
SomeFactory.register("some product", SomeProduct.class);
}
...
}
All products should register themselves at factory.
But before using this code, all Products classes should be loaded.
I can put Class.forName() somewhere, for example in main function.
But i want to avoid such sort of manual classes loading. I want just add new IProduct
implementations, without updating other parts(such as SomeFactory or Main methods, etc.).
But i wonder, is it possible to automatically load some classes(marked with annotation, for example)?
P.S I want to notice, that no other classes will be added at run-time, all IProduct implementations are known before compiling.
UPD#1
Thank for your answering!
But is it possible to make auto-generated property-file with IProduct instances?
I mean is it possible to make some build-time script(for maven for example) that generates property-file or loader code? Are there such solutions or frameworks?
UPD#2
I finished with using Reflections library that provides run-time information, by scanning classpath at startup.
This is possible, but not easily. It would need to scan all the classes in the classpath to see if they have an annotation or implement the IProduct interface. See How do you find all subclasses of a given class in Java? for answers to such a problem.
I would do keep it simple and just have a list of classes to load, either in the factory itself, or in an external file (properties file, for example).
Have each product register itself, using a static block like this:
class MyProduct1{
static{
SomeFactory.register(MyProduct1.getClass());
}
..
..
}
An external property file can keep track of all Products.
Your main method can parse this list of Products and do a Class.forName("..").
This way you wouldnt need to code any specific product, just the property file keeps changing. Ah! yes adding security registration would also be a plus point.
Note: I'm just proposing an idea, I'vent tried it myself :)

How to Read Java File Structure using Java?

I'm trying to read a java file and display in console the package, class and method name. something like this:
File: Test.java
package tspec.test;
public class Test {
public void addTest () {}
public void deleteTest () {}
}
Output:
package name: tspec.test
class name: Test
method name:
addTest
deleteTest
Thanks in advance :)
This can be accomplished using the Java Compiler API (introduced in Java 6). Unfortunately, this solution is limited to Sun's JDK. Therefore, you will have to have that JDK installed and you must include its tools.jar file in your class path.
public void displayInformation(File javaSourceFile) throws Exception {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
// The file manager locates your Java source file for the compiler. Null arguments indicate I am comfortable with its default behavior.
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
// These will be parsed by the compiler
Iterable<? extends JavaFileObject> fileObjects = fileManager.getJavaFileObjects(javaSourceFile);
// Creates a new compilation task. This doesn't actually start the compilation process.
// Null arguments indicate I am comfortable with its default behavior.
CompilationTask task = compiler.getTask(null, null, null, null, null, fileObjects);
// Cast to the Sun-specific CompilationTask.
com.sun.tools.javac.api.JavacTaskImpl javacTask = (com.sun.tools.javac.api.JavacTaskImpl) task;
// The Sun-specific JavacTaskImpl can parse the source file without compiling it, returning
// one CompilationUnitTree for each JavaFileObject given to the compiler.getTask call (only one in our case).
Iterable<? extends CompilationUnitTree> trees = javacTask.parse();
CompilationUnitTree tree = trees.iterator().next();
// Create a class that implements the com.sun.source.tree.TreeVisitor interface.
// The com.sun.source.util.TreeScanner is a good choice because it already implements most of the logic.
// We just override the methods we're interested in.
class MyTreeVisitor extends TreeScanner<Void, Void> {
#Override
public Void visitClass(ClassTree classTree, Void p) {
System.out.println("class name: " + classTree.getSimpleName());
System.out.println("method name:");
return super.visitClass(classTree, p);
}
#Override
public Void visitMethod(MethodTree methodTree, Void p) {
System.out.println(methodTree.getName());
return super.visitMethod(methodTree, p);
}
}
tree.accept(new MyTreeVisitor(), null);
}
When I pass this method a File whose content is your sample, I receive this output:
class name: Test
method name:
addTest
deleteTest
Unfortunately, I haven't yet figured out where the package name is stored.
Reflection and Introspection Java API's.
It's purpose is to introspect Java code and report back about it's contents. With Reflection you can do things like :
Class.forName(className).getDeclaredMethods();
Java also has the Java Mirror API with similiar functionality, but is not as commonly used.
Both of these solutions require no 3rd party libraries or tools.
The only difficult is the java code may not be well formatted. like the function declaration can be spread on multiple lines.
The ultimate solution is to create an automata to tokenize the source code first and then apply some compiler technique to grab what you want from the parsed data.
We use PMD Java code analyzer to solve similar problem.
It is useful.
http://pmd.sourceforge.net/
You don't have to do this by parsing the Java file yourself! Java already contains a way of getting information about its own classes, methods, and packages: it's called reflection.
Have a look at the java.lang.Class class. Each instance of this class represents a particular Java class, and contains methods to return the class name, the package it lives in, the methods it contains, and lots more information.
Also worth looking at is the java.lang.reflect package, since some of the methods of Class return types from this package. The package contains classes to represent things like methods, types, fields, and so on.
To obtain a Class instance of your Test class, you can use the following code:
Class<?> testclass = Class.forName("tspec.test.Test");
This returns a class of an unknown type, which is what the question mark inside the angle brackets means if you're not familiar with generics. Why the type of the class instance is unknown is because you specify the class name with a string, which is parsed at runtime. At compile-time, Java cannot be sure that the string passed to forName even represent a valid class at all.
However, testclass as defined above will be fine for getting the class's name, methods, and containing package.

Categories

Resources