Given the following snippet:
Set<Class<? extends MyClass>> allClasses =
new Reflections("mypackage").getSubTypesOf(MyClass.class);
The library recursively search for all the classes extending MyClass in the given package and subpackages. I need to do this in the given package only, i.e., not in the subpackages. Is there a way to do so?
You can use the input filter (a Predicate), so that types in sub packages would not be scan:
new Reflections(new ConfigurationBuilder().
addUrls(ClasspathHelper.forPackage("my.pack")).
filterInputsBy(new FilterBuilder().
include("my\\.pack\\..*\\.class").
exclude("my\\.pack\\..*\\..*\\.class")));
And of course, you can always (post) filter the results, for example:
import static org.reflections.ReflectionUtils.*;
getAll(reflections.getSubTypesOf(A.class),
withPattern(".*my\\.pack\\.(?!.*\\..*).*")); //ouch...
This is brute force, but:
1) Get subclasses of MyClass. Put in a set.
2) Iterate over classes in the set; remove classes which belong to other packages (i.e. those for which _someClass.getPackage().equals(MyClass.class.getPackage()) is false)
Related
I want to use Runtime Reflection with Scala annotations (could also be a Java annoations if necessary, but I would prefer to limit pure Java code)
I want to implement something like:
/**
print all methods that implement a specific annotation
*/
def getAllAnnotated(): Unit {...}
For example, if I have:
class Foo {
#printme
def foo(args: A): R
def oof(args: A): R
}
class Bar {
#printme
def bar(): Unit
}
The result of running getAllAnnotated() would be something like:
Foo.foo
Bar.bar
Note that I don't want to look in a specific class, but instead any available method
Try one of classpath scanners based on Java reflection (e.g. Reflections) + scala-reflect. Since we use Java reflection only to look for classes and scala-reflect to look for annotated methods, annotations can be written in Scala.
import org.reflections.Reflections
import org.reflections.scanners.SubTypesScanner
import org.reflections.util.{ClasspathHelper, ConfigurationBuilder}
import scala.annotation.StaticAnnotation
import scala.jdk.CollectionConverters._
import scala.reflect.runtime.currentMirror
import scala.reflect.runtime.universe._
class printme extends StaticAnnotation
val reflections = new Reflections(
(new ConfigurationBuilder)
.setUrls(ClasspathHelper.forPackage(""))
.setScanners(new SubTypesScanner(false))
)
def getAllAnnotated(): Unit =
reflections.getAllTypes.asScala
.flatMap(className =>
currentMirror.classSymbol(Class.forName(className))
.toType
.decls
.filter(symbol =>
symbol.isMethod && symbol.annotations.exists(_.tree.tpe =:= typeOf[printme])
)
.map(method => s"$className.${method.name}")
).foreach(println)
Alternatives to Reflections library are for example ClassGraph and Burningwave. If we replace scala-reflect with Java reflection then annotation will have to be written in Java because only annotations written in Java are visible at runtime with Java reflection.
In Java you can scan for the classes in the package using reflection Using Reflections to get all classes of the package and then recursively go inside all the classes to find the annotations.
I want to load dynamic library where classes inherit from an interface/abstract class on my core project, so I can load my classes at runtime and use it. How can i do that ?
Example:
Core: ITrigger (interface)
Library: {MyTriggerOne extends ITrigger} {MyTriggerTwo extends ITrigger}
If you want to load a class/library dynamically use Class.forName('class name') method to load.
I had the same requirement and I used the library Reflections.
Very simple code snippet:
public Set<Class<? extends ITrigger>> getITriggerClasses() {
final Reflections reflections = new Reflections("package.where.to.find.implementations");
return reflections.getSubTypesOf(ITrigger.class);
}
Then you can use the method Class::newInstance to create the ITrigger(s).
This is a very simple example, there are several options to initialize the Reflections class (not only with one package name).
Java's SPI(Service Provider Interface) libraries allow you to load classes dynamically based on the interfaces they implement, that can be done with the help of META-INF/services.
You can create a interface like
package com.test.dynamic;
public interface ITrigger {
String getData();
String setData();
}
you can use the ServiceLoader class to load the interface like below code
ServiceLoader<ITrigger> loader = ServiceLoader.load(ITrigger.class);
then you can perform all the operation on it.
If you have some other implementing classes on your classpath, they register themselves in META-INF/services.
you need to create a file in META-INF/services in your classpath with the following properties
The name of the file is the fully qualified class name of the
interface, in this case, it's com.test.dynamic.ITrigger
The file contains a newline-separated list of implementations, so
for the example implementation, it would contain one line:
com.test.dynamic.impl.SomeITriggerImplementation class.
I would like to reference a class Bag in a JAR file, but Eclipse is telling me that Bag cannot be resolved to a type. I have added the JAR in which Bag is defined to the classpath for the project, but the error is still there. What am I doing wrong?
I think you can't do that, because the Bag class in algs4.jar is inside the default package.
Before J2SE 1.4, we still can import classes from the default package using a syntax like this:
import Unfinished;
But from J2SE 1.5, that's no longer allowed. So if we want to access a default package class from within a packaged class requires moving the default package class into a package of its own. Read here for more detail explanation :
How to access java-classes in the default-package?
Some options you can choose :
Access the class via reflection or some other indirect method. But it is a little bit hard, something like this :
Class fooClass = Class.forName("FooBar");
Method fooMethod = fooClass.getMethod("fooMethod", new Class[] { String.class });
String fooReturned = fooMethod.invoke(fooClass.newInstance(), new String("I did it"));
If you own the source code of that jar library, you need to put it in properly package and wrap it again as a new jar library.
You may need to either fully qualify the Bag class, or import it.
I have the need of getting the Class from a String.
The string is just the class his name without the package declaration.
While I could use Class.forName(className); this requires me to give the FQN.
Here is just where I have the problem.
I know its base package : be.chillworld.catalog but this package have subpackages.
Example :
be.chillworld.catalog.location
be.chillworld.catalog.operation
Easiest solution is to remove all the subpackages so I can do the Class.forName() but there goes the nice structure then.
Anyone have an idea of how to get mine specific class?
Use Reflections Class.Give base package when initiating class and get your specific classes.
Reflections reflections = new Reflections("com.sss.xxx");
reflection.getSubTypesOf(ddd.class)
I want to get all the package names from an separate Java project, how would I do this in Java preferably using reflections?
I have imported the project into my build path and I've tried using the code below to get the package names.
Package[] pack = Package.getPackages();
EDIT: I'm not using jar files, I have just imported the project as it will be in the same dir. I only need packages that I created, specifically packages which begin with a certain directory.
You really can't know every package name in the libraries by just using getPackages() as it only will list the ones known to the classloader. This means that if a class has not yet been loaded from a specific package, then it will be absent from the list.
Use the zip file handling routines to open the jar files, and read out the packages by directory name. With this technique, you will discover all package names, even those that are not yet "in use". Basically, any path that contains a .class file is a "package name".
---- Edited as further details indicates JAR files are not being used ---
Since you aren't using JAR files (and why not? they're really good!), you will have to scan directories. To "find" the directories, you will need to chop up the class path. The way to get the class path is:
String classpath = System.getProperty("java.class.path", null);
Then you do a search of all the directories under each "starting point" that has a .class file in it. Once you have all of those, you have all of the packages.
Again, it is not possible to know all the packages by just asking the classloader, unless you could somehow guarantee the class loader has loaded all of the classes (which it typically doesn't).
As long as you don't need empty packages, something like this should work:
/**
* Finds all package names
* #return Set of package names
*/
public Set<String> findAllPackages() {
List<ClassLoader> classLoadersList = new LinkedList<ClassLoader>();
classLoadersList.add(ClasspathHelper.contextClassLoader());
classLoadersList.add(ClasspathHelper.staticClassLoader());
Reflections reflections = new Reflections(new ConfigurationBuilder()
.setScanners(new SubTypesScanner(false), new ResourcesScanner())
.setUrls(ClasspathHelper.forClassLoader(classLoadersList.toArray(new ClassLoader[0])))
.filterInputsBy(new FilterBuilder().include(FilterBuilder.prefix("my.base.package"))));
Set<Class<? extends Object>> classes = reflections.getSubTypesOf(Object.class);
Set<String> packageNameSet = new TreeSet<String>();
for (Class classInstance : classes) {
packageNameSet.add(classInstance.getPackage().getName());
}
return packageNameSet;
}
It finds all classes, loops through them and gets the package name stored in a Set to avoid duplicates.
Unfortunately, we can't just use the code below with a normal Reflections object without specifying a custom configuration to allow Object scanning.
Set<Class<? extends Object>> classes = reflections.getSubTypesOf(Object.class);