This message was deleted.
# community-support
s
This message was deleted.
f
Copy code
Could not determine the dependencies of task ':b:compileJava'.
> Could not resolve all task dependencies for configuration ':b:compileClasspath'.
   > Could not resolve project :a.
     Required by:
         project :b
      > No matching variant of project :a was found. The consumer was configured to find a library for use during compile-time, compatible with Java 8, preferably in the form of class files, preferably optimized for standard JVMs, and its dependencies declared externally but:
          - Variant 'apiElements' capability com.x:a:1.0.0 declares a library for use during compile-time, packaged as a jar, and its dependencies declared externally:
              - Incompatible because this component declares a component, compatible with Java 11 and the consumer needed a component, compatible with Java 8
              - Other compatible attribute:
                  - Doesn't say anything about its target Java environment (preferred optimized for standard JVMs)
v
From what you said, you cannot except for also degrading A to Java 11. But this already cannot work in Eclipse. If a class file compiled for target Java 11, a Java 8 JVM cannot read it. So even if compiling would work - and you could probably get around that - it would fail at runtime.
f
Aha, thanks, perhaps tomorrow I can check the compiled jars and see how the class are targeted. If looking at the project files, A does specified on 11 while B is specified on 8. I think it works for us probably because we run everything on 11, and the client runs on 8 that using B is probably only using some package or classes in there but having no real connection to A. Another thing is, is there a way to configure Gradle to still compile it to 11 as target, but it only allow me to use Java 8 or older syntaxes? This can sort of allowing me to still use my build and do not worry about writing stuff the eclipse build cannot handle.
v
Probably, but never tried that
πŸ‘ 1
f
Copy code
tasks.withType<JavaCompile> {
    sourceCompatibility = "8"
    targetCompatibility = "11"
}
Thanks, I tried to just set it as this on B, but seems not working.
Compliance level '1.8' is incompatible with target level '11'. A compliance level '11' or better is required
v
Where do you get that? From Gradle?
For me it works from Gradle. Is it maybe caused by the JDK you use, or do you somehow use the Eclipse Compiler or something like that?
f
Yes, I had to use Eclipse Compiler. So do I need to set up the compiler differently? πŸ€”
So seems when I set both source and target to 8, I got blocked by gradle, and when I try set them separately, I got blocked by ecj? πŸ˜†
Copy code
targetCompatibility = "11"
 options.compilerArgs = listOf("-source", "1.8")
