reflections icon indicating copy to clipboard operation
reflections copied to clipboard

reflections works on Android?

Open avurro opened this issue 8 years ago • 19 comments

Hi guys,

I wanted to know if this library works on Android.

Thank you in advance

avurro avatar Mar 11 '16 07:03 avurro

same question here

christophetd avatar May 13 '16 11:05 christophetd

Hy, I tried to use in in my app. Here is the code:


public List<String> getAllInterfaces() throws IllegalAccessException, InstantiationException {
    List<String> retVal = new ArrayList<>();
    Reflections reflections = new Reflections("Engines");
    Set<Class<? extends AbstractEngine>> allEngines = reflections.getSubTypesOf(AbstractEngine.class);
    for(Class<? extends AbstractEngine> c : allEngines){            
          AbstractEngine t =   c.newInstance();              
          retVal.add(t.getProviderName());            
    }
    return retVal;
}

Unfortunately it didn't work. When I test it in my unit-tests it works. Do you have any idea why it doesn't work?

xandi1987 avatar May 16 '16 10:05 xandi1987

I made a few tests and couldn't get it working. My assumption is that it cannot work on Android due to the way classes are loaded, which is different than on a standard JVM setup.

christophetd avatar May 16 '16 10:05 christophetd

Do you know any workarounds?

xandi1987 avatar May 16 '16 10:05 xandi1987

I switched to using Gradle at build time to do what I needed, but I didn't find any workaround to use reflections. Would be interested if someone finds one, though.

christophetd avatar May 16 '16 10:05 christophetd

@christophetd , not sure if that what you've ment, but one solution/workaround is to generate xml on build time, then let Reflections collect it on bootstrap. see here

ronmamo avatar May 17 '16 12:05 ronmamo

@ronmamo Considering this is still open, is there any specific gradle config that can be used to generate the classes at compile time using Reflections().save(). My current way doesn't work and i'm struggling to get it to play ball, any chance of some pointers/example gradle configuration?

zackpollard avatar Jan 21 '17 12:01 zackpollard

@ronmamo, thank you for the Reflections library. I have tried to integrate it into my Android project using several sources of information and I am running into the same problem. I also have to admit I am not a gradle (or maven) expert so this may be more difficult for me to understand.

Your answer on generating a xml file on build and letting Reflections collecting it on "bootstrap" seems to be the way to go, however I seem unable to find the way to actually do this. Your link explains the general possibility and the reflections-maven repository gives a maven example. With the help of stackoverflow, I have tried to convert the maven example to grade. But it does not actually work. What does "at boostrap" actually mean specifically as refering to project / java files? Where do I insert

Reflections reflections = Reflections.collect() ?

Does this need to go into a special file or can I use this at any point in my code (this is what I am currently doing)?

From several stackoverflow posts and your git readme files, I have come up with this for now:

build.gradle (Module:app):

[...]
dependencies {
[...]
    compile 'org.reflections:reflections:0.9.11'
}

build.gradle (Project: MyProject):

buildscript {
    repositories {
        jcenter()
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.3'
        classpath 'org.reflections:reflections:0.9.11'
    }
}

allprojects {
    repositories {
        jcenter()
    }
}

