vancetang / reflections

Automatically exported from code.google.com/p/reflections
Do What The F*ck You Want To Public License
0 stars 0 forks source link

Reflections can`t find anotated classes in external jar #118

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
Hello everybody,

I'm trying to detect anotated Java classes using reflections. It works fine 
when classes are in the project. But when I move this classes to an external 
jar reflections can't find them. I'm using the following code:

Reflections reflections = new Reflections(new ConfigurationBuilder()                        
  .setUrls(ClasspathHelper.forJavaClassPath()));    

Set<Class<?>> annotated = reflections.getTypesAnnotatedWith(MC.class);  

And annotated set is empty when anotated classes are in an external jar. I have 
checked out that the jar is in the classpath by printing out the classpath and 
it appears there.

how can I fix this? thanks in advance.

Original issue reported on code.google.com by jjsarr...@gmail.com on 4 Jun 2012 at 8:34

GoogleCodeExporter commented 9 years ago
I'm using Eclipse, windows 7 and the last reflections 0.9.7 RC1, but I don't 
think the problem is related to this. It's something else.

Original comment by jjsarr...@gmail.com on 4 Jun 2012 at 8:37

GoogleCodeExporter commented 9 years ago
need more info: either create a reproducible code, debug or send the log (just 
add the slf4j-simple)

Vfs.fromURL(url).getFiles() - for the external url (jar), does the result 
contains the class file?

Original comment by ronm...@gmail.com on 4 Jun 2012 at 9:12

GoogleCodeExporter commented 9 years ago
1.- Where can I find the log? I'm using Eclipse and nothing is generated and no 
error messages appear, it just don't find the classes in the jar. 
2.- I'm using VFs like this:

Vfs.fromURL(new 
URL("file:\\C:\\Users\\juanjo\\Desktop\\ejemplos.jar")).getFiles();

but how can I check if the ressult contains the class file I need? IM doing this

Iterable<File> fsx = Vfs.fromURL(new 
URL("file:\\C:\\Users\\juanjo\\Desktop\\ejemplos.jar")).getFiles()
Iterator test = fsx.iterator();
    while (test.hasNext()) {
           System.out.println(test.getClass().getCanonicalName());
        }

but this is and endless loop :(

Original comment by jjsarr...@gmail.com on 4 Jun 2012 at 9:37

GoogleCodeExporter commented 9 years ago
[deleted comment]
GoogleCodeExporter commented 9 years ago
sorry for being a newbie LOL. I have changed the code to this:

 Iterable<File> fsx = Vfs.fromURL(new URL("file:\\C:\\Users\\juanjo\\Desktop\\ejemplos.jar")).getFiles();
            Iterator test = fsx.iterator();
            while (test.hasNext()) {
                System.out.println(test.next());
            }

and this is the output:

C:\Users\juanjo\Desktop\ejemplos.jar!\META-INF/MANIFEST.MF
C:\Users\juanjo\Desktop\ejemplos.jar!\AddTable.class
C:\Users\juanjo\Desktop\ejemplos.jar!\AddTable.java
C:\Users\juanjo\Desktop\ejemplos.jar!\SplitTable.class
C:\Users\juanjo\Desktop\ejemplos.jar!\SplitTable.java
C:\Users\juanjo\Desktop\ejemplos.jar!\AddFK.class
C:\Users\juanjo\Desktop\ejemplos.jar!\AddFK.java

I don't know why this simbol "!" appear, but you can see that classes are 
there...

this is how I use reflections:

MicrochangeCreator mcc = new MicrochangeCreator();         
            Reflections reflections = new Reflections(
                    new ConfigurationBuilder()
                        .setUrls(ClasspathHelper.forJavaClassPath())
                );
            System.out.println(ClasspathHelper.forJavaClassPath());
            Set<Class<?>> annotated = reflections.getTypesAnnotatedWith(MC.class);

the output of the classpath show this (the external jar appears in first 
position, show it find it!! but later on the annotated set looks empty:

[file:/C:/Users/juanjo/Desktop/ejemplos.jar, 
file:/C:/Users/juanjo/.m2/repository/xpp3/xpp3_min/1.1.4c/xpp3_min-1.1.4c.jar, 
file:/C:/Users/juanjo/.m2/repository/xml-apis/xml-apis/1.0.b2/xml-apis-1.0.b2.ja
r, file:/C:/Users/juanjo/workspace/Comparator/target/classes/, 
file:/C:/Users/juanjo/.m2/repository/dom4j/dom4j/1.6.1/dom4j-1.6.1.jar, 
file:/C:/Users/juanjo/.m2/repository/com/thoughtworks/xstream/xstream/1.3.1/xstr
eam-1.3.1.jar, 
file:/C:/Users/juanjo/.m2/repository/commons-cli/commons-cli/1.1/commons-cli-1.1
.jar, 
file:/C:/Users/juanjo/.m2/repository/postgresql/postgresql/8.1-408.jdbc3/postgre
sql-8.1-408.jdbc3.jar, 
file:/C:/Users/juanjo/.m2/repository/mysql/mysql-connector-java/5.1.18/mysql-con
nector-java-5.1.18.jar, 
file:/C:/Users/juanjo/.m2/repository/javassist/javassist/3.12.1.GA/javassist-3.1
2.1.GA.jar, file:/C:/Users/juanjo/workspace/Extracter/target/classes/, 
file:/C:/Users/juanjo/.m2/repository/org/reflections/reflections/0.9.7.RC1/refle
ctions-0.9.7.RC1.jar, 
file:/C:/Users/juanjo/workspace/Evolutioner/target/classes/, 
file:/C:/Users/juanjo/.m2/repository/com/google/guava/guava/12.0-rc1/guava-12.0-
rc1.jar, 
file:/C:/Users/juanjo/.m2/repository/com/google/code/findbugs/jsr305/1.3.9/jsr30
5-1.3.9.jar]

Original comment by jjsarr...@gmail.com on 4 Jun 2012 at 9:52

GoogleCodeExporter commented 9 years ago
ok no problem. so the jar exists, being found and contains the classes.
is the MC annotation itself annotated with @Retention(RUNTIME)?

Original comment by ronm...@gmail.com on 4 Jun 2012 at 10:07

GoogleCodeExporter commented 9 years ago
yes it is:

@Retention(RetentionPolicy.RUNTIME)
public @interface MC {
    int Version();
}

Original comment by jjsarr...@gmail.com on 4 Jun 2012 at 10:10

GoogleCodeExporter commented 9 years ago
well dude, you'll probably have to debug it further... or create a reproducible 
code and send it over.

Original comment by ronm...@gmail.com on 4 Jun 2012 at 10:15

GoogleCodeExporter commented 9 years ago
ok this simple code:

public class prueba {

    public static void main(String[] args) throws MalformedURLException {
        Reflections reflections = new Reflections(
                new ConfigurationBuilder()
                    .setUrls(ClasspathHelper.forJavaClassPath())
            );
        System.out.println(ClasspathHelper.forJavaClassPath());
        Set<Class<?>> annotated = reflections.getTypesAnnotatedWith(MC.class);  
        Iterable<File> fsx = Vfs.fromURL(new URL("file:\\C:\\Users\\juanjo\\Desktop\\ejemplos.jar")).getFiles();
        Iterator<File> test = fsx.iterator();
        while (test.hasNext()) {
            System.out.println(test.next());
        }

    }
}

generates this error:

Exception in thread "main" java.lang.NoClassDefFoundError: 
com/google/common/base/Predicate
    at prueba.main(prueba.java:16)
Caused by: java.lang.ClassNotFoundException: com.google.common.base.Predicate
    at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
    ... 1 more

using this version downloaded from maven:

      <dependency>
            <groupId>org.reflections</groupId>
            <artifactId>reflections</artifactId>
            <version>0.9.5</version>
    </dependency>

what is happening?

Original comment by jjsarr...@gmail.com on 4 Jun 2012 at 1:08

GoogleCodeExporter commented 9 years ago
what is happening is that you're dude not updated and not reading documentation 
and not googling for an exception. :) dig-in. I'll be happy to help further via 
my email. after you switch to intellij.

Original comment by ronm...@gmail.com on 4 Jun 2012 at 1:31

GoogleCodeExporter commented 9 years ago
don't be so rude...I tried diferent versions of the code. Using 
      <dependency>
            <groupId>org.reflections</groupId>
            <artifactId>reflections</artifactId>
            <version>0.9.8</version>
    </dependency>

the error disappear, but still it doesn`t find the jars...I'm developing 
eclipse plugins and I can't change to anything else.

Original comment by jjsarr...@gmail.com on 4 Jun 2012 at 1:39

GoogleCodeExporter commented 9 years ago
not rude :) I'll be glad to help. the best is to debug into Reflections and see 
what is happening in scan(), than how Store is populated. kindly provide more 
info as discussed above.

Original comment by ronm...@gmail.com on 4 Jun 2012 at 2:22

GoogleCodeExporter commented 9 years ago
what happens in scan? it works at first, and it finds the classes on the 
external jar and add them to the store...but later on it start loading other 
things on the store (all of them like com.google.*) and its looks like my 
classes are overwrited or deleted.
But this is only if the classes are on an external file, if they are in the 
project the behaviour on debug is the same, they seem to be overwrited but 
later on when I use

Set<Class<?>> annotated = reflections.getTypesAnnotatedWith(MC.class);  

the set is not empty, but in the case of the external jar it is empty.

any ideas?

Original comment by jjsarr...@gmail.com on 4 Jun 2012 at 4:10

GoogleCodeExporter commented 9 years ago
ok. so first try to limit the urls for scanning - forJavaClassPath() is too 
broad for anything. try using ClasspathHelper.forPackage("some.thing") so that 
you'll hit only the relevant jars. that should solve the overriden classes as 
well (which sounds strange to me). 
now let's see what REALLY happens in the scan() and Store without all the 
'noise', in both cases external jar and in project.