If I just set like this, I got this error:
duplicate source compliance setting specification: 1.8
So apparently those config is given to the compiler...
v
I have no idea how to configure ejc accordingly, just Google suggested that this message might come from it. What do you mean by Gradle blocking you to set both to 8? That should work
f
Oh, what I means is the original problem, because A needs to be targeted to Java 11, and when setting B targeting to 8 (so setting "both" source and target to 8), then gradle does not allow me to do so.
v
Well, you could trick it. If you know it is a Java 11 compiler on B, you could configure the
compileClasspath
on
B
to request Java 11 compatible stuff instead of Java 8 compatible stuff.
πŸ‘€ 1
Btw. when wanting to use the same value for source and target and not wanting to use a toolchain, at least use
release
instead as it then also ensures the right API is used to compile against.
βœ… 1
f
Hmm thanks... but I am not sure if I understand your "trick it" idea. Basically the project A and B are all subprojects of a single master gradle project, and I have some build-logic to config ecj as the compiler for both of them. So in build-logic I have set the shared conventional plugin as
Copy code
plugins {
    java
    id("io.github.themrmilchmann.ecj") // for using eclipse compiler - <https://stackoverflow.com/questions/3061654/what-is-the-difference-between-javac-and-the-eclipse-compiler>
}
java {
    toolchain.languageVersion.set(JavaLanguageVersion.of(11))
    toolchain.vendor.set(JvmVendorSpec.ADOPTIUM)
}
ecj {
    compilerGroupId.set("org.eclipse.jdt")
    compilerArtifactId.set("ecj")
    compilerVersion.set("3.36.0")
}
Then those apply both to A and B, but in B I am adding some extra such as: b:
Copy code
plugins {
    id("p-java-library") // local convention plugin
}
dependencies {
    implementation(project(":A"))
}
tasks.withType<JavaCompile> {
    sourceCompatibility = "8"
    targetCompatibility = "8"
}
Then I got the error on the top of the project.
v
Something like
Copy code
configurations.compileClasspath {
    attributes.attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 11)
}
on B
πŸ‘€ 1
f
Woo... It's a bit difficult to understand for now but somehow it does make it compiles 🀯 However, the interesting fact seems to be, the compile will NOT fail in this case if I write
List.of()
in a file in B. But, the Intellij somehow fetch correct info and can show me the
List.of()
is Java9 api and gives me an error. I guess this will serve as a solution for me.
I earlier downloaded the latest ecj.jar, and made a very simple java file on it and compile, I get the same error when -source and -target used differently. (Incase anyone is interested to know)
Copy code
java -jar ecj-4.30.jar A.java -source 1.8 -target 11
Compliance level '1.8' is incompatible with target level '11'. A compliance level '11' or better is required
πŸ‘Œ 1
Again, thank you so much πŸ˜„
πŸ‘Œ 1
Oh by the way, looks like I need to set
compileOnly(project(":A"))
in B, otherwise, for example using "implementation", it still cannot work :)
v
Woo... It's a bit difficult to understand for now but somehow it does make it compiles
A has that attribute set to 11 B requests this attribute to be at most 8 thus it fails Now you tell B "request it to be at most 11" and the resolution error disappears And as you are actually using a Java 11 compiler, the compiler can read the Java 11 classes of A
However, the interesting fact seems to be, the compile will NOT fail in this case if I write
List.of()
in a file in B.
That's why I said you should use
release
if you need source and target to be the same, because with
release
you additionally tell the compiler to compile against the according API and prevent using newer API or breakingly changed API. If you for example just set source compatibility to 8 with the normal compiler, you get a warning that you did not also set the bootstrap classpath from a Java 8 JDK which would also serve the same purpose.
βœ… 1
Oh by the way, looks like I need to set
compileOnly(project(":A"))
in B, otherwise, for example using "implementation", it still cannot work πŸ™‚
Well, if you for something use the
runtimeClasspath
, you again have the same problem and could use the same work-around.
But you probably don't want a hard dependency anyway, as you said the one using B with Java 8 does not use functions of B that need A which would fail at runtime then. So having A as a hard dependency is anyway questionable.
βœ… 1
Actually, what you probably really would want, are feature variants
πŸ‘€ 1
f
Oh right... I just read about
release
and learned it is different from setting both -source and -target. Good input.
options.release = 8
works perfect.
The feature variants do seem interesting, need to read more later to under stand more, perhaps in the far future when we migrate to gradle, then we could use that. For now the build is still controlled by Eclipse, and my goal here is to be able to build the whole thing with Gradle while not touching too much of the eclipse configurations. :)
πŸ‘Œ 1
One more follow up question πŸ˜› What if I have some main method in a class on B that people use locally to generate some stuff, and it does depend on A, but hopefully in the part of code that has no new Java feature is used, then how can I still run this main method now? I realized, at least in Intellij, if I use complileOnly, then running the main method in B, I got an error saying A class not found πŸ€” I tried to add a class path to a/build/classes/java/main, and seems not working either. Perhaps if I write a JavaExec task in gradle it can be solved in some easily way to set anther project as run time dependency.
There is also some option saying about "provided" scope, but seems cannot find a good doc on how to use that in gradle. Maybe I am getting into some wrong directly here. Anyway, need to jump, have a nice weekend πŸ™‚
v
What if I have some main method in a class on B that people use locally to generate some stuff, and it does depend on A
If it needs to run on Java 8, you are lost as A requires Java 11 to run.
f
That’s true, but this special method I need to run on B is something that always runs in our platform so it is on Java11. (Sorry this sounds pretty confusing and complex setup πŸ˜› )
v
Well yeah, if you use
compileOnly
that basically is what some call provided. It means if you need it at runtime, you have to supply it manually
βœ… 1
f
Sounds sweet πŸ™‚