2012-01-26 12 views
11

Lo que trato de hacer es escribir algunos plugins Maven que escaneen las clases de aplicaciones buscando la implementación de una interfaz en particular (pueden ser clases con alguna anotación también) y base en el resultado generando algún código. Implementé correctamente el complemento que se ejecuta en la fase de generación de fuentes y escribí el código fuente en el directorio de fuentes generadas.explorando el classpath de Java en el plugin maven

El problema está en escanear classpath para las implementaciones/clases de interfaz particulares con alguna anotación. estoy usando la biblioteca Reflections para escanear las clases de la siguiente manera:

private Set<Class< ? extends MyInterface >> scan(final String packageName) { 
    final Reflections reflections = new Reflections(packageName); 
    return reflections.getSubTypesOf(MyInterface.class); 
} 

Desafortunadamente, este método devuelve conjunto vacío. Cuando imprimo mi ruta de clase de la clase que se extiende org.apache.maven.plugin.AbstractMojo (el mismo en el que estoy usando Reflections) me sale el siguiente resultado:

/home/pd5108/apache-maven-2.2.1/boot/classworlds- 1.1.jar

Las clases que quiero encontrar utilizando Reflections existen tanto en los JAR como en el módulo dentro del cual se configura el complemento. Al observar el classpath impreso, parece que en este momento (fase generate-sources) las dependencias definidas en maven no están disponibles aún en classpath, probablemente se agreguen en las siguientes fases. ¿Es eso cierto? ¿Hay algún otro enfoque que pueda usar?

Aquí es la forma en cómo se imprime ruta de clases:

URL[] urls = ((URLClassLoader)sysClassLoader).getURLs(); 

for(int i=0; i< urls.length; i++) { 
    System.out.println(urls[i].getFile()); 
} 

Respuesta

5

campos de clase requeridos MOJO:

/** 
    * The project currently being built. 
    * 
    * @parameter expression="${project}" 
    * @readonly 
    * @required 
    */ 
    private MavenProject project; 

    /** @parameter expression="${localRepository}" */ 
    protected ArtifactRepository m_localRepository; 

    /**@parameter default-value="${localRepository}" */ 
    private org.apache.maven.artifact.repository.ArtifactRepository 
     localRepository; 

    /** @parameter default-value="${project.remoteArtifactRepositories}" */ 
    private java.util.List remoteRepositories; 

    /** @component */ 
    private org.apache.maven.artifact.factory.ArtifactFactory artifactFactory; 

    /** @component */ 
    private org.apache.maven.artifact.resolver.ArtifactResolver resolver; 

resolución de todas las dependencias JAR:

final List<Dependency> dependencies = project.getDependencies(); 

    for (Dependency d : dependencies) { 

     final Artifact artifact = 
      artifactFactory.createArtifactWithClassifier(d.getGroupId(), 
       d.getArtifactId(), d.getVersion(), d.getType(), 
       d.getClassifier()); 

     try { 
      resolver.resolve(artifact, remoteRepositories, 
        localRepository); 
     } catch (ArtifactResolutionException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } catch (ArtifactNotFoundException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 

     File artifactFile = artifact.getFile(); 
     System.out.println(artifactFile.getAbsolutePath()); 
    } 

Y ahora tenemos que analizar estos JAR utilizando la API de reflexión en busca de las clases apropiadas. En este punto, creo que no hay otra manera, dado que trabajo en generate-sources, los valores de fase y artefactos para las siguientes fases aún no se han calculado.

-2

podría ser más rápida/más seguro/más fácil tener sólo la lista de plugins de configuración de las clases que desea generar código basado en. Luego, simplemente agrégalo al pom y listo. No se necesita reflexión, y ciertamente aceleraría el funcionamiento del plugin.

+0

Es la opción que considero un último recurso ... Como tengo muchas clases implementando esta interfaz y todas ellas se consideran en la generación de código, me gustaría evitar escribirlas "estáticamente". Además, estas clases se agregan/eliminan con frecuencia. –

+0

Siempre podría tener un script de shell que hizo algo así como grep todos los archivos java para "implementa X" y luego analizar los nombres de clase y crear un archivo de propiedades de ellos. Luego, haga que su complemento use ese archivo de propiedades para saber a qué clases generar código extra también. Si no estás en Unix, podrías emular el grep en Java, supongo, pero sería mucho más lento. – Michael

1

Existen dependencias de artefactos definidas en la sección <dependencies> y dependencias de complementos definidas en <plugin><dependencies>.

Las dependencias del complemento se agregan a classpath, aunque no estoy seguro acerca de las dependencias del artefacto. ¿Intentó agregar las dependencias de su complemento en el <plugin><dependencies>?

+0

De acuerdo con su consejo, he agregado una 'dependencia de plugin' y ahora no está visible en el classpath impreso (extraño), ¡pero la biblioteca Reflections detecta las clases que implementan MyInterface correctamente! ¿Hay alguna forma de que pueda incluir dependencias de artefactos en dependencias de plugins? Me encantaría evitar copiar y pegar toda la sección:/ –

+1

@PiotrekDe Tal vez pueda crear un proyecto jar con todas las dependencias necesarias que usaría como dependencia tanto para el POM como para el complemento. Aunque no estoy seguro de que valga la pena ... –

Cuestiones relacionadas