Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow an incremental build to perform less weaving #1962

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

mjaggard
Copy link

@mjaggard mjaggard commented Oct 9, 2023

This change allows for defining a Gradle plugin that will only perform Weaving or copying on classes that have changed their inputs. I have put some of the code for the Gradle plugin (available under the same license) in the comments below, but I couldn't see where this could be added to the Eclipselink codebase.

@mjaggard
Copy link
Author

mjaggard commented Oct 9, 2023

Gradle plugin:

/*
 * Copyright (c) 2023 Billforward Inc. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0,
 * or the Eclipse Distribution License v. 1.0 which is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 */
import org.gradle.api.DefaultTask
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.tasks.*
import org.gradle.work.ChangeType
import org.gradle.work.Incremental
import org.gradle.work.InputChanges

import java.util.stream.StreamSupport

abstract class IncrementalWeavingTask extends DefaultTask {
    @Incremental
    @PathSensitive(PathSensitivity.RELATIVE)
    @InputDirectory
    abstract DirectoryProperty getJavaCompileOutput();

    @InputFile
    abstract RegularFileProperty getWeavingPersistenceXML();

    @OutputDirectory
    abstract DirectoryProperty getWeavingOutput();

    @CompileClasspath
    Iterable<File> classpath

    @TaskAction
    void execute(InputChanges inputChanges) throws IOException, URISyntaxException {
        var listOfUrls = StreamSupport.stream(getClasspath().spliterator(), false)
                .map(f -> f.toURI().toURL())
                .toArray(URL[]::new)
        var loader = new URLClassLoader(listOfUrls)

        writeXML()

        boolean incremental = inputChanges.isIncremental()

        var set = new HashSet<String>()
        if (incremental) {
            inputChanges.getFileChanges(getJavaCompileOutput()).forEach(it -> {
                if (it.getChangeType() == ChangeType.REMOVED) {
                    it.getFile().delete()
                } else {
                    set.add(it.getNormalizedPath())
                    getLogger().info("Changed path: {}", it.getNormalizedPath())
                }
            })
        }

        if (set.size() > 50) {
            incremental = false
        }

        var proc = new StaticWeaveProcessor(
                getJavaCompileOutput().get().asFile,
                getWeavingOutput().get().asFile
        )
        proc.setLogLevel(5)
        proc.setClassLoader(loader)
        proc.setPersistenceInfo(getJavaCompileOutput().get().asFile)

        if (incremental) {
            proc.fileNeedsProcessingPredicate = it -> {
                getLogger().debug("File: {}", it)
                return set.contains(it)
            }
        }

        proc.performWeaving()

        deleteXML()
    }

    private void writeXML() throws IOException {
        //Finding classes only works from the root containing persistence.xml containing directory downwards
        var xmlContents = getWeavingPersistenceXML().get().asFile.text
        var tempDir = new File(getJavaCompileOutput().get().asFile, "META-INF")
        tempDir.mkdirs()
        var tempFile = new File(tempDir, "persistence.xml")
        tempFile.delete()
        tempFile << xmlContents
    }

    private void deleteXML() {
        new File(new File(getJavaCompileOutput().get().asFile, "META-INF"), "persistence.xml").delete()
        new File(new File(getWeavingOutput().get().asFile, "META-INF"), "persistence.xml").delete()
        new File(getJavaCompileOutput().get().asFile, "META-INF").delete()
        new File(getWeavingOutput().get().asFile, "META-INF").delete()
    }
}

An example of use. Likely if this were released as a Gradle plugin, several of these convention overrides would be moved into the plugin itself.


def jpaWeave = tasks.register('jpaWeave', IncrementalWeavingTask) {
    dependsOn compileJava
    javaCompileOutput = new File(sourceSets.main.output.classesDirs.singleFile.parentFile, "before-jpa")
    weavingOutput = sourceSets.main.output.classesDirs.singleFile
    classpath = sourceSets.main.compileClasspath
    weavingPersistenceXML = new File(sourceSets.main.resources.srcDirs.iterator().next(), 'META-INF/persistence.xml.weaving')
}

tasks.named('compileJava', JavaCompile).configure {
    def beforeJpa = new File(sourceSets.main.output.classesDirs.singleFile.parentFile, "before-jpa")
    destinationDirectory.set(beforeJpa)
    finalizedBy jpaWeave
}

tasks.named('classes').configure {
    dependsOn jpaWeave
}

tasks.named('compileTestFixturesJava').configure {
    dependsOn jpaWeave
}

@rfelcman
Copy link
Contributor

rfelcman commented Jan 2, 2024

  1. For functional changes like this we expect some test. Please check and maybe extend with new test method jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/tests/jpa/beanvalidation/BeanValidationJunitTest.java
  2. Please ensure, that copyright year in the modified files (main + test scope) is updated to the current year.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants