Java reflection without file [duplicate] - java

This question already has answers here:
Can you find all classes in a package using reflection?
(30 answers)
Closed 6 years ago.
With that I can find the package name within an application
Package pack = Item.class.getPackage();
But all examples which I can find here or elsewhere to find the classes in a package use file to load a jar and look into that. I there a way to gat a classes list within active project without file ?
[EDIT]
there are othere answers here but they all didn't work for me
[Edit]
is for some reasons this has been blocked for answers. here is the solution
private static Set<Class<? extends Object>> getClassesInPackage(String packagename) {
List<ClassLoader> classLoadersList = new LinkedList<ClassLoader>();
classLoadersList.add(ClasspathHelper.contextClassLoader());
classLoadersList.add(ClasspathHelper.staticClassLoader());
Reflections reflections = new Reflections(new ConfigurationBuilder()
.setScanners(new SubTypesScanner(false /* don't exclude Object.class */), new ResourcesScanner())
.setUrls(ClasspathHelper.forClassLoader(classLoadersList.toArray(new ClassLoader[0])))
.filterInputsBy(new FilterBuilder().include(FilterBuilder.prefix(packagename))));
Set<Class<?>> classes = reflections.getSubTypesOf(Object.class);
return classes;
}

It is impossible due to dynamic nature of classloaders. Classloaders do not have to expose all classes they have.
The only way might be to write your own classloader and play with the order of classloading so, your classloader will have more info.
However, here is a library that could potentially help you getting classes in the package (never used it but found it just now by googling).
something ike that:
Reflections reflections = new Reflections("my.project.prefix");
Set<Class<? extends Object>> allClasses =
reflections.getSubTypesOf(Object.class);

Related

Reflections and ByteBuddy

How can I use byte-buddy generated classes with "org.reflections"?
Example:
Class<?> dynamicType = new ByteBuddy()
.subclass(Object.class)
.name("de.testing.SomeClass")
.method(ElementMatchers.named("toString"))
.intercept(FixedValue.value("Hello World!"))
.make()
.load(getClass().getClassLoader(),ClassLoadingStrategy.Default.INJECTION)
.getLoaded();
Now I want to use org.reflections to find all subtypes of Object inside a specific Package:
Reflections reflections = new Reflections("de.testing");
Set<Class<? extends Object>> objs = reflections.getSubTypesOf(Object.class);
for (Class clazz : objs ) {
log.info("{}",clazz.getName());
}
Any ideas?
As suggested in the comments, reflections scans the class path by querying class loaders for its resources. This does normally only work for standard class loaders whereas Byte Buddy creates classes in memory where they are not found using resource scanning.
You can work around this by storing Byte Buddy's classes in a jar file and loading this jar file manually using a URLClassLoader. Byte Buddy allows you to create a jar by .make().toJar( ... ). You can then provide this class loader to reflections which by default only scans the system class loader.
All this does however seem like quite a complex solution to a problem that could be easily solved by registering your types somewhere explicitly.

Java Reflections: Get Classes but not SubTypes

I'm upgrading from org.reflections:reflections:0.9.5 to version 0.9.9. I am using:
Reflections reflectionPaths = new Reflections("resources", new TypeAnnotationsScanner());
Set<Class<?>> rootResourceClasses = reflectionPaths.getTypesAnnotatedWith(Path.class);
Which gets me all classes in the resources package with an #Path Annotation.
Since the library has been updated the top line requires an extra new SubTypesScanner() for the code to run. I however do not want sub types to be returned.
How can I use this new version of the library to pull back only classes and interfaces that are not sub types?
I get this Exception if I don't include the SubTypesScanner
org.reflections.ReflectionsException: Scanner SubTypesScanner was not configured
at org.reflections.Store.get(Store.java:58)
at org.reflections.Store.get(Store.java:70)
at org.reflections.Store.getAll(Store.java:97)
at org.reflections.Reflections.getAllAnnotated(Reflections.java:423)
at org.reflections.Reflections.getTypesAnnotatedWith(Reflections.java:384)
at org.reflections.Reflections.getTypesAnnotatedWith(Reflections.java:370)
I believe you using this annotation "javax.ws.rs.Path". Pls try this :-
Reflections reflectionPaths = new Reflections("resources", new TypeAnnotationsScanner());
Set<Class<?>> rootResourceClasses = reflectionPaths.getTypesAnnotatedWith(Path.class, true);
I faced the same problem and my solution is providing SubTypesScanner as well:
Reflections reflectionPaths = new Reflections(packageString,
new TypeAnnotationsScanner(), new SubTypesScanner());
Not sure if it helps, but I had that Scanner SubTypesScanner was not configured error which started appearing when I updated a totally unrelated lib.
I found that message where someone, looking for a similar error, discovered that the exception is thrown when the path is totally empty (not my case) but also if a base class of the one looked for is not in the scanned package (my case).
I have zero idea why it used to work, nor why it stopped, but I added the missing package in the scanner and it started working again.

How to speed up the class scan via Reflection API in Java?

