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

Classloader issue related to java.xml.bind in ArtifactTransform #29114

Open
tudortimi opened this issue May 13, 2024 · 3 comments
Open

Classloader issue related to java.xml.bind in ArtifactTransform #29114

tudortimi opened this issue May 13, 2024 · 3 comments
Labels
a:bug in:artifact-transforms to-triage 👋 team-triage Issues that need to be triaged by a specific team

Comments

@tudortimi
Copy link

tudortimi commented May 13, 2024

Current Behavior

I was trying to use javax.xml.bind in a plugin I’m developing. I see issues related to missing classes when I try to run in Java 11, but these only happen in a part of the code that uses JAXB and not in others.

I'm running it on both Java 8 and Java 11. Since JAXB is not part of the JDK anymore from Java 9, I added a dependency in the plugin build:

dependencies {
    implementation("com.sun.xml.bind:jaxb-ri:2.3.9") {
        because("javax.xml.bind is not part of the JDK anymore starring with JDK9")
    }
}

I have two places in my plugin where I use JAXB. One place is in a task:

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;

public class WriteCompileSpecFile extends DefaultTask {
    // ...

    @TaskAction
    protected void generate() {
        DefaultHDVLCompileSpec compileSpec = new DefaultHDVLCompileSpec(getSvSource().getFiles());
        try {
            JAXBContext jaxbContext = JAXBContext.newInstance(DefaultHDVLCompileSpec.class);
            Marshaller marshaller = jaxbContext.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

            FileAdapter fileAdapter = new FileAdapter(getProject().getProjectDir());
            marshaller.setAdapter(fileAdapter);

            marshaller.marshal(compileSpec, destination.get().getAsFile());
        } catch (JAXBException e) {
            throw new RuntimeException(e);
        }
    }
}

I can execute this task without any problems.

The other place where I use JAXB is in an artifact transform:

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;

public abstract class WriteXrunArgsFile implements TransformAction<TransformParameters.None> {
    // ...

    private static DefaultHDVLCompileSpec getCompileSpec(File input) {
        File compileSpec = new File(input, ".gradle-hdvl/compile-spec.xml");
        try {
            JAXBContext jaxbContext = JAXBContext.newInstance(DefaultHDVLCompileSpec.class);
            Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();

            FileAdapter fileAdapter = new FileAdapter(input);
            unmarshaller.setAdapter(fileAdapter);

            DefaultHDVLCompileSpec result = (DefaultHDVLCompileSpec) unmarshaller.unmarshal(compileSpec);
            for (File svSourceFile : result.getSvSourceFiles()) {
                assert svSourceFile.isAbsolute() : "not absolute: " + svSourceFile;
                assert svSourceFile.exists() : "doesn't exist: " + svSourceFile;
            }

            return result;
        } catch (JAXBException e) {
            throw new RuntimeException(e);
        }
    }
}

When the artifact transform gets executed, I get:

      > Execution failed for WriteXrunArgsFile: /home/tudor/.gradle/caches/transforms-4/2f8f369cd18dbcfb90e34fd250b46eaa/transformed/some-published-dependency-0.1.0.zip.
         > javax.xml.bind.JAXBException: Implementation of JAXB-API has not been found on module path or classpath.
            - with linked exception:
           [java.lang.ClassNotFoundException: com.sun.xml.bind.v2.ContextFactory]

Expected Behavior

I would expect the dependency to be enough. I discussed this here in the Gradle forum with @Vampire and he suggested I open an issue.

Context (optional)

I switched to using a newer version of JAXB, which works on both Java 8 and 11 (version 3.0.2), but this required changing the namespace as well. I'm not blocked by the issue, but would like to understand whether I'm doing something wrong or whether something can be improved in Gradle.

Steps to Reproduce

I see the issue in this commit of my plugin: tudortimi/gradle-hdvl@3347a4e

To reproduce, after cloning that repo and selecting the commit, with Java 11 installed, run:

cd examples/using-published/some-published-dependency
../../../gradlew publish  # executes task that writes XML using JAXB, works

cd examples/using-published/some-project
../../../gradlew genFullXrunArgsFile  # consumes artifact produced by previous project, triggers artifact transform, using JAXB fails

Gradle version

8.7

Build scan URL (optional)

https://scans.gradle.com/s/2micrd4yj3ahe

Your Environment (optional)

Java 11

@Vampire
Copy link
Contributor

Vampire commented May 13, 2024

To have the essential information here too. When executing a task action, the thread context class loader gets set to the class loader of the task action that is executed. But for artifact transforms this thread context class loader setting is not done and the JAXB implementation is searched via the thread context class loader which then causes it not being found during the artifact transform.

I guess that the thread context class loader should also be set for executing transform actions unless there is a reason not to.

@ljacomet ljacomet added in:artifact-transforms 👋 team-triage Issues that need to be triaged by a specific team and removed to-triage labels May 16, 2024
@ljacomet
Copy link
Member

This issue needs a decision from the team responsible for that area. They have been informed. Response time may vary.


One question to answer here is whether transforms implementations can have dependencies.

@Vampire
Copy link
Contributor

Vampire commented May 16, 2024

Maybe I misunderstand, but why should they not?
I have many artifact transforms that need dependencies.
Just as one example I have an artifact transforms that signs DLLs contained within JARs on-the-fly.
I wouldn't want to implement this myself, so I use JSign for it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
a:bug in:artifact-transforms to-triage 👋 team-triage Issues that need to be triaged by a specific team
Projects
None yet
Development

No branches or pull requests

3 participants