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

Configure Gradle's toolchains #1227

Closed
dodie opened this issue Apr 22, 2021 · 15 comments
Closed

Configure Gradle's toolchains #1227

dodie opened this issue Apr 22, 2021 · 15 comments
Assignees
Milestone

Comments

@dodie
Copy link

dodie commented Apr 22, 2021

Steps to reproduce

  • Select the following properties on https://start.spring.io/:
    • Project: Gradle Project
    • Language: Java
    • Spring Boot: 2.4.5
    • Java: 16
  • Generate project

Behavior

When I try to build the project with ./gradlew assemble Java 16, it fails:

> startup failed:
  General error during semantic analysis: Unsupported class file major version 60
  
  java.lang.IllegalArgumentException: Unsupported class file major version 60

It seems that the generated project contains a build.gradle file with sourceCompatibility = '11'. Also, the project has Gradle version 6.8.3 which does not support Java 16 out of the box and the project does not use Gradle toolchain.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Apr 22, 2021
@wilkinsona
Copy link
Contributor

wilkinsona commented Apr 22, 2021

start.spring.io is doing its best here to accommodate your request. Spring Boot 2.4.x only supports Gradle 6.x and Gradle 6.x does not support Java 16. As a result, the Java version that you have selected has been downgraded to a version that Gradle 6.8.x does support.

If you want to use Java 16 with Spring Boot 2.4.5 and Gradle, then, as you have noted, you can configure Gradle's toolchain support. We considered making start.spring.io do this automatically but decided against it as it may lead to some surprising behaviour as, for example, it can cause Gradle to download a JDK which may be blocked or prohibited for some users.

I wonder if we could/should add an entry to HELP.md that explains what has been downgraded and why.

@snicoll
Copy link
Contributor

snicoll commented Apr 22, 2021

I wonder if we could/should add an entry to HELP.md that explains what has been downgraded and why.

There is one, actually:

The following was discovered as part of building this project:

    * The JVM level was changed from '16' to '11', review the JDK Version Range on the wiki for more details.

The explanation however, isn't great. Isn't this a duplicate of spring-io/start.spring.io#250 ?

@wilkinsona
Copy link
Contributor

I'd forgotten about spring-io/start.spring.io#250. Thanks for the reminder, @snicoll. I think this could well be a duplicate.

An alternative would be for us to treat this a little bit differently. For example, we could generate the project with Gradle 6.8.3 and sourceCompatibility = '16' and then describe in HELP.md that Gradle's Toolchain support needs to be configured to build the project. It's not a huge amount of configuration for the user to add and describing what to do without doing it by default would alleviate our concern about unexpected behaviour.

Another alternative would be to reconsider our concerns and configure the toolchain by default after all, with a note in HELP.md highlighting what has been done.

@snicoll
Copy link
Contributor

snicoll commented Apr 26, 2021

Honoring the user's choice and generate a broken project with a note in HELP.md does not sound very appealing to me. If they really want to run on a version that the version of Spring Boot they've chosen is not supported, they could change back the value to 16 and follow that notes about configuring toolchain. I think this one has the advantage of being more explicit (i.e. failing only if you start using Java 12+ APIs).

@wilkinsona
Copy link
Contributor

wilkinsona commented Apr 26, 2021

I think it could be argued that the current behaviour is also broken, albeit silently. The user's asked for something that we could configure for them, but we've given them something else instead. This is why I suggested the second alternative where we configure the toolchain. I think I'm leaning towards this approach now. It's giving the user exactly what they've asked for within the limitations of Gradle 6.x.

@snicoll
Copy link
Contributor

snicoll commented Apr 26, 2021

Yup, not denying the problem, just giving feedback on the first solution and forgetting to provide some for the other one :) What you said. If configuring the toolchain is easy enough, I'd like us to explore that option and add a note in HELP.md perhaps?

@snicoll snicoll added type: enhancement and removed status: waiting-for-triage An issue we've not yet triaged labels Apr 26, 2021
@snicoll snicoll added this to the 0.11.0 milestone Apr 26, 2021
@snicoll snicoll changed the title Generated Gradle project does not work with Java 16 Configuring Gradle's toolchain when Gradle does not handle the requested Java version Apr 26, 2021
@wilkinsona wilkinsona changed the title Configuring Gradle's toolchain when Gradle does not handle the requested Java version Configure Gradle's toolchain when Gradle does not handle the requested Java version May 15, 2021
@snicoll snicoll modified the milestones: 0.11.0, 0.11.1 Sep 9, 2021
@snicoll snicoll modified the milestones: 0.11.1, 0.12.0 Sep 27, 2021
@vpavic
Copy link
Contributor

vpavic commented Dec 30, 2021

From today's standpoint, would you be open to configure Gradle's toolchain by default, as originally proposed in #1187?

There are numerous benefits of using Gradle toolchain on top of the case expressed in this issue. A project that configures toolchain is ensured to always build using the appropriate Java version. With the ecosystem becoming increasingly split between 3 different Java version (8, 11 & 17) this feature just becomes more attractive.

it can cause Gradle to download a JDK which may be blocked or prohibited for some users

Isn't this basically the same as with the Gradle wrapper itself? You still use the wrapper in generated projects even though some environments might be more prohibitive about it and prefer to use their own Gradle distribution. Personally I wouldn't conflate such considerations with initializr.

@wilkinsona
Copy link
Contributor

Isn't this basically the same as with the Gradle wrapper itself?

No, I didn't think so. You can avoid using the wrapper with changing the build script by running gradle rather than ./gradlew. Once a project's being configured to use a toolchain, I don't think it's possible to avoid using it without changing the build script.

@vpavic
Copy link
Contributor

vpavic commented Jan 10, 2022

The way I see it:

  • Gradle wrapper
    • if you don't use it you might end up using the wrong Gradle version which could fail
    • if you use it, it will download the needed Gradle version only once
  • Gradle toolchains
    • if you don't use it you might end up using the wrong JDK version which could fail
    • if you use it, it will either pick it up from the supported locations or download the needed JDK only once

That looks fairly analogous to me. And a far better developer experience OOTB, at least IMO.

Once a project's being configured to use a toolchain, I don't think it's possible to avoid using it without changing the build script.

I've been using toolchains for quite some time now and in practice it has never downloaded a JDK for me, because it will pick up the appropriate JDK from my local SDKMAN installation.

Additionally, you might also take into consideration that for some time now Gradle promotes toolchains as the way of declaring Java version (see the very first snippet from the Building Java & JVM projects page of the user manual) and that sourceCompatibility and targetCompatibility are referred to as historical options for the Java compiler.

@wilkinsona
Copy link
Contributor

wilkinsona commented Jan 11, 2022

As I read it, sourceCompatibility and targetCompatibility are historical as they have been superseded by release not because of toolchains. In fact, Gradle’s own docs suggest that using release may be the easier option in some cases.

In short, there’s no perfect one-size-fits-all solution here. There are numerous options, each with slightly different advantages and disadvantages, particularly when you consider that we also have to support Java 8.

@KotlinIsland
Copy link
Contributor

Why not toolchains by default? I think they are awesome.

@wilkinsona
Copy link
Contributor

Please see the discussion above, particularly this comment and the issue to which it links.

snicoll added a commit that referenced this issue Jul 11, 2023
This commit improves the resolution of plugins to ignore a non fatal
resolution of the model.

See gh-1227
@mhalbritter
Copy link
Contributor

Just tested with Gradle 8.7: The automatic download of JDKs is not enabled by default. If you request a Java version through a toolchain which is not available on the machine, it fails with:

Could not determine the dependencies of task ':bootJar'.
> Could not resolve all dependencies for configuration ':runtimeClasspath'.
   > Failed to calculate the value of task ':compileJava' property 'javaCompiler'.
      > Cannot find a Java installation on your machine matching this tasks requirements: {languageVersion=19, vendor=any, implementation=vendor-specific} for LINUX on x86_64.
         > No locally installed toolchains match and toolchain download repositories have not been configured.

To automatically download JDKs, the user has to specify toolchain download repositories.

@wilkinsona
Copy link
Contributor

That's a really nice improvement. Looks like it landed in Gradle 8.0. Given that it removes one of the downsides of the toolchains approach, I'm in favour of this now for cases where the Gradle version and the Java version are not compatible. Right now, we'd use a toolchain for Gradle projects that are using Java 22. When we upgrade to Gradle 8.8, we'd switch it off again.

@mhalbritter
Copy link
Contributor

We talked about that in our meeting and want to make toolchains the default. If that leads to problems, we'll just use them if we need to, e.g. compiling Java 22 with Gradle 8.7.

@mhalbritter mhalbritter changed the title Configure Gradle's toolchain when Gradle does not handle the requested Java version Configure Gradle's toolchains Jun 4, 2024
@mhalbritter mhalbritter self-assigned this Jun 4, 2024
@mhalbritter mhalbritter removed this from the General Backlog milestone Jun 4, 2024
mhalbritter added a commit that referenced this issue Jun 5, 2024
This is obsolete when using toolchains. The Kotlin plugin automatically
sets the jvmTarget to the used toolchain.

See gh-1227
@mhalbritter mhalbritter added this to the 0.21.0 milestone Jun 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants