Java annotations not being found in JAR file using org.reflections - java

I'm using the org.reflections library to detect some classes that are annotated in my project. When I run the project from eclipse, the annotated classes are found.
However, when the project is packaged into a JAR file and run, no annotated classes are found.
Here is some example code:
#TestAnnotation
public class App {
public static void main (String[] args) {
Reflections reflections = new Reflections("com.package");
Set<Class<?>> annotated = reflections.getTypesAnnotatedWith(TestAnnotation.class);
for (Class c : annotated) {
System.out.println ("found annotated class " + c.getName());
}
}
}
When I run this code in a JAR file there is no output. What am I doing wrong?
Thanks

Pay attention to
Reflections reflections = new Reflections("com.package");
There you try to explore annotated classes located in package package which is nested in com package. But package is Java keyword. So it can not be used as name of package. After I moved App and TestAnnotation just into com package everything works fine.
But it is possible that your case is really bad. May be some tool or some person created package that has package name (for example, used Cyrillic а instead of Latin a, both are looking same in editor, but they are totally different for Java). When letters are mixed everything looks fine but doesn't work. So try to create new valid root package and move your classes into it.

Related

How to write an import statement to refer to a java class in a jar?

How can I refer to a Java class in stdlib1.jar when the directory structure is like this? How to write the import statement?
I want to call a method under stdlib1.jar, I have configured it.
The classes are in the default package. According to this answer, it is not possible to import classes from the default package. So, they have to be moved to another package or you have to use reflection.
You call a method from a class and not from a package.
You don't need to specify the jar when you call a method from a class belonging to it. Which matters is your jar is in the classpath
In your screenshot if the lib makes part of the classpath folders, you can import and use classes from it in your code.
Here the classes of your jar use the default package (no package name) which seems weird for a third-party library. Default package is not recommended since it doesn't allow to naturally reference and use the classes of the archive from the client code.
I am not sure you are using the correct version of the jar. Look at that :
http://grepcode.com/snapshot/repo1.maven.org/maven2/com.googlecode.princeton-java-introduction/stdlib/1.0.1
This contains classes in the edu.princeton.cs package :
With package, you could declare this :
For example :
You could create a class like that and use BinaryIn like that:
package main;
import edu.princeton.cs.BinaryIn;
public class MyClass(){
public static void main(String args[]){
BinaryIn in = new BinaryIn();
}
}

How to instantiate a class without knowing its package?

I have an Eclipse project (MainProject) and it references another Eclipse project (ReferencedProject). MainProject also references a JAR file (ReferencedJar). This ReferencedJar's file name is known. I also know there is a class (ReferencedClass) in ReferencedJar, but I don't know in what package ReferencedClass is because the package path is not known beforehand.
I need to instantiate ReferencedClass in ReferencedProject using reflection. How can I do this? And will the solution be okay when the project is packaged to a its standalone jar outside Eclipse?
The reason for this question is; The ReferencedJar is file generated by a modeller application. It generates java classes for your model and puts them into ReferencedJar. The user can choose which package the classes it generates will be put into. But the class names are always the same. MainProject is project that will include this generated jar, but ReferencedProject (a framework) also needs to instantiate a class in this generated jar. Hope this makes the question more clear.
Thanks in advance
Edit: Actually I have an idea but don't know how to implement it. Because I know the name of ReferencedJar file, I could access it on runtime and check all the classes it contains. Then I can find the matching class by name comparison. But how can I access the ReferencedJar on runtime?
As long as the class you need is in the class path, you can get a reference to it by invoking Class.forName(String className)
String className = "WhatEver";
String packageName = "some.package";
Class<?> c = Class.forName(packageName + "." + className);
If you don't know the package name, however, and there's no way to get it from a configuration file, I would recommend using a library like reflections to scan the class path and find the relevant class.
You can not instantiate a class you if do not know its package

Access classes from package

I'm developing an android test app and i'm going to access all internal class of android.view package. android.view is a package that is present in jar file. I tried by loading package name but it doesn't display the classes if any one tried
this already, please help.
Here's what I tried so far:
public static void main() throws ClassNotFoundException{
Class o =Class.forName("android.view");
Class[] C=o.getDeclaredClasses();
for(int i=0;i<C.length;i++) {
Classname = C[i].getName();
ClassesDisplayActivity.your_array_list3.add(Classname);
Log.i("Ramu","classname "+ C[i].getName());
}
}
}
It is not possible to determine at runtime all of the classes that are in a package using a standard class loader.
You might have some luck with this library though:
https://code.google.com/p/reflections/
Package is not a class. You cannot call Class.forName() for package and access classes that belong to class using getDelcaredClasses().
I do not know what do you really need, so I'd recommend you to explain this in separate question. probably you will receive better solutions.
However if you really need this you have to do the following:
Get your classpath by calling System.getProperty(java.class.path)
split this property to its elements by colon
iterate over the list and read each resource. If resource is jar you can use ZipInputStream, if it is a directory use File class.
filter list of resources you got at #3.
Fortunately you can use 3rd party library named Reflections that helps you to do all this without writing code.

How do I get all the class names and method names of a project?

I have downloaded a huge project written in Java. I wish to know the Classes and Methods of every class that are available in the project (for further analysis). How can I recover this information. Can I try javadoc in eclipse?
I guess you may ask about changing SVN properties.
Follow this step if that so.
press Alt + Shift + Q
Select Show view (view : Outline)
then under that u can see all details
I have wrote a custom doclet to list the classname and its methods:
public class ListClassAndMethods {
public static boolean start(RootDoc root) {
ClassDoc[] classes = root.classes();
for(ClassDoc clazz : classes){
System.out.println("Class Name: "+clazz);
System.out.println("--------------------------");
for(MethodDoc methodz :clazz.methods()){
System.out.println(methodz.name());
}
}
return true;
}
}
you need to run create a jar of this class and refer it while creating
a javadoc using Eclipse IDE
I would extract all the class source files (.java) with find (if you're on a *nix implementation) and create an empty NetBeans project with just one package and all the classess inside it. Netbeans will correct the package declaration and you can easily use autogenerate javadoc to get a navigable web archive listing all the classes and public/protected methods.
Of course the code may not run anymore but you'll get what you want in minutes.

Reflections returning Set with null elements

I'm using Reflections to find classes that have an specific annotation. My project structure is the following
One WAR package:
WEB-INF/classes/...packages.../ClassAnnoted1.class
One JAR package that is included by the war that has a class that executes this code:
Reflections reflections= new Reflections(ClasspathHelper.forWebInfClasses(servletContext))
Set set= reflections.getTypesAnnotatedWith(CustomAnnotation.class)
CustomAnnotation is also present on the JAR package.
the set size is correct (ie if I have 3 classes with the annotation in my WAR the jar, the set size comes back as 3), but all elements inside it are null instead of Class. I need to get the class and check the annotation parameters inside the class of the JAR.
Anyone got any idea of why this is happening?
EDIT:
Reflections reflections= new Reflections("com.my.customAnnotededClasses"); //package that my annoted class is in
Set set= reflections.getTypesAnnotatedWith(CustomAnnotation.class);
Also does not work, in this case the set length is zero instead of the number of classes with the annotation.
EDIT 2:
Ok, the real problem was that I was packaging my whole application as an EAR so I had the following:
EAR
----> WAR
----> JAR
The jar was included in the EAR lib folder and not on the WAR lib folder. So the jar classes couldn't see the war classes, once i made the WAR depend on the JAR directly like this:
EAR
----> WAR
---------> JAR
It started working. But the original question still stands, there might be situations where I want the Jar classes included in the EAR instead of the WAR (if i have multiple wars that need to use my jar for instance).
I guess I can't do it using the reflections library. So I did it by hand:
public static List<Class<?>> getClassesAnnotatedWith(Class annotation, ServletContext servletContext) {
List<Class<?>> webClasses, jarClasses;
webClasses= getClassesAnnotedWithFromClassLoader(annotation, servletContext.getClassLoader());
jarClasses= getClassesAnnotedWithFromClassLoader(annotation, Thread.currentThread().getContextClassLoader());
for (Class<?> jarClass : jarClasses) {
Class<?> elementToAdd= null;
for (Class<?> webClass : webClasses) {
if ( ! jarClass.getName().equals(webClass.getName())) {
elementToAdd= jarClass;
}
}
if(elementToAdd != null) {
webClasses.add(elementToAdd);
}
}
return webClasses;
}
private static List<Class<?>> getClassesAnnotedWithFromClassLoader(Class annotation, ClassLoader classLoader) {
List<Class<?>> classes= new ArrayList<Class<?>>();
Class<?> classLoaderClass= classLoader.getClass();
while (! classLoaderClass.getName().equals("java.lang.ClassLoader")) {
classLoaderClass= classLoaderClass.getSuperclass();
}
try {
Field fldClasses= classLoaderClass.getDeclaredField("classes");
fldClasses.setAccessible(true);
Vector<Class<?>> classesVector= (Vector<Class<?>>) fldClasses.get(classLoader);
for (Class c : classesVector) {
if (c.isAnnotationPresent(annotation)) {
classes.add(c);
}
}
} catch (Exception e) { }
return classes;
}
I get the ClassLoader from my WAR package through the ServletContext object. There is also a protection in case a class is defined in both the WAR and the JAR with the annotation and same name (you should probably check if the packages are the same too though).
Note that you should probably never use this code in your own projects (maybe only for debugging). It involves reflecting the ClassLoader class to make the "classes" property public. This property might not exists in Java 9 for example, so beware. This might also have some security problems if you are interacting modules written by third parties.
i had one a similar problem. are you sure, you included the annotation-classes into your classpath? if they are not loaded, they will somehow be found but not really returned and without any exception or anything
The Reflections library gave me various problems. Now I am using the reflection part of the Guava library: until now, no unexpected behavior has occurred.
In any case, I think that it is very rare that the source of the problem is the Java classloader.
Maybe try to load the class CustomAnnotation.class before to use it in the Reflections API.
Your code should work on conventional environments.
However, in different environments, such as osgi, you get:
1) urls with different protocol (bundle/vfs/...)
2) different class loader.
In the first case, you should a) add the relevant UrlType (see the DefaultUrlTypes in Vfs for examples), or b) use different method to get the urls (see other methods in ClasspathHelper and examine the returned URL list)
In the second case, you should a) pass the customClassLoader to Reflections constructor or ConfigurationBuilder in order resolving will happen, or b) query the store directly reflections.getStore().get(TypeAnnotationsScanner.class)
see also #8339845, JbossIntegration

Categories