import java.util.concurrent.Callable
apply plugin: SourceGenerationPlugin
/**
* A plugin for dealing with AnnotationProcessor-based source generation.
*
* Creates (or reuses) a grouping task named `generateSources` which is responsible
* for coordinating (via task deps) the running of all source-generation tasks.
*
* Additionally a grouping task is created for each SourceSet to hold the generation
* task for that SourceSet. This task is named following the `run{SourceSet.name}SourceGenerators`.
* This task is also injected into the SourceSet as `sourceGeneratorsTask` for scripts to access
*/
class SourceGenerationPlugin implements Plugin {
public static final String GROUP = "sourceGeneration";
public static final String GENERATE_SOURCES_TASK_NAME = "generateSources";
@Override
public void apply(Project project) {
final JavaPluginConvention javaPluginConvention = project.getConvention().findPlugin( JavaPluginConvention.class );
if ( javaPluginConvention == null ) {
// something seriously awry
return;
}
project.convention.plugins[GROUP] = new SourceGenerationPluginConvention( project );
// first set up the overall generateSources task
Task generateSourcesTask = project.getTasks().findByName( GENERATE_SOURCES_TASK_NAME );
if ( generateSourcesTask == null ) {
generateSourcesTask = project.getTasks().create( GENERATE_SOURCES_TASK_NAME );
generateSourcesTask.setGroup( GROUP );
generateSourcesTask.setDescription( "Grouping task for all source generation tasks" );
}
// for each source set, define the specific grouping tasks (and associate with the generateSources as a
// task dependency)
for ( SourceSet sourceSet : javaPluginConvention.getSourceSets() ) {
final ExtraPropertiesExtension extProps = ( (ExtensionAware) sourceSet ).getExtensions().getExtraProperties();
// find the main javac task for this sourceSet (so we can add dependsOn to it)
final JavaCompile javaCompileTask = (JavaCompile) project.getTasks().getByName( sourceSet.getCompileJavaTaskName() );
// create the pre-apt generation grouping task
final String sourceGeneratorsTaskName = sourceSet.getTaskName( "run", "sourceGenerators" );
final Task sourceGeneratorsTask = project.getTasks().create( sourceGeneratorsTaskName );
sourceGeneratorsTask.setGroup( GROUP );
sourceGeneratorsTask.setDescription(
String.format(
"Grouping task for running all source generation tasks for the %s source-set of the %s project",
sourceSet.getName(),
project.getName()
)
);
generateSourcesTask.dependsOn( sourceGeneratorsTask );
javaCompileTask.dependsOn( sourceGeneratorsTask );
final File aptDir = new File( new File( project.getBuildDir(), "generated-src/apt" ), sourceSet.name );
javaCompileTask.options.compilerArgs += [ "-s", aptDir.absolutePath ];
javaCompileTask.doFirst({
if ( !aptDir.exists() ) {
if ( !aptDir.mkdirs() ) {
project.logger.warn( "Unable to create APT dir : " + aptDir.absolutePath )
}
}
})
generateSourcesTask.dependsOn( javaCompileTask )
extProps.set( "sourceGeneratorsTask", sourceGeneratorsTask );
extProps.set( "aptDir", aptDir );
}
}
}
class SourceGenerationPluginConvention {
public static final String METAGEN_DEPENDENCY_CONFIG_NAME = "hibernateJpaModelGenTool";
public static final String METAGEN_PROCESSOR_NAME = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor";
private final Project project;
// practicality says we only ever deal with 2 source-sets:
private JavaCompile mainProcOnlyTask;
private JavaCompile testProcOnlyTask;
SourceGenerationPluginConvention(Project project) {
this.project = project
}
/**
* Exposed to the build scripts to be able to apply JPA Metamodel Generation support to the
* SourceSet it specifies.
*
* @param sourceSet The SourceSet to which JPA Metamodel Generation support should be applied.
*/
public void addMetaGenProcessor(SourceSet sourceSet) {
if ( sourceSet.name.equals( "main" ) ) {
if ( mainProcOnlyTask == null ) {
mainProcOnlyTask = generateProcessorOnlyTask( sourceSet )
}
}
else if ( sourceSet.name.equals( "test" ) ) {
if ( testProcOnlyTask == null ) {
testProcOnlyTask = generateProcessorOnlyTask( sourceSet )
}
}
else {
throw new IllegalArgumentException( "SourceSet (" + sourceSet.name + ") not valid for source generation" )
}
}
private JavaCompile generateProcessorOnlyTask(SourceSet sourceSet) {
final File targetDir = sourceSet.aptDir;
// find the main javac task for this sourceSet (we will alter it a bit later on)
final JavaCompile javaCompileTask = (JavaCompile) project.getTasks().getByName( sourceSet.getCompileJavaTaskName() );
final ExtraPropertiesExtension extProps = ( (ExtensionAware) sourceSet ).getExtensions().getExtraProperties();
final String aptTaskName = sourceSet.getTaskName( "run", "annotationProcessors" );
// final AnnotationProcessorOnlyTask aptTask = project.getTasks().create( aptTaskName, AnnotationProcessorOnlyTask.class );
final JavaCompile aptTask = project.getTasks().create( aptTaskName, JavaCompile.class );
aptTask.options.compilerArgs += [
"-nowarn",
"-proc:only",
"-encoding", "UTF-8",
"-s", targetDir.getAbsolutePath(),
"-processor", METAGEN_PROCESSOR_NAME
]
aptTask.setGroup( SourceGenerationPlugin.GROUP );
aptTask.setDescription(
String.format(
"Grouping task for running all AnnotationProcessors (javac -proc:only) for the %s sourceSet of the %s project",
sourceSet.getName(),
project.getName()
)
);
// sourceSet.getAllJava() returns a SourceDirectorySet which is a "live view" meaning it keeps expanding
// even as we add to it. The problem is that later on here we will add the output directory of this task
// to this SourceDirectorySet; we need to make sure that we use the view of the SourceDirectorySet *before* that
// happens as the source for this task. getSrcDirs() does that
aptTask.source( sourceSet.getAllJava() )
aptTask.destinationDir = targetDir
aptTask.setSourceCompatibility( javaCompileTask.getSourceCompatibility() );
aptTask.setTargetCompatibility( javaCompileTask.getTargetCompatibility() );
aptTask.setDependencyCacheDir( javaCompileTask.getDependencyCacheDir() );
aptTask.getConventionMapping().map(
"classpath",
new Callable() {
public FileCollection call() throws Exception {
return javaCompileTask.getClasspath() + project.configurations[METAGEN_DEPENDENCY_CONFIG_NAME]
}
}
);
aptTask.mustRunAfter( extProps.get( "sourceGeneratorsTask" ) );
javaCompileTask.dependsOn( aptTask );
project.tasks.findByName( SourceGenerationPlugin.GENERATE_SOURCES_TASK_NAME ).dependsOn( aptTask )
// Add the APT output dir to the source set
// - so that the generated sources get compiled during main javac
sourceSet.getJava().srcDir( targetDir );
return aptTask
}
}