task runReflections {
    doLast {
        org.reflections.Reflections("f.q.n").save("${sourceSet.main.output.classesDir}/META-INF/reflections/myproject-reflections.xml")
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

And later on in my code (this class is reached at some point through user input, not loaded on app start):

Reflections reflections = Reflections.collect(); 
Set<Class<? extends MyInterface>> allClasses = reflections.getSubTypesOf(MyInterface.class);

This generates the following exception since "reflections" is not instantiated and has the value of "null": Attempt to invoke virtual method 'java.util.Set org.reflections.Reflections.getSubTypesOf(java.lang.Class)' on a null object reference

I understand that the generated .xml file resides on the computer where the build is happening, and I am not sure if this is also transferred to the android device so my guess is that is why this fails. But at what point does my Java code have access to this file before the apk is transferred and run on my android device?

I have tried googling this in many different ways from different angles but I cannot seem to find a solution to make reflections work in Android. I understand the principle explained here and it seems better to generate the information in an xml file at build time to have the class information available at runtime. But how can I set this up properly?

Thank you, Joe

joe15000 avatar Jul 16 '17 15:07 joe15000

Anyone succeed in executing Reflections on Android ? (via Gradle or not)

I'm using the last version of Reflections library : 0.9.11

Here is what I added in my app/build.gradle in order to generate the json file:

afterEvaluate {
        android.applicationVariants.each { variant ->
            if (variant.productFlavors.find { it.name == 'a' } != null) {
                variant.javaCompiler.doLast {
                    def collection = files { variant.javaCompiler.destinationDir.listFiles() }
                    URL[] urls = collection.collect {
                        it.toURI().toURL()
                    }
                    ClassLoader classLoader = new URLClassLoader(urls, ClassLoader.systemClassLoader)
                    org.reflections.Configuration config = org.reflections.util.ConfigurationBuilder
                            .build("my.package") // my.package just for the example of course
                            .addClassLoader(classLoader)
                            .setUrls(urls)
                    org.reflections.Reflections reflections = new org.reflections.Reflections(config)
                    reflections.save("${variant.javaCompiler.destinationDir}/META-INF/reflections/usecases-reflections.json",
                            new org.reflections.serializers.JsonSerializer())
                }
            }
        }
    }

The json file is created into the ...app/build/intermediates/classes/a/debug/META-INF/reflections/ folder but doesn't contain the scanned classes.

Here is the generated json file content:

{
  "store": {
    "storeMap": {
      "SubTypesScanner": {},
      "TypeAnnotationsScanner": {}
    }
  }
}

With the default Scanner, it should work @ronmamo right ?

Thank you.

almighty972 avatar Feb 21 '18 14:02 almighty972

Finally, I got it working (the gradle task part) but at runtime the Reflections library doesn't work, because of Android dex format, I guess.

almighty972 avatar Feb 26 '18 10:02 almighty972

Has anyone been able to get this working?

crunchy234 avatar Jun 29 '18 05:06 crunchy234

I am looking for something that can run on android, sad.

ted-dev-42 avatar Mar 16 '19 09:03 ted-dev-42

+1

NoahNyy avatar Apr 13 '19 03:04 NoahNyy

My use case is not specific to Android. However, there is a plugin that can be used to generate the XML file at compile time: https://github.com/manosbatsis/gradle-reflections-plugin

I changed the default params in the build script via

import org.reflections.scanners.MethodAnnotationsScanner
import org.reflections.scanners.SubTypesScanner

reflectionsConfig.params = [ new SubTypesScanner(), new MethodAnnotationsScanner() ]

and also ended up having to not use the default Reflections.collect() since for some reason this entire project is just super inconsistent for me. Instead I manually parsed the file via

// Use protected constructor via a reflection utility
Reflection reflections = newInstance(findConstructor(Reflections.class));
XmlSerializer serializer = new XmlSerializer();
URL resource = this.getClassLoader().getResource("META-INF/reflections/ProjectName-reflections.xml");
checkNotNull(resource);
try (InputStream inputStream = resource.openConnection().getInputStream()) {
    reflections.merge(serializer.read(inputStream));
} catch (IOException e) {
    Logger.severe(e);
}

Not sure if this will help anyone, but perhaps.

Andavin avatar Apr 26 '19 15:04 Andavin

My use case is not specific to Android. However, there is a plugin that can be used to generate the XML file at compile time: https://github.com/manosbatsis/gradle-reflections-plugin

I changed the default params in the build script via

import org.reflections.scanners.MethodAnnotationsScanner
import org.reflections.scanners.SubTypesScanner

reflectionsConfig.params = [ new SubTypesScanner(), new MethodAnnotationsScanner() ]

and also ended up having to not use the default Reflections.collect() since for some reason this entire project is just super inconsistent for me. Instead I manually parsed the file via

// Use protected constructor via a reflection utility
Reflection reflections = newInstance(findConstructor(Reflections.class));
XmlSerializer serializer = new XmlSerializer();
URL resource = this.getClassLoader().getResource("META-INF/reflections/ProjectName-reflections.xml");
checkNotNull(resource);
try (InputStream inputStream = resource.openConnection().getInputStream()) {
    reflections.merge(serializer.read(inputStream));
} catch (IOException e) {
    Logger.severe(e);
}

Not sure if this will help anyone, but perhaps.

How did you get the gradle plugin working with the android plugin? Android plugin is not compatible with the java plugin, so you can't access the 'classes' and 'jar' tasks.

nabellows avatar Oct 15 '19 20:10 nabellows

Sadly i have no experience in android builds. That said, any contribution to https://github.com/manosbatsis/gradle-reflections-plugin/issues/5 is welcome if it can be useful.

manosbatsis avatar Sep 07 '20 21:09 manosbatsis

It works if you downgrade to 0.9.11

Heath123 avatar Nov 21 '20 16:11 Heath123

It works if you downgrade to 0.9.11

Are u sure ? Is it work in android ?

Dev-AliGhasemi avatar Apr 16 '21 11:04 Dev-AliGhasemi

version 0.9.11 compiled fine ! but can not fetch classes with specific annotation . this is my code :

package com.jira; public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Reflections reflections = new Reflections("com.jira", new SubTypesScanner(false), new TypeAnnotationsScanner());
    Log.e("anot", reflections.getTypesAnnotatedWith(Test.class).size() + "");
}

} `

Dev-AliGhasemi avatar Apr 16 '21 11:04 Dev-AliGhasemi