I use org.reflections library to scan ClassPath and get classes. Here is my code:
Reflections ref = new Reflections();
Set<Class<? extends Service>> classes = new HashSet<>();
for (Class<? extends Service> subType : ref.getSubTypesOf(Service.class)) {
if (!Modifier.isAbstract(subType.getModifiers())) {
classes.add(subType);
}
}
But I faced a problem. It takes too much time. At the same time I can not set a package
new Reflections("my.pack");
because I want to save an ability to add Service classes in the future. How can I accelerate this process? Is it possible to exclude rt.jar packs?
Use FilterBuilder to exclude java root package at least.
And it may help to specify SubTypesScanner as that's what you're doing.
Reflections ref = new Reflections(new SubTypesScanner(),
new FilterBuilder().excludePackage("java"));

Reflections could not get class type

I am using a third party library called Reflections (not to be mistaken with Java reflection) to search another jar for Classes that extend Foo using the following code:
Reflections reflections = new Reflections("com.example");
for(Class<? extends Foo> e : reflections.getSubTypesOf(Foo.class)) {
doSomething()
}
When I do this Reflections throws the following error:
org.reflections.ReflectionsException: could not get type for name com.example.ExtendsFoo
Does anyone know how to fix this cause I'm stumped?
Thanks in advance!
The problem may be due to not having a class loader that can resolve the name (even though it can resolve the subtype). This sounds contradictory, but I had the error message when I was building a Configuration and using ClasspathHelper.forClassLoader on an application- instantiated URLClassloader to figure out what to scan on the classpath, but not passing in said URLClassLoader into the Reflections configuration so that it could instantiate things correctly.
So you may want to try something along the lines of the following:
URLClassLoader urlcl = new URLClassLoader(urls);
Reflections reflections = new Reflections(
new ConfigurationBuilder().setUrls(
ClasspathHelper.forClassLoader(urlcl)
).addClassLoader(urlcl)
);
where urls is an array of URLS to the jars containing the classes you want to load. I was getting the same error as you if I did not have the final addClassLoader(...) call to the ConfigurationBuilder.
If this doesn't work, or is not applicable, it may be worth just setting a breakpoint in ReflectionsUtil.forName(String typeName, ClassLoader... classLoaders)) to see what is going on.
Take a look: https://code.google.com/p/reflections/issues/detail?id=163
Reflections (in its current version 0.9.9-RC1) doesn't re-throw exception correctly. That's why you may miss the true cause of the problem. In my case it was a broken .class file, which my default class loader failed to load and threw an exception. So, first of all, try to make sure that your class is truly loadable.
Scanning for classes is not easy with pure Java.
The spring framework offers a class called ClassPathScanningCandidateComponentProvider that can do what you need. The following example would find all subclasses of MyClass in the package org.example.package
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(true);
provider.addIncludeFilter(new AssignableTypeFilter(MyClass.class));
// scan in org.example.package
Set<BeanDefinition> components = provider.findCandidateComponents("org/example/package");
for (BeanDefinition component : components)
{
This method has the additional benefit of using a bytecode analyzer to find the candidates which means it will not load all classes it scans.
Class cls = Class.forName(component.getBeanClassName());
// use class cls found
}
Fore more info read the link

Loading the classes from a jar that is dynamically uploaded through a servlet

I am uploading a jar dynamically through servlet and saving it in my WEB-INF/lib directory.
I want to get all the classes annotated with my #annotation,
have used reflections code below without any luck.. the manifest of the jar is readble but the classes are not.. the list of classes is 0
List<ClassLoader> classLoadersList = new LinkedList<ClassLoader>();
classLoadersList.add(ClasspathHelper.contextClassLoader());
classLoadersList.add(ClasspathHelper.staticClassLoader());
ConfigurationBuilder builder = new ConfigurationBuilder().setScanners(new SubTypesScanner(false), new ResourcesScanner(),
new TypeAnnotationsScanner());
Set<URL> set = ClasspathHelper.forClassLoader(classLoadersList.toArray(new ClassLoader[0]));
FilterBuilder filterBuilder = new FilterBuilder().include(FilterBuilder.prefix(exportPackage));
Reflections reflections = new Reflections(builder.setUrls(set).filterInputsBy(filterBuilder));
Set<Class<? extends Object>> classSet = reflections.getTypesAnnotatedWith(MyAnnotation.class);
What changes to the configuration will help get the classes from the jar that is dynamically uploaded..
Since you are updating your own WEB-INF/lib directory it is not necessarily caught by your context class loader. BTW I think it is a bad practice: the behavior depends on the application server and this directory is probably not writable and even probably does not exist if you are running from war...
So, I'd put the jar to other directory and use my custom class loader. It is not so hard. You can use regular UrlClassLoader. Just configure it to read classes from correct path. Once this is done pass this class loader when you are creating instance of Reflections. Take a look on its javadcoc. The constructor can except various types of parameters including class loader.
from your listener class (or from wherever servletContext is available), try using:
new Reflections(ClasspathHelper.forWebInfClasses(servletContext))
or
new Reflections(ClasspathHelper.forWebInfLib(servletContext))

Categories