'Android: Load implementations of interface across libraries using Guava

I want to collect all implementations of concrete interface in my Android application. I've got something like this:

            List<T> list = ClassPath.from(ClassLoader.getSystemClassLoader())
                    .getTopLevelClasses(Reflection.getPackageName(parent))
                    .stream()
                    .map(ClassPath.ClassInfo::load)
                    .filter(current -> isImplementation(parent, current))
                    .map(aClass -> (T) aClass)
                    .collect(Collectors.toList());

but It always return 0 classes. Even if I want to retrieve all classes:

ClassPath.from(ClassLoader.getSystemClassLoader())
                    .getAllClasses()
                    .stream()
                    .map(ClassPath.ClassInfo::load)
                    .collect(Collectors.toList());

It's always zero. When I run it locally from my library in unit test it's ok. Probably, it's problem with ClassLoader. It doesn't provide informations about all packages provided by application.

I don't want to use DexFile because it's deprecated . There's no other information about entries() replacement function.

Is there any possibility to work around this?



Solution 1:[1]

TLDR:

You can use dagger dependency (or newer, hilt) to install components into one domain, such as SingletonComponent and inject it as constructor parameter by implementation. You can even inject multiple implementations as set.

Real answer:

I have created library common and test. Those libraries are pinned in my application.

  1. In common module you can create any interface, like:
public interface Item {
}
  1. Set dependency common to test. Reload dependencies. Now you can see Item in your test library. Write custom class that implements interface:
public class CustomItem implements Item{

//...

}
  1. Create module in your test library:
@Module
@InstallIn(SingletonComponent.class)
public class TestModule {

    @Provides
    @Singleton
    @IntoSet
    public Item customItem() {
        return new CustomItem();
    }

}
  1. Set dependency common and test in application and add module with set of your implementations:
@Module
@InstallIn(SingletonComponent.class)
public class ApplicationSingletonModule {

    @Provides
    @Singleton
    public CustomClassProvider customClassProvider(Set<Item> items) {
        return new CustomClassProvider(items);
    }
}

You can add multiple Item implementations and inject it across libraries without any problem.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 KurdTt-