extra-java-module-info
extra-java-module-info copied to clipboard
Configuration options to (de)activate the plugin for selected Configurations and Source Sets
Hello. So A bit of context: I am pulling artifacts together, so they can be put in a native (outside of gradle) installer. I am doing this using a configuration, and adding the dependencies to the configuration. Now I still need to add the extraJavaModuleInfo to project, or else I will untransformed jars without jpms infos and that wont work.
However the plugin currently only registers itself with configurations that are related to sourceSets my configurations isnt related to one.. After skimming through the code it seems there is an Attribute "javaModules" of type Boolean, so I thought maybe i can use that.
val gimme by configurations.registering{
isCanBeConsumed=false
attributes{
attribute(Attribute.of("javaModule", Boolean::class.java),true )
Howerver that gives me
Build file 'G:\development\java21\blub\zInstaller\Setup-JournalReportingTool2\External-Artifacts\build.gradle.kts' line: 9
Could not create domain object 'gimme' (Configuration)
> Unexpected type for attribute 'javaModule' provided. Expected a value of type boolean but found a value of type java.lang.Boolean.
And it seems like kotlins boolean handling is an absolute nightmare and there is no way to get a correct primitive java boolean... as a workaround i am gonna try to add an empty dummy sourceset tomorrow and see if that gets me somewhere . Best regards
Hi, I'll give more feedback on this later.
In general, the type you need to use for the attribute in Kotlin is Boolean::class.javaObjectType.
Hope this helps.
Ah many thanks, cant believe i spend like an hour trying all kind of ai generenated nonsense to get this boolan nonsense to work, but couldnt find this syntax ;)
Ok I got my setup running, but probably would recommend my aproach; it can be a bit confusing how gradle handles variant selection slightly different than "normal"
And now I also got the usecase that my project actually is a java project, but because this Plugin implecetly activates itself for all source sets, it also also integrates itself with a source set that will break and I cant easily migrate. As a workaround i can split my project, but its a bit akward.
For reference - the topic is currently documented in the README: https://github.com/gradlex-org/extra-java-module-info#how-do-i-deactivate-the-plugin-functionality-for-a-certain-classpath
As this issue shows, it's quite awkward to use, especially because of the Boolean::class.javaObjectType attribute.
I think the plugin extension could offer an easier DSL/API for this. Something like:
extraJavaModuleInfo {
deactivate(sourceSets.test)
deactivate(configurations.annotationProcessor)
activate(configurations.myOwn)
}
Hello, I have run into a related issue so adding my support for an option to deactivate this automatic sourceset system. Ideally we would also be able to expand this into specific dependencies so that we could do something like this:
dependencies {
testImplementation(libs.jopt) {
extraJavaModuleInfo.automaticModule('jopt.simple', it)
}
}
This way your transformer only runs on dependencies that explicitly require it.
This would increase build speeds as it means less transformer runs.
It would allow for less error prone configuration as the one of the alternatives is automaticModule('jopt-simple-5.0.4.jar', 'jopt.simple') which could cause issues if you forget to update the jar name when bumping versions.
@LexManos I think the plugin already supports what you need. You can define rules without using the Jar name. You can use coordinates
automaticModule('jnet.sf.jopt-simple:jopt-simple', 'jopt.simple')
or catalog entries.
automaticModule(libs.jopt, 'jopt.simple')
If you disable all checks, the plugin only modifies the Jars for which you defined a rule:
extraJavaModuleInfo {
failOnMissingModuleInfo = false
failOnAutomaticModules = false
}
Your comment about "doing less work" makes me realize that we can shortcut the analysis if the checks are disabled. This will be in the next release (#159). But it has no influence on the result and the impact of the optimization is probably not measurable in most scenarios. The functionality described above works with the current version already.
Ah, I did not notice you could use catalog entries, if automaticModule(libs.jopt, 'jopt.simple'). Tho, if possible, I would still suggest the syntax I suggested where you can specify this data in the dependency configuration directly.
As for the request to disable the plugin for selected configurations more easily, I would still request that. Specifically this plugin causes issues with Eclipse importing a fresh workspace.
subprojects.zip When importing this into a fresh Eclipse workspace as a gradle project, it does not properly import. The build will say success, the projects will be imported, but sub1 will not have a reference to the root project. If you run the sub1:eclipseClasspath task manually in eclipse you can see an error:
org.gradle.api.InvalidUserDataException: Transform output Z:\subprojects\build\libs\subprojects-1.0.jar must exist.
at org.gradle.api.internal.artifacts.transform.DefaultTransformOutputs.validateOutputExists(DefaultTransformOutputs.java:105)
I am not exactly sure why this happens, as it's all gradle magic. But I would assume that it is because when buildship imports a project dependency it doesn't actually build the jar file as it doesn't need it. But for some reason still calls the artifact transformer. Perhaps you can detect this and better handle things, but having dependencies opt-in seems like a simple solution.
@LexManos this is a know problem. 🙁
- https://github.com/gradlex-org/extra-java-module-info/issues/106
- https://github.com/gradlex-org/extra-java-module-info/issues/78
See also the linked Gradle issues. This is unfortunately also an issue in Gradle itself.
I created another issue to think about a solution again: #161
Adding a different notation won't solve the issue as that is not how the Artifact Transform system of Gradle works. You can't transform a single dependency. You register the Transform globally and Gradle decides when it is needed based on Artifact Attributes (powerful, but complex...).
If you want the definition close to the dependency for readability purpose, you can do something like this with the current notation:
testImplementation(libs.jopt) {
extraJavaModuleInfo.automaticModule(toString(), 'jopt.simple')
}
...although I personally hink these shouldn't be mixed.
What you register with this plugin is a global patching rule. Similar to how the Version Catalog is global. When you declare a dependency, you declare it in one scope in one subproject and you may well repeat it in several places. The patching rule is defined only once and global for all appearances of the dependency.
For reference, see also this comment: https://github.com/gradlex-org/extra-java-module-info/blob/acfd46eb979554fcd9e9ac65486628218585db9a/src/main/java/org/gradlex/javamodule/moduleinfo/ExtraJavaModuleInfoTransform.java#L221-L226
Interesting, I'll add it to my ever growing list of 'gradle does something weird so we have to work around it' Anyways, I would like to see is some simpler method of disabling these specific lines in your plugin: https://github.com/gradlex-org/extra-java-module-info/blob/158aa7e5b983d9ee65ce621daf917b953da771eb/src/main/java/org/gradlex/javamodule/moduleinfo/ExtraJavaModuleInfoPlugin.java#L165-L174
But I would love to see a simple extraJavaModuleInfo.optInMode = true (Or some other better name)
Then I can do my own implementation(foo) { attributes.attribute(javaModule, true) } }
Yes you've shown the clunky way to do it, but as gradle doesn't allow removal of already added attributes having a way to simply opt-out from the beginning would be nice. Not to mention, in most of my use cases it is literally only one dependency that is not already module compliant.
I think that that would be functionally what I need with least effort on your end.
Now on to related, things that are not a "This SHOULD be done", but a "You should consider this if you feel like it"
Technically yes, an artifact transformer is a global system and you can't target a dependency directly. However functionally you can. There is nothing stating that your attribute has to be a boolean, on the contrary it can be anything serializable. For one of my projects i've been able to do this:
dependencies {
compileOnly util.transform(libs.foo) {
configuration = ['public foo.internal.Bar']
}
compileOnly util.transform(libs.bizz) {
configuration = ['public bizz.internal.Buzz']
}
}
Which effectively does:
Dependency transform(Object dep, Closure<?> config) {
def ret = project.dependencies.create(dep)
def key = nextId++
def myConfig = new MyConfig(key)
def wrapped = new Dispatcher(myConfig, ret)
ret.attributes.attribute(transformed, key)
project.configure(wrapped, config)
project.dependencies.registerTransformer(Transformer) {
from.attribute(transformed, 0)
to.attribute(transformed, key)
parameters {
config = myConfig.configuration
}
}
return ret
}
Dispatcher is just something that uses groovy's methodMissing/propertyMissing methods to delegate things as needed. Bit of dirty hacks in the backend, but makes the front end so simple.
As for what benefit this has over the current system. The fact that it is not global means that you can transform the same artifact in multiple ways for multiple configurations. If you're in a single project setup you can define your attributes in a single location instead of multiple blocks. You can more easily control that if any attributes are published for which configuration in your module metadata file.
Options to enable/disable the plugin for selected source sets and/or configurations are available in 1.11.
@LexManos there is now also an option to disable the transformation of local Jars: skipLocalJars = true Activating it should solve the Eclipse import issue.
if you have a use case for more configuration options you would like to see, please open a separate issue.
May I ask for a short howto for this case:
works:
testImplementation("org.wiremock:wiremock:3.13.0")
implementation("com.github.koppor:wiremock-slf4j-shim:main-SNAPSHOT")
Does not work
testImplementation("org.wiremock:wiremock:3.13.0")
testImplementation("com.github.koppor:wiremock-slf4j-shim:main-SNAPSHOT")
module("org.wiremock:wiremock", "wiremock") {
overrideModuleName()
patchRealModule()
exportAllPackages()
mergeJar("com.github.koppor:wiremock-slf4j-shim")
}
I don't see really why, but I think, this is issue is related?
(Background: I am preparing a howto for a workaround for https://github.com/wiremock/wiremock/issues/2149, which covers a workaround for https://github.com/wiremock/wiremock/issues/2874)
The PR where we experiemnted is https://github.com/JabRef/jabref/pull/13293