Original comment by ronm...@gmail.com on 4 Jun 2012 at 7:49

GoogleCodeExporter commented 9 years ago
the only thing I need to know is how reference the package that is on an 
external jar...

the jar is called ejemplos.jar and inside have a package called examples, and 
inside are the *.class files.

I have tried tryng:

ClasspathHelper.forPackage(examples)
ClasspathHelper.forPackage(ejemplos.jar/examples)
ClasspathHelper.forPackage(ejemplos/examples)

etc and so on but none works. Again if the I move the package to my project 
instead of using the jar it recognizes the package name perfectly.

Original comment by jjsarr...@gmail.com on 4 Jun 2012 at 8:34

GoogleCodeExporter commented 9 years ago
that's strange. in comment 4 you printed out the contents of the jar

C:\Users\juanjo\Desktop\ejemplos.jar!\META-INF/MANIFEST.MF
C:\Users\juanjo\Desktop\ejemplos.jar!\AddTable.class
C:\Users\juanjo\Desktop\ejemplos.jar!\AddTable.java

and there is no examples package there. therefore you can't locate it using 
ClasspathHelper.forPackage("examples") nor 
classLoader.getResources("examples"). 
solutions for that:
1) use good fqns (fully qualified name). fqns are important in many ways, and 
also for that matter.
2) otherwise you can add a marker file, such as "META-INF/microchange/<empty>" 
so these urls can be found using forPackage. 
3) if you're not taking this approach, just add the url manually to the 
configuration using ConfigurationBuilder#addUrl(...)
4) (OPTIONAL) another thing to take in account is that if you're adding jars at 
runtime AND using your classloader, you should configure it as well in the 
configuration (see javadoc). 

as a result of fixing this, the urls should be found, scanned and Store object 
should be populated properly. 
please examine the Store by debug or something and make sure it's ok. than we 
can continue.

Original comment by ronm...@gmail.com on 5 Jun 2012 at 6:54

GoogleCodeExporter commented 9 years ago
ok now I tried:

ConfigurationBuilder config = new ConfigurationBuilder();
config.addUrls(new URL("file:\\C:\\Users\\juanjo\\Desktop\\ejemplos.jar"));     
Reflections reflections = new Reflections(config);
Set<Class<?>> annotated = reflections.getTypesAnnotatedWith(MC.class);  

and the store is populated, but the next instruction don't work. It doesn't 
recognize the MC.class annotation...I added the MC class to the external jar 
but still don't work. This is the MC class:

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
public @interface MC {
    int Version();
}

and I use it like this in the external jar:

@MC(Version=2) 

any ideas?

Original comment by jjsarr...@gmail.com on 5 Jun 2012 at 8:29

GoogleCodeExporter commented 9 years ago
what id "doesn't work"? exception? 
please see option 4 in the previous comment.

Original comment by ronm...@gmail.com on 5 Jun 2012 at 10:39

GoogleCodeExporter commented 9 years ago
No exceptions and no error are shown....I'm not using any ClassLoader, just the 
default one. Do I really need to create a special ClassLoader to load a jar as 
simple as this:

@MC(Version=1)
public class AddTable implements Microchange{

    public void executeMicrochange(Connection con) throws SQLException {

        PreparedStatement st = con.prepareStatement("CREATE TABLE cuartel(ID_cuartel int,nombre char(50),PRIMARY KEY (ID_cuartel));");
        st.execute();
    }

    public void verifyMicrochange(DBparameters dbparam, Connection con, Connection conTest) throws SQLException, IOException,
            InterruptedException {

        DatabaseMetaData dbmd = conTest.getMetaData();
        ResultSet rsGetTableNames = dbmd.getTables(conTest.getCatalog(),null, null, new String[] {"TABLE"});
        while (rsGetTableNames.next()) {
            if (rsGetTableNames.getString("TABLE_NAME").equalsIgnoreCase("CUARTEL")) {
                System.out.println("Cuartel table loaded");
            }
        }   
    }

    public static void main(String[] args) {    
        MicrochangeCreator.execMicrochange(new SplitTable());
    }

}

Original comment by jjsarr...@gmail.com on 5 Jun 2012 at 10:49

GoogleCodeExporter commented 9 years ago
no, you don't really need to create a special ClassLoader. and you should not 
add MC.class to the external jar.

so:
is the store populated ok?
is the query compiles and does not throw any exception 
(reflections.getTypesAnnotated...)?
is the result of the query is an empty set?
what is the result of MC.class.getNames()?
what are the relevant keys you get in 
reflections.getStore().get(TypeAnnotationsScanner.class)?

Original comment by ronm...@gmail.com on 5 Jun 2012 at 11:21

