-
Notifications
You must be signed in to change notification settings - Fork 62
Overriding in module descriptors #5955
Comments
Here's a proposal for the syntax of this, based on a suggestion by @tombentley: native("jvm")
module com.my.app "1.0.0" {
import "org.hibernate:hibernate-entitymanager" "5.0.4.Final" {
~ shared import "org.hibernate:hibernate-core" {
+ shared import "javax.transaction:jta" "1.1";
}
~ shared import "org.javassist:javassist";
~ shared import "org.hibernate.javax.persistence:hibernate-jpa-2.1-api";
}
import "org.hsqldb:hsqldb" "2.3.1";
} There are three operators:
The An interesting question is: is it better to write the above like this, with just one level of nesting allowed? native("jvm")
module com.my.app "1.0.0" {
import "org.hibernate:hibernate-entitymanager" "5.0.4.Final" {
~ shared import "org.hibernate:hibernate-core";
~ shared import "org.javassist:javassist";
~ shared import "org.hibernate.javax.persistence:hibernate-jpa-2.1-api";
}
~ import "org.hibernate:hibernate-core" {
+ shared import "javax.transaction:jta" "1.1";
}
import "org.hsqldb:hsqldb" "2.3.1";
} That is, can I use one |
We need some way to distinguish "global" overrides from overrides that apply to a single nested |
Some people are going to complain that (FTR it's not even displayed on Mac azerty keyboards, it's a tricky |
Upon reflection, it seems to me that we should clearly separate regular module imports, and module overrides, since the former only to the current module, and the latter apply recursively to all its dependencies. So we don't want to confuse people about the semantic difference between them. Given that, perhaps a layout like the following is better: native("jvm")
module com.my.app "1.0.0" {
import "org.hibernate:hibernate-entitymanager" "5.0.4.Final";
import "org.hsqldb:hsqldb" "2.3.1";
module "org.hibernate:hibernate-entitymanager" "5.0.4.Final" {
~ shared import "org.hibernate:hibernate-core";
~ shared import "org.javassist:javassist";
~ shared import "org.hibernate.javax.persistence:hibernate-jpa-2.1-api";
}
module "org.hibernate:hibernate-core" {
+ shared import "javax.transaction:jta" "1.1";
}
} This is, I suppose, a lot more consistent with how |
Well, TBH, I would be perfectly happy using:
But then I wouldn't know what to do for removing FTR, it would look like this: native("jvm")
module com.my.app "1.0.0" {
import "org.hibernate:hibernate-entitymanager" "5.0.4.Final";
import "org.hsqldb:hsqldb" "2.3.1";
module "org.hibernate:hibernate-entitymanager" "5.0.4.Final" {
shared import "org.hibernate:hibernate-core";
shared import "org.javassist:javassist";
shared import "org.hibernate.javax.persistence:hibernate-jpa-2.1-api";
}
module "org.hibernate:hibernate-core" {
shared import "javax.transaction:jta" "1.1";
}
} The above is rather clean and readable, and more ceylonic (no cryptic symbols). But how would you indicate removal of a dependency? |
So how do you distinguish between shared and non-shared additional imports?
Using |
I'm not sure I understand. If module ( |
With the |
It is possible, yes. |
+1 for Another point from your proposal, Gavin, is that I feel it duplicating. Assuming there is no reason for overriding modules not being imported (directly or indirectly), why don't place overrides inside module import?
|
Yeah, I'm not convinced by symbols. I'd rather have annotations. We can just add a |
Well the issue is that:
So I think the singly-nested |
Feels wrong. Grumble. |
The other annotations are adjectives, so |
|
|
Would look something like: native("jvm")
module com.my.app "1.0.0" {
import "org.hibernate:hibernate-entitymanager" "5.0.4.Final";
import "org.hsqldb:hsqldb" "2.3.1";
module "org.hibernate:hibernate-entitymanager" "5.0.4.Final" {
shared import "org.hibernate:hibernate-core";
ignore import "org.hibernate.javax.persistence:hibernate-jpa-2.1-api";
}
} |
Perhaps in addition to the proposal in this issue, it would be useful to also have a way of optionally indicating that all transitive dependencies of a module import should be themselves treated as directly imported by the module. Otherwise, developers having this need would still need tools like the ceylon-gradle-plugin to auto-generate module descriptors which surface transitive dependencies of module imports to become top-level module imports themselves. |
I just made the following work, on branch native("jvm")
module jaxrs.example "1.0.0" {
shared import javax.javaeeapi "7.0";
import ceylon.interop.persistence "1.3.1";
module ceylon.interop.persistence "1.3.1" {
import maven:org.hibernate.javax.persistence:"hibernate-jpa-2.1-api" "1.0.0.Final"
=> javax.javaeeapi "7.0";
}
} Cool!! |
Oh, damn! I just realized that, while this is working great at compiletime, it doesn't have any effect at all at runtime. The thing is that the existing Hrm, I wonder how we can solve this. WDYT, @FroMage? |
Hrm, @FroMage, even before hitting the runtime issue, I've run into something else, which you can observe here: https://github.com/ceylon/ceylon-examples-di/tree/5955 The code passes the typechecker in IntelliJ, but then blows up when attempting to actually compile it with the Java backend. Somehow, the overrides are treated somewhat differently by the command line compiler. OTOH, in this example: https://github.com/DiegoCoronel/ceylon-jboss-swarm/tree/5955 everything is peachy, so it's not like they're simply ignored by the command line compiler. Not sure what to make of this. |
Alright, I think I've got the descriptor / compiletime side of this more-or-less sorted now. There are currently four things you can do:
I still have not decided how to replace a module ( And I will need @FroMage's help on the problem of propagating overrides from compiletime to runtime. And there is still no "override merging", only the module descriptors of source modules are taken into account. But anyway, this is actually really good progress. |
Nice! Are the version number fields in the "from" part optional in your examples? module maven:com.sparkjava:"spark-core" => "2.5.2"; |
Now since overrides are proposed to be inherited, if you want local overrides only for running e.g. test code, do you propose creating a separate module for testing? Put the test deps that used to be in test-override.xml (optionally along with test code) into its own module that depends on the main module? |
Not in the current implementation. |
That could be nice though, if you want to use a policy like "I don't care which version is pulled, I just want to use exactly version x.y". |
Yeah, most overrides in the wild don't match on version numbers: they blanket replace or remove every version of a given module. |
module ceylon.interop.persistence "1.3.1" {
module maven:org.hibernate.javax.persistence:"hibernate-jpa-2.1-api" "1.0.0.Final"
=> import javax.javaeeapi "7.0";
} I'd go for this syntax to alter dependencies: module ceylon.interop.persistence "1.3.1" {
import maven:org.hibernate.javax.persistence:"hibernate-jpa-2.1-api" "1.0.0.Final"
=> import javax.javaeeapi "7.0";
} And this for replacing modules globally: module maven:org.hibernate.javax.persistence:"hibernate-jpa-2.1-api" "1.0.0.Final"
=> module javax.javaeeapi "7.0"; This way we can stick to |
Sure, bear in mind that this is still very much a proof of concept, and I'm still just trying to get something that basically "works", before trying to get too deep into the details. I definitely have this feature (all-version matching) in mind. |
Interesting. I was coming at it from a different angle:
Part of the justification for the different keyword was that
OTOH, I can also see how your syntax is also reasonable:
Both options are reasonable. |
The use of matching keywords on both sides of the fat arrow in @FroMage's proposed syntax seems to me to make it more intuitive than the other alternative. |
The options here are:
|
Following an agreeable discussion about module descriptors and assemblies, we decided that we need to allow overrides in
module.ceylon
. Merging these overrides would apply downwards in a module dependency tree (cycles are not a problem because they always have to be compiled together anyway).For flatclasspath we would still require additional overrides (to resolve conflicts between non-shared but duplicated dependencies).
We'd need a compile-time version validation phase (to identify diamonds), which would benefit from being able to obtain dependency information without downloading the entire module. This could be a special API for herd, or a separate artifact obtainable separately from the module itself.
The text was updated successfully, but these errors were encountered: