Implementación de paquetes parecidos a Spring en Android

Estoy intentando implementar una función de escaneo de paquetes, similar a la de component-scan de Spring, para el framework de Android que estoy desarrollando. Básicamente, me gustaría ser capaz de especificar un paquete base, por ejemplo, com.foo.bar y recuperar todas Class instancias de Class que tienen una anotación en particular. No quiero tener que registrar todos los componentes con mi framework, ya que esto podría anular el propósito de la exploración automática.

Basado en mi investigación, parece que no es posible con Java recuperar recursos dados un nombre de paquete usando la reflexión. Sin embargo, miré brevemente el marco de Reflections , y me pregunto si hay un equivalente compatible con Android. Si no, tal vez hay una manera un poco menos obvia de lograr lo que quiero hacer.

Miré un poco la fuente de Spring para ver cómo lograron esto, pero no creo que lo que estén haciendo funcionaría dentro del tiempo de ejecución de Dalvik.

Actualizar

Actualmente, el siguiente código ha sido el mejor que puedo hacer para recuperar todas las clases que contienen una anotación específica, pero francamente es una solución bastante pobre. Hace algunas suposiciones realmente inseguras sobre el ClassLoader y escanea (y carga) todas las clases de aplicación.

 public Set<Class<?>> getClassesWithAnnotation(Class<? extends Annotation> annotation) { Set<Class<?>> classes = new HashSet<Class<?>>(); Field dexField = PathClassLoader.class.getDeclaredField("mDexs"); dexField.setAccessible(true); PathClassLoader classLoader = (PathClassLoader) Thread.currentThread().getContextClassLoader(); DexFile[] dexs = (DexFile[]) dexField.get(classLoader); for (DexFile dex : dexs) { Enumeration<String> entries = dex.entries(); while (entries.hasMoreElements()) { String entry = entries.nextElement(); Class<?> entryClass = dex.loadClass(entry, classLoader); if (entryClass != null && entryClass.isAnnotationPresent(annotation)) { classes.add(entryClass); } } } return classes; } 

Comparto la opinión de Joop Eggen y considero que su enfoque es bueno. En Android intento evitar las características usuales de la aplicación web que conducen a un inicio de aplicación duradero. No utilizo la reflexión ni la exploración de paquetes.

Pero si quieres … si lo entiendo correctamente quieres tener una anotación para una clase. En lugar de utilizar las anotaciones, también puede utilizar las interfaces de marcadores (para tener más posibilidades).

1) Mira

  • Anotación: Anotación personalizada de Java y carga dinámica
    Tiene una implementación en la pregunta que sólo contesta a su pregunta.
  • Anotación: Analizar anotaciones de Java en tiempo de ejecución
  • Interfaz: Buscar clases Java implementando una interfaz
  • Interfaz: ¿Es algo similar a ServiceLoader en Java 1.5?
  • Interfaz: ¿Cómo puedo obtener una lista de todas las implementaciones de una interfaz mediante programación en Java?
  • Interfaz: Ya que el enfoque es costoso, tal vez el ServiceLoader sea ​​un compromiso entre el tiempo de ejecución y el confort, ya que sólo carga las clases dadas en el archivo de servicios. Por otro lado si sólo las clases con una determinada interfaz están en su paquete, entonces el ServiceLoader no es tan rápido.

2) AndroidAnnotations

Preferiría la forma en que funciona AndroidAnnotations (tal vez una integración en AndroidAnnotations es la forma preferible): Añade automáticamente un paso de compilación extra que genera código fuente, utilizando la herramienta de procesamiento de anotaciones Java estándar. Por lo tanto, en lugar del análisis en tiempo de ejecución, ejecuta código basado en las anotaciones generadas durante el tiempo de compilación.

Creo que la anotación Bean / EBean podría funcionar para usted (solo clase individual): https://github.com/excilys/androidannotations/wiki/Enhance%20custom%20classes

Una función de escaneo no está disponible, vea este hilo

3) Escribir su propio procesador de anotación

  • Consulte APT (Herramienta de procesamiento de anotaciones) . La idea sería generar una función estática que devuelva una lista de clases que están anotadas, de modo que no se necesita escanear clases.
  • Un recurso muy bueno es http://javadude.com/articles/annotations/index.html

Quería encontrar toda la subclase en tiempo de ejecución. Así que he estado buscando la exploración de clase de android. Este es mi código final de lo que reuní en la web. Usted recibirá la idea.

 public static void findSubClasses(Context context, Class parent) { ApplicationInfo ai = context.getApplicationInfo(); String classPath = ai.sourceDir; DexFile dex = null; try { dex = new DexFile(classPath); Enumeration<String> apkClassNames = dex.entries(); while (apkClassNames.hasMoreElements()) { String className = apkClassNames.nextElement(); try { Class c = context.getClassLoader().loadClass(className); if (parent.isAssignableFrom(c)) { android.util.Log.i("nora", className); } } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } // android.util.Log.i("nora", className); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { try { dex.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } 

Echa un vistazo a ClassPathScanner de Vogar. Se utiliza para encontrar casos de prueba en la ruta de clase.

EDITAR:

Encontré este problema en el rastreador de problemas de Android. Parece que ClassLoader.getResource(String) está 'trabajando como se esperaba', en que devuelve null . Esto es esperado porque el DalvikVM no mantiene los recursos alrededor después de compilar. Hay soluciones descritas en el problema, pero puede haber otra forma de acceder a las clases que desee.

Utilice PackageManager para obtener una retención de una instancia de ApplicationInfo . ApplicationInfo tiene un campo público llamado sourceDir que es la ruta completa (una String ) a la ubicación del directorio de origen para esa aplicación. Crear un File de esta String , y usted debe ser capaz de navegar a su paquete en el directorio de origen. Una vez allí, puede utilizar el método de mi respuesta original para encontrar las clases que está buscando.

 String applicationSourceDir = getPackageManager().getApplicationInfo(androidPackageName, 0).sourceDir; 

/EDITAR

Debe ser capaz de utilizar ClassLoader.getResource(String) para obtener una URL para su paquete específico (el pasado en String es el nombre del paquete que está interesado en delimitado por separadores de ruta en lugar de puntos). Con esta URL puede llamar a getFile() , desde el cual puede crear un File Java en la carpeta del paquete. Llame a packageFile.listFiles() desde allí, y tiene sus clases / subpaquetes.

Sea recursivo con los subpaquetes y con las clases encuentre el objeto Class utilizando el método Class.forName(String) estático.

En su proceso de creación de java incorporar la ruta de acceso de clase de exploración, la generación de inyección de datos / código. Esto también podría ser portado a Dalvik. Es aún más eficiente que el escaneado dinámico.

  • Android Httpclient
  • Agregar acceso de inicio de sesión social a las aplicaciones nativas mediante oauth de seguridad de primavera
  • El servicio Web devuelve SOAP cuando no se especifica el tipo de contenido
  • ¿Hay algún marco de aplicación de Android como primavera?
  • Oauth 2.0 Android uso Primavera-Para-Android
  • Autenticación de usuario mediante REST
  • Lea el cuerpo de la respuesta en un interceptor de primavera de Android
  • HTTP Status 403 - No válido CSRF Token 'null' se encontró en el parámetro de solicitud
  • Configurar un cliente Stomp en android con el marco de Spring en el lado del servidor
  • Manejo del tiempo de espera con AndroidAnnotations (Spring Rest)
  • Marco ligero de inyección de dependencia para Android
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.