Skip to content Skip to sidebar Skip to footer

How To Integrate The Reflections Library In Android Studio Using Gradle With Save And Collect

My question is related to the Reflections library by @ronmamo on github and integrating this into my Android project to dynamically access all classes that inherit from a certain i

Solution 1:

There's a little bit of a chicken-or-egg problem to solve here

  1. You want Reflections API to access the classes compiled from src/main/java
  2. Gradle tasks and the Reflections classes are loaded by Gradle's buildscript classloader
  3. The classes in src/main/java are compiled after the buildscript classloader is defined

You'll need to introduce another classloader that can access the compiled classes to break the cyclic dependency. This can then be passed to Reflections. Eg:

buildscript {
    classpath 'org.reflections:reflections:0.9.11'
}
task doReflectyStuff {
    dependsOn compileJava
    doLast {
        URL[] urls = sourceSets.main.runtimeClasspath.files.collect {
            it.toURI().toURL()
        }
        ClassLoaderclassLoader=newURLClassLoader(urls, null)
        Configurationconfig=newConfigurationBuilder("com.mypackage", classLoader)
        Reflectionsreflections=newReflectionsBuilder(config)
        ...
    }
}

See here for a similar question

Solution 2:

This is what I did: The task was to use Reflections on Android for classes provided with a dependency (i.e. inside a JAR file). This solution works for me:

top build.gradle:

dependencies {
    classpath 'org.reflections:reflections:0.9.10'
}

project build.gradle:

afterEvaluate {
    android.applicationVariants.each { variant ->
        variant.javaCompiler.doLast {
            // get JAR file that contains the classesdefcollection= project.configurations.compile*.toURI().find { URI uri -> newFile(uri).name.startsWith("startOfJarFileNameHere") }
            URL[] urls = collection.collect {
                println "Collecting classes using Reflections from " + it
                it.toURL()
            }

            // collect all classesClassLoaderclassLoader=newURLClassLoader(urls, ClassLoader.systemClassLoader)
            org.reflections.Configurationconfig= org.reflections.util.ConfigurationBuilder
                    .build("package.name.of.interest.here")
                    .addClassLoader(classLoader)
                    .setUrls(urls)
            org.reflections.Reflectionsreflections=neworg.reflections.Reflections(config)

            // save as JSON file into the assets folder// (a) generate file for current debug or release build
            reflections.save(
                "${variant.javaCompiler.destinationDir}/../../assets/${variant.buildType.name}/reflections/my-reflections.json",
                    neworg.reflections.serializers.JsonSerializer())
            // (b) always update fall-back file for debug (used when running app from Android Studio or IntelliJ)
            reflections.save(
                    "${variant.javaCompiler.destinationDir}/../../../../src/debug/assets/reflections/my-reflections.json",
                    neworg.reflections.serializers.JsonSerializer())
        }
    }
}

Java code on Android:

InputStreamiStream= getAssets().open("reflections/my-reflections.json");
Configurationconfig= ConfigurationBuilder.build().setSerializer(newJsonSerializer());
Reflectionsreflections=newReflections(config);
reflections.collect(iStream);
Set<Class<? extendsMyType>> myTypes = reflections.getSubTypesOf(MyType.class);

Solution 3:

I have been trying to use Reflections in Android for some days and this is what I have achieved so far. I have created a task in project's build.gradle:

task myTask(dependsOn: compileJava) {
    doLast {
        URL[] urls = sourceSets.main.runtimeClasspath.files.collect {
            it.toURI().toURL()
        }
        ClassLoaderclassLoader=newURLClassLoader(urls, ClassLoader.systemClassLoader)
        org.reflections.Configurationconfig=newConfigurationBuilder()
                .addClassLoader(classLoader)
                .filterInputsBy(newFilterBuilder().include(FilterBuilder.prefix("com.company.project")))
                .addScanners(newSubTypesScanner(false))
        Reflectionsreflections=newReflections(config)
        reflections.save("${sourceSets.main.output.classesDirs}/META-INF/reflections/mcommerce-reflections.json", newJsonSerializer())
    }
}

Later on a class from the project I instantiate Reflections just as is done in the GitHub's examples (I use Kotlin):

valreflections= Reflections.collect(
                        "META-INF/reflections",
                        FilterBuilder().include(".*-reflections.json"),
                        JsonSerializer()
                ) 

If myTask is run on the Terminal the build is successful but I get this message "given scan urls are empty. set urls in the configuration", I searched for this in Google but didn't find anything helpful.

I tried different ways of configuring Reflections on the gradle file but when I collect them I always receive a null instance.

I hope my answer is of some use for someone.

Post a Comment for "How To Integrate The Reflections Library In Android Studio Using Gradle With Save And Collect"