GoogleCodeExporter commented 9 years ago
2.- the query compiles and executes with no errors.
3.- The result is an empty set
4.- Mc.class returns com.evolutioner.framework.MC (correct)
5.- reflections.getStore().get(TypeAnnotationsScanner.class returns NOTHING. 
maybe thats the problem

This is the content of the store:

{TypesScanner={com.evolutioner.microchange.AddFK=[com.evolutioner.microchange.Ad
dFK], 
com.evolutioner.microchange.AddTable=[com.evolutioner.microchange.AddTable], 
com.evolutioner.microchange.SplitTable=[com.evolutioner.microchange.SplitTable],

com.evolutioner.microchange.Microchange=[com.evolutioner.microchange.Microchange
]}, 
TypeElementsScanner={com.evolutioner.microchange.AddFK=[verifyMicrochange(DBpara
meters, java.sql.Connection, java.sql.Connection), main(java.lang.String[]), 
executeMicrochange(java.sql.Connection), <init>()], 
com.evolutioner.microchange.AddTable=[verifyMicrochange(DBparameters, 
java.sql.Connection, java.sql.Connection), main(java.lang.String[]), 
executeMicrochange(java.sql.Connection), <init>()], 
com.evolutioner.microchange.SplitTable=[verifyMicrochange(DBparameters, 
java.sql.Connection, java.sql.Connection), main(java.lang.String[]), 
executeMicrochange(java.sql.Connection), <init>()], 
com.evolutioner.microchange.Microchange=[verifyMicrochange(DBparameters, 
java.sql.Connection, java.sql.Connection), 
executeMicrochange(java.sql.Connection)

Original comment by jjsarr...@gmail.com on 5 Jun 2012 at 1:10

GoogleCodeExporter commented 9 years ago
[deleted comment]
GoogleCodeExporter commented 9 years ago
when using ClassPathHelper.forJavaClasspath() the method 
reflections.getStore().get(TypeAnnotationsScanner.class returns this (see file 
attached)

Original comment by jjsarr...@gmail.com on 5 Jun 2012 at 1:24

Attachments:

GoogleCodeExporter commented 9 years ago
do you have any idea why the scanners are TypesScanner and TypeElementsScanner, 
and not the default one?

Original comment by ronm...@gmail.com on 5 Jun 2012 at 1:55

GoogleCodeExporter commented 9 years ago
No, i don´t have any idea...:( but typeAnnotationsScanner should find my 
annotation.

this other commands returns null:

            System.out.println(reflections.getStore().get(TypeElementsScanner.class))
System.out.println(reflections.getStore().get(TypesScanner.class));

Original comment by jjsarr...@gmail.com on 5 Jun 2012 at 2:01

GoogleCodeExporter commented 9 years ago
please recheck your code:
do you have any idea why the scanners are TypesScanner and TypeElementsScanner, 
and not the default one?

Original comment by ronm...@gmail.com on 5 Jun 2012 at 2:04

GoogleCodeExporter commented 9 years ago
this is all reflections code.Is there anything wrong?

 ConfigurationBuilder config = new ConfigurationBuilder();
            config.addUrls(new URL("file:\\C:\\Users\\juanjo\\Desktop\\ejemplos.jar"));     
            Reflections reflections = new Reflections(config);
           /* Reflections reflections = new Reflections(ClasspathHelper.forJavaClassPath());*/
            Set<Class<?>> annotated = reflections.getTypesAnnotatedWith(MC.class);  
            System.out.println(MC.class.getName());
            System.out.println(reflections.getStore().get(TypeAnnotationsScanner.class));
         System.out.println(reflections.getStore().get(TypeElementsScanner.class));
            System.out.println(reflections.getStore().get(TypesScanner.class));

the output is :

com.evolutioner.framework.MC
{}
null
null

Original comment by jjsarr...@gmail.com on 5 Jun 2012 at 2:17

GoogleCodeExporter commented 9 years ago
sorry dude, I can't help you. your answers are not consistent. sorry.

Original comment by ronm...@gmail.com on 5 Jun 2012 at 3:35

GoogleCodeExporter commented 9 years ago
I am facing a similar issue. I am loading the jar at runtime at the command 
prompt. I want to use reflections to get subtypes of a class from this 
externally loaded jar. Could you please help? Please let me know what kind of 
details you need.

ConfigurationBuilder config = new ConfigurationBuilder();

            config.addUrls(new File(jarFiles[0]).toURI().toURL()).addScanners(new SubTypesScanner(false));
            Reflections reflections = new Reflections(config);
            Set<Class<? extends GeneratedMessage>> annotated = reflections
                    .getSubTypesOf(com.google.protobuf.GeneratedMessage.class);

I also tried this to test the URLs version of the Reflections constructor. 
Here, jarFiles[] is the list of JARs user enters at the command prompt. I have 
included jarFiles[0] just for testing. In regular setting, I'll be looping 
though the elements:
Reflections reflectionsProtobuffSerializer = new 
Reflections(jarFiles[0].replaceFirst(".jar", ""));

Original comment by desai.di...@gmail.com on 16 Feb 2013 at 3:09

GoogleCodeExporter commented 9 years ago
[deleted comment]
GoogleCodeExporter commented 9 years ago
Maybe this could come in handy... 
http://stackoverflow.com/questions/8339845/reflections-library-not-working-when-
used-in-an-eclipse-plug-in

Original comment by cebb...@gmail.com on 12 Sep 2014 at 8:16