diff --git a/hibernate-core/hibernate-core.gradle b/hibernate-core/hibernate-core.gradle index 73a55c3ba0..9047d5c603 100644 --- a/hibernate-core/hibernate-core.gradle +++ b/hibernate-core/hibernate-core.gradle @@ -177,5 +177,5 @@ task jaxb { } -runSourceGenerators.dependsOn jaxb -runSourceGenerators.dependsOn generateGrammarSource +sourceSets.main.sourceGeneratorsTask.dependsOn jaxb +sourceSets.main.sourceGeneratorsTask.dependsOn generateGrammarSource diff --git a/source-generation.gradle b/source-generation.gradle index 1db18efd79..7585e0dc59 100644 --- a/source-generation.gradle +++ b/source-generation.gradle @@ -1,31 +1,19 @@ -import java.nio.charset.Charset import java.util.concurrent.Callable -import javax.tools.Diagnostic -import javax.tools.DiagnosticListener -import javax.tools.JavaCompiler -import javax.tools.JavaFileObject -import javax.tools.StandardJavaFileManager -import javax.tools.ToolProvider - -import org.gradle.api.internal.project.ProjectInternal -import org.gradle.api.internal.tasks.SimpleWorkResult -import org.gradle.api.internal.tasks.compile.CompilationFailedException -import org.gradle.api.internal.tasks.compile.Compiler -import org.gradle.api.internal.tasks.compile.DefaultJavaCompileSpec -import org.gradle.api.internal.tasks.compile.DefaultJavaCompilerFactory -import org.gradle.api.internal.tasks.compile.DelegatingJavaCompiler -import org.gradle.api.internal.tasks.compile.JavaCompileSpec -import org.gradle.api.internal.tasks.compile.JavaCompilerArgumentsBuilder -import org.gradle.api.internal.tasks.compile.JavaCompilerFactory -import org.gradle.api.internal.tasks.compile.daemon.CompilerDaemonManager -import org.gradle.api.internal.tasks.compile.jdk6.Jdk6JavaCompiler -import org.gradle.internal.jvm.Jvm 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 @@ -68,7 +56,20 @@ class SourceGenerationPlugin implements Plugin { 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 ); } } } @@ -80,45 +81,54 @@ class SourceGenerationPluginConvention { private final Project project; // practicality says we only ever deal with 2 source-sets: - private AnnotationProcessorOnlyTask mainProcOnlyTask; - private AnnotationProcessorOnlyTask testProcOnlyTask; + private JavaCompile mainProcOnlyTask; + private JavaCompile testProcOnlyTask; SourceGenerationPluginConvention(Project project) { this.project = project } - private AnnotationProcessorOnlyTask getLocateProcessorOnlyTask(SourceSet sourceSet) { + /** + * 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 ) } - return mainProcOnlyTask; } else if ( sourceSet.name.equals( "test" ) ) { if ( testProcOnlyTask == null ) { testProcOnlyTask = generateProcessorOnlyTask( sourceSet ) } - return testProcOnlyTask; } else { throw new IllegalArgumentException( "SourceSet (" + sourceSet.name + ") not valid for source generation" ) } } - private AnnotationProcessorOnlyTask generateProcessorOnlyTask(SourceSet sourceSet) { + 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(); - // Obtain the output dir reference: generated-src/apt/{sourceSet.name} - final File outputDir = new File( - new File( project.getBuildDir(), "generated-src/apt/" ), - sourceSet.getName() - ); - final String aptTaskName = sourceSet.getTaskName( "run", "annotationProcessors" ); - final AnnotationProcessorOnlyTask aptTask = project.getTasks().create( aptTaskName, AnnotationProcessorOnlyTask.class ); +// 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( @@ -132,10 +142,8 @@ class SourceGenerationPluginConvention { // 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().getSrcDirs() ) - aptTask.destinationDir = outputDir - // again for JBoss Logging... - aptTask.classesDir = outputDir + aptTask.source( sourceSet.getAllJava() ) + aptTask.destinationDir = targetDir aptTask.setSourceCompatibility( javaCompileTask.getSourceCompatibility() ); aptTask.setTargetCompatibility( javaCompileTask.getTargetCompatibility() ); @@ -145,7 +153,7 @@ class SourceGenerationPluginConvention { "classpath", new Callable() { public FileCollection call() throws Exception { - return javaCompileTask.getClasspath() + return javaCompileTask.getClasspath() + project.configurations[METAGEN_DEPENDENCY_CONFIG_NAME] } } ); @@ -154,223 +162,10 @@ class SourceGenerationPluginConvention { javaCompileTask.dependsOn( aptTask ); project.tasks.findByName( SourceGenerationPlugin.GENERATE_SOURCES_TASK_NAME ).dependsOn( aptTask ) - - // create a FileTree representation of the APT output dir and add it to the JavaCompile task (so they get compiled) -// final ConfigurableFileTree outputDirFileTree = project.fileTree( outputDir ); -// outputDirFileTree.builtBy( aptTask ); -// javaCompileTask.getSource().plus( outputDirFileTree ); - // Add the APT output dir to the source set - sourceSet.getJava().srcDir( outputDir ); + // - so that the generated sources get compiled during main javac + sourceSet.getJava().srcDir( targetDir ); return aptTask } - - public void addMetaGenProcessor(SourceSet sourceSet) { - AnnotationProcessorOnlyTask task = getLocateProcessorOnlyTask( sourceSet ) - task.processors += METAGEN_PROCESSOR_NAME - task.classpath += project.configurations[METAGEN_DEPENDENCY_CONFIG_NAME] - } } -class AnnotationProcessorOnlyTask extends AbstractCompile { - @Input - def List processors = new ArrayList(); - // todo : support for this? really only "used" for logging and its use is questionable - //private Map processorSettings = new HashMap(); - - def File dependencyCacheDir; - def File classesDir; - - private Compiler javaCompiler; - - AnnotationProcessorOnlyTask() { - // Stolen from Gradle's Compile/JavaCompile - org.gradle.internal.Factory antBuilderFactory = getServices().getFactory( org.gradle.api.AntBuilder.class ); - JavaCompilerFactory inProcessCompilerFactory = new ExpandedJavaCompilerFactory( getLogger() ); - ProjectInternal projectInternal = (ProjectInternal) getProject(); - CompilerDaemonManager compilerDaemonManager = getServices().get( CompilerDaemonManager.class ); - JavaCompilerFactory defaultCompilerFactory = new DefaultJavaCompilerFactory( - projectInternal, - antBuilderFactory, - inProcessCompilerFactory, - compilerDaemonManager - ); - - // The Gradle IncrementalJavaCompiler cant be used here for various reasons - javaCompiler = new DelegatingJavaCompiler( defaultCompilerFactory ); - } - - @OutputDirectory - public File getDependencyCacheDir() { - return dependencyCacheDir; - } - - public void setDependencyCacheDir(File dependencyCacheDir) { - this.dependencyCacheDir = dependencyCacheDir; - } - - @Override - protected void compile() { - // see if the output dir exists - if ( !getDestinationDir().exists() ) { - // its does not - create it (javac will complain if its not there) - makeDirectory( getDestinationDir() ); - } - else { - // it does - clean it - project.delete( getDestinationDir() ) - makeDirectory( getDestinationDir() ); - } - - if ( !getClassesDir().exists() ) { - // create classes dir if not there (again, javac will complain if its not there) - makeDirectory( getClassesDir() ); - } - - CompileOptions compileOptions = new CompileOptions(); - - Collections.addAll( - compileOptions.getCompilerArgs(), - "-nowarn", - "-proc:only", - "-encoding", "UTF-8", - "-s", getDestinationDir().getAbsolutePath(), - "-processor", processors.join( "," ) - - ); - - DefaultJavaCompileSpec spec = new DefaultJavaCompileSpec(); - spec.setSource( getSource() ); - // jboss logging needs this :( - spec.setDestinationDir( getClassesDir() ); - spec.setClasspath( getClasspath() ); - spec.setDependencyCacheDir( dependencyCacheDir ); - spec.setSourceCompatibility( getSourceCompatibility() ); - spec.setTargetCompatibility( getTargetCompatibility() ); - spec.setCompileOptions( compileOptions ); - - WorkResult result = javaCompiler.execute( spec ); - setDidWork( result.getDidWork() ); - } - - @SuppressWarnings("ResultOfMethodCallIgnored") - private static void makeDirectory(File directory) { - directory.mkdirs(); - } -} - -/** - * Implementation of the Gradle JavaCompilerFactory contract generating {@link ExpandedJdk6JavaCompiler} instances - */ -class ExpandedJavaCompilerFactory implements JavaCompilerFactory { - private final Logger logger; - - public ExpandedJavaCompilerFactory(Logger logger) { - //To change body of created methods use File | Settings | File Templates. - this.logger = logger; - } - - @Override - public Compiler create(CompileOptions options) { - return new ExpandedJdk6JavaCompiler( logger ); - } -} - -/** - * Extension of Gradle's Jdk6JavaCompiler to add DiagnosticListener for diagnostic message mapping and APT support - */ -public class ExpandedJdk6JavaCompiler extends Jdk6JavaCompiler { - private final Logger logger; - - public ExpandedJdk6JavaCompiler(Logger logger) { - this.logger = logger; - } - - public WorkResult execute(JavaCompileSpec spec) { - logger.info( "Compiling with JDK Java compiler API." ); - - final DiagnosticListenerImpl diagnosticListener = new DiagnosticListenerImpl( logger ); - final JavaCompiler.CompilationTask task = createCompileTask( spec, diagnosticListener ); - boolean success = task.call(); - if ( !success || diagnosticListener.sawError() ) { - throw new CompilationFailedException(); - } - - return new SimpleWorkResult( true ); - } - - private static JavaCompiler.CompilationTask createCompileTask( - JavaCompileSpec spec, - DiagnosticListenerImpl diagnosticListener) { - List options = new JavaCompilerArgumentsBuilder(spec).build(); - JavaCompiler compiler = findCompiler(); - if ( compiler == null ) { - throw new RuntimeException("Cannot find System Java Compiler. Ensure that you have installed a JDK (not just a JRE) and configured your JAVA_HOME system variable to point to the according directory."); - } - CompileOptions compileOptions = spec.getCompileOptions(); - StandardJavaFileManager fileManager = compiler.getStandardFileManager( - null, - null, - compileOptions.getEncoding() != null - ? Charset.forName( compileOptions.getEncoding() ) - : null - ); - Iterable compilationUnits = fileManager.getJavaFileObjectsFromFiles(spec.getSource()); - return compiler.getTask(null, null, diagnosticListener, options, null, compilationUnits); - } - - - private static class DiagnosticListenerImpl implements DiagnosticListener { - private final Logger logger; - - public DiagnosticListenerImpl(Logger logger) { - this.logger = logger; - } - - @Override - public void report(Diagnostic diagnostic) { - switch ( diagnostic.getKind() ) { - case Diagnostic.Kind.ERROR: - logger.debug( "[ERROR] : " + diagnostic.toString() ); - break; - case Diagnostic.Kind.WARNING: - logger.debug( "[WARNING] : " + diagnostic.toString() ); - break; - case Diagnostic.Kind.MANDATORY_WARNING: - logger.debug( "[MANDATORY_WARNING] : " + diagnostic.toString() ); - break; - case Diagnostic.Kind.NOTE: - logger.debug( "[NOTE] : " + diagnostic.toString() ); - break; - case Diagnostic.Kind.OTHER: - logger.debug( "[OTHER] : " + diagnostic.toString() ); - break - default: - logger.debug( "[UNKNOWN] : " + diagnostic.toString() ); - break; - } - } - - public boolean sawError() { - // technically ERROR diagnostics should end the compile cycle, but since we are just generating - // sources here we ignore errors for now (expecting the later compilation task to report them - // if still valid) - return false; - } - } - - private static JavaCompiler findCompiler() { - File realJavaHome = Jvm.current().getJavaHome(); - File javaHomeFromToolProvidersPointOfView = new File(System.getProperty("java.home")); - if (realJavaHome.equals(javaHomeFromToolProvidersPointOfView)) { - return ToolProvider.getSystemJavaCompiler(); - } - - System.setProperty("java.home", realJavaHome.getAbsolutePath()); - try { - return ToolProvider.getSystemJavaCompiler(); - } finally { - System.setProperty("java.home", javaHomeFromToolProvidersPointOfView.getAbsolutePath()); - } - } -} diff --git a/tooling/metamodel-generator/hibernate-jpamodelgen.gradle b/tooling/metamodel-generator/hibernate-jpamodelgen.gradle index 5b8258a162..caaed83397 100644 --- a/tooling/metamodel-generator/hibernate-jpamodelgen.gradle +++ b/tooling/metamodel-generator/hibernate-jpamodelgen.gradle @@ -64,7 +64,8 @@ task jaxb { } } } -runSourceGenerators.dependsOn jaxb + +sourceSets.main.sourceGeneratorsTask.dependsOn jaxb checkstyleMain.exclude '**/jaxb/**'