package com.fitbank.autoservices; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.Collection; import java.util.LinkedList; import java.util.regex.Pattern; import org.apache.maven.artifact.DependencyResolutionRequiredException; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.project.MavenProject; import static org.apache.maven.plugins.annotations.LifecyclePhase.PROCESS_CLASSES; import static org.apache.maven.plugins.annotations.ResolutionScope.COMPILE; /** * Genera los archivos META-INF/services/* para los interfaces especificados. */ @Mojo(name = "generate", defaultPhase = PROCESS_CLASSES, threadSafe = true, requiresDependencyResolution = COMPILE) public class AutoServicesMojo extends AbstractMojo { /** * Output */ @Parameter(defaultValue = "${project.build.outputDirectory}") private File outputDirectory; /** * Clases o interfaces de los que se buscarĂ¡ las subclases. */ @Parameter private String[] classes; /** * The Maven project. */ @Parameter(defaultValue = "${project}", readonly = true) private MavenProject project; public void execute() throws MojoExecutionException { File services = new File(outputDirectory, "META-INF/services"); if (!services.exists()) { services.mkdirs(); } for (String serviceClassName : classes) { URLClassLoader dcl; try { Collection urls = new LinkedList(); for (Object s : project.getCompileClasspathElements()) { urls.add(new File((String) s).toURI().toURL()); } urls.add(outputDirectory.toURI().toURL()); dcl = new URLClassLoader(urls.toArray(new URL[urls.size()])); } catch (MalformedURLException e) { throw new MojoExecutionException("Cannot load classpath", e); } catch (DependencyResolutionRequiredException e) { throw new MojoExecutionException("Cannot load classpath", e); } Class base; try { base = dcl.loadClass(serviceClassName); } catch (ClassNotFoundException e) { throw new MojoExecutionException("Cannot load class " + serviceClassName, e); } File service = new File(services, serviceClassName); FileWriter w = null; try { w = new FileWriter(service); getLog().info( "Buscando subclases para " + base.getName() + " en " + outputDirectory); for (String className : getClassNames(outputDirectory, outputDirectory)) { try { Class clase = dcl.loadClass(className); if (base.isAssignableFrom(clase) && !base.equals(clase)) { getLog().info("Encontrado " + clase.getName()); w.write(clase.getName() + "\n"); } } catch (ClassNotFoundException e) { throw new MojoExecutionException("Cannot load class " + className, e); } } } catch (IOException e) { throw new MojoExecutionException("Error creating file " + service, e); } finally { if (w != null) { try { w.close(); } catch (IOException e) { // ignore } } } } } private Collection getClassNames(File start, File parent) { Collection classNames = new LinkedList(); for (File f : parent.listFiles()) { if (f.isDirectory()) { classNames.addAll(getClassNames(start, f)); } else if (f.getName().endsWith(".class") && !f.getName().matches("\\$.*\\.class")) { classNames.add(f.getAbsolutePath().replace( start.getAbsolutePath(), "").replaceAll(".class$", "") .replaceAll(Pattern.quote(File.separator), ".") .substring(1)); } } return classNames; } }