radcortez / openjpa-gradle-plugin

Apache License 2.0
4 stars 12 forks source link

Support JDK 11 #8

Closed lingocoder closed 5 years ago

lingocoder commented 5 years ago

Context

A project that uses openjpa-gradle-plugin:3.0.0 has a requirement to support JDK 11+.

According to a known issue reported on the OpenJPA project, OpenJPA can support JDK 9+ by upgrading its xbean-asm5 dependency to xbean-asm6 or newer.

A Gradle dependency report for this plugin's openjpa configuration shows that the version of xbean-asm in use for the openjpa-gradle-plugin is org.apache.xbean:xbean-asm5-shaded:3.17. A newer version (xbean-asm7-shaded:4.14) is available.

The Problem

Using openjpa-gradle-plugin:3.0.0 with JDK 11 or newer results in a MetamodelExtension-related NoClassDefFoundError.

Steps to Reproduce

Assumes JDK 11 or newer is installed

Enter the following in the project's build.gradle build script to upgrade this plugin's current xbean-asm5 dependency to xbean-asm7:

   ...
    openjpa {
    ...
    metamodel {
        metamodelOutputFolder 'build/generated'
        metamodelDependency 'org.apache.openjpa:openjpa:3.1.0'
    }
    ...
}
   ...

Verify that the openjpa configuration dependency report contains the updated dependencies with the gradle dependencies --configuration openjpa

Expected Result

openjpa
\--- org.apache.openjpa:openjpa:3.1.0
     +--- org.apache.commons:commons-collections4:4.3
     +--- net.sourceforge.serp:serp:1.15.1
     |    \--- junit:junit:3.8.1
     +--- org.apache.geronimo.specs:geronimo-jms_1.1_spec:1.1.1
     +--- org.apache.geronimo.specs:geronimo-jta_1.1_spec:1.1.1
     +--- org.apache.commons:commons-pool2:2.6.0
     +--- org.apache.xbean:xbean-asm7-shaded:4.12
     \--- org.apache.geronimo.specs:geronimo-jpa_2.2_spec:1.0

Actual Result

FAILURE: Build failed with an exception.
...
* What went wrong:
A problem occurred evaluating root project 'openjpa-lab'.
> org/gradle/api/internal/ClosureBackedAction

* Try:
Run with --debug option to get more log output. Run with --scan to get full insights.

* Exception is:
org.gradle.api.GradleScriptException: A problem occurred evaluating root project 'openjpa-lab'.
        ...
Caused by: java.lang.NoClassDefFoundError: org/gradle/api/internal/ClosureBackedAction
        at com.radcortez.gradle.plugin.openjpa.OpenJpaExtension.metamodel(OpenJpaExtension.groovy:44)
        ...

* Get more help at https://help.gradle.org
...
BUILD FAILED in 16s

Environment

Windows 7 Professional 64 bit Open JDK 11 Gradle 5.2.1 com.radcortez.gradle:openjpa-gradle-plugin:3.0.0

radcortez commented 5 years ago

@lingocoder thanks for the report. I'll have a look and see if I can fix it.

Cheers!

lingocoder commented 5 years ago

Awesome @radcortez. Let me know if you need more details. Thanks for looking into it.

lingocoder commented 5 years ago

Also @radcortez, when this plugin is applied in a project and I do gradle dependencies on that project, then an openjpa configuration is shown in Gradle's dependencies report for that project. However, it's not obvious where that configuration comes from or why it's there.

For example, an open source project I'm working on uses this plugin. It also has dependencies on org.apache.openjpa:openjpa as well as spring-boot-starter-data-jpa. Seeing that openjpa configuration in Gradle's dependency report for the very first time, it is not obvious which of the project's three jpa-related dependencies that openjpa configuration comes from.

It would be very valuable to users of the plugin, in my opinion, if you explained somewhere in your README.md that this plugin adds that openjpa configuration and the reasons for it. Thanks in advance for that.

vorburger commented 5 years ago

@radcortez I'm looking into a problem related to this in https://github.com/apache/fineract/pull/609 (which, as far as I know, incidentially is the same project that @lingocoder originally raised this issue for). I think there may be two separate issues:

With OpenJPA 3.1.0 (likely 3.0.0 already), there's, apparently, that ClosureBackedAction problem shown above. I'm guess that problem will you require you to look more into and fix in openjpa-gradle-plugin and release a new version?

With OpenJPA 2.4.3, which would be sufficient for Apache Fineract at least in the short term, given that OPENJPA-2730 went into v2.4.3, I'm hitting another problem, which I suspect is much simpler and can be resolved purely by configuration - I just can't figure out how, because my Gradle skills suck:

So in fineract-provider/build.gradle (of https://github.com/apache/fineract/pull/609, not yet merged), we have:

buildscript {
  ext {
    openJPAVersion = '2.4.3'
  }
  repositories {
         jcenter()
         mavenCentral()
         maven { url "https://plugins.gradle.org/m2/" }
  }

  dependencies {
     classpath 'com.bmuschko:gradle-tomcat-plugin:2.5',
               'nl.javadude.gradle.plugins:license-gradle-plugin:0.11.0',
               'org.zeroturnaround:gradle-jrebel-plugin:1.1.2',
               'org.springframework.boot:spring-boot-gradle-plugin:2.1.3.RELEASE' // also change springDataJpaVersion below
     classpath "org.apache.openjpa:openjpa:$openJPAVersion"
     classpath 'com.radcortez.gradle:openjpa-gradle-plugin:3.0.0'
     classpath 'gradle.plugin.org.nosphere.apache:creadur-rat-gradle:0.2.2'
  }
}

But ./gradlew dependencies --configuration openjpa (thanks @lingocoder for pointing that out!) still shows:

openjpa
\--- org.apache.openjpa:openjpa:2.4.2
     +--- commons-lang:commons-lang:2.6
     +--- commons-collections:commons-collections:3.2.2
     +--- net.sourceforge.serp:serp:1.15.1
     |    \--- junit:junit:3.8.1
     +--- org.apache.geronimo.specs:geronimo-jms_1.1_spec:1.1.1
     +--- org.apache.geronimo.specs:geronimo-jta_1.1_spec:1.1.1
     +--- commons-pool:commons-pool:1.6
     +--- org.apache.xbean:xbean-asm5-shaded:3.17
     \--- org.apache.geronimo.specs:geronimo-jpa_2.0_spec:1.1

Note how that's still 2.4.2 ... how do we, by configuration, make the Gradle openjpa configuration (whatever that is...) also use 2.4.3? Clearly buildscript dependencies is not sufficient.

radcortez commented 5 years ago

Also @radcortez, when this plugin is applied in a project and I do gradle dependencies on that project, then an openjpa configuration is shown in Gradle's dependencies report for that project. However, it's not obvious where that configuration comes from or why it's there.

For example, an open source project I'm working on uses this plugin. It also has dependencies on org.apache.openjpa:openjpa as well as spring-boot-starter-data-jpa. Seeing that openjpa configuration in Gradle's dependency report for the very first time, it is not obvious which of the project's three jpa-related dependencies that openjpa configuration comes from.

It would be very valuable to users of the plugin, in my opinion, if you explained somewhere in your README.md that this plugin adds that openjpa configuration and the reasons for it. Thanks in advance for that.

I understand. I can modify the README and add that additional information. The idea to add the openjpa closure was to clearly identify the configuration and tasks available in the plugin.

radcortez commented 5 years ago

@radcortez I'm looking into a problem related to this in apache/fineract#609 (which, as far as I know, incidentially is the same project that @lingocoder originally raised this issue for). I think there may be two separate issues:

With OpenJPA 3.1.0 (likely 3.0.0 already), there's, apparently, that ClosureBackedAction problem shown above. I'm guess that problem will you require you to look more into and fix in openjpa-gradle-plugin and release a new version?

With OpenJPA 2.4.3, which would be sufficient for Apache Fineract at least in the short term, given that OPENJPA-2730 went into v2.4.3, I'm hitting another problem, which I suspect is much simpler and can be resolved purely by configuration - I just can't figure out how, because my Gradle skills suck:

So in fineract-provider/build.gradle (of apache/fineract#609, not yet merged), we have:

buildscript {
  ext {
    openJPAVersion = '2.4.3'
  }
  repositories {
         jcenter()
         mavenCentral()
         maven { url "https://plugins.gradle.org/m2/" }
  }

  dependencies {
     classpath 'com.bmuschko:gradle-tomcat-plugin:2.5',
               'nl.javadude.gradle.plugins:license-gradle-plugin:0.11.0',
               'org.zeroturnaround:gradle-jrebel-plugin:1.1.2',
               'org.springframework.boot:spring-boot-gradle-plugin:2.1.3.RELEASE' // also change springDataJpaVersion below
     classpath "org.apache.openjpa:openjpa:$openJPAVersion"
     classpath 'com.radcortez.gradle:openjpa-gradle-plugin:3.0.0'
     classpath 'gradle.plugin.org.nosphere.apache:creadur-rat-gradle:0.2.2'
  }
}

But ./gradlew dependencies --configuration openjpa (thanks @lingocoder for pointing that out!) still shows:

openjpa
\--- org.apache.openjpa:openjpa:2.4.2
     +--- commons-lang:commons-lang:2.6
     +--- commons-collections:commons-collections:3.2.2
     +--- net.sourceforge.serp:serp:1.15.1
     |    \--- junit:junit:3.8.1
     +--- org.apache.geronimo.specs:geronimo-jms_1.1_spec:1.1.1
     +--- org.apache.geronimo.specs:geronimo-jta_1.1_spec:1.1.1
     +--- commons-pool:commons-pool:1.6
     +--- org.apache.xbean:xbean-asm5-shaded:3.17
     \--- org.apache.geronimo.specs:geronimo-jpa_2.0_spec:1.1

Note how that's still 2.4.2 ... how do we, by configuration, make the Gradle openjpa configuration (whatever that is...) also use 2.4.3? Clearly buildscript dependencies is not sufficient.

I'm also not a super Gradle expert :) I actually wrote this plugin to learn more about Gradle.

In the past I think I've also had some issues about overriding libraries from plugins, but I can't remember exactly. I need to have a look.

Most likely, this plugin should be aligned with OpenJPA, so you will have a version of the plugin for each version of OpenJPA (even if that only means that the internal library was bumped), but maybe that will make things more clear.

@vorburger @lingocoder any thoughts?

vorburger commented 5 years ago

Most likely, this plugin should be aligned with OpenJPA, so you will have a version of the plugin for each version of OpenJPA (even if that only means that the internal library was bumped), but maybe that will make things more clear.

@vorburger @lingocoder any thoughts?

If at all possible, I think ideally it would be better to let users of the plugin somehow override to run with another OpenJPA version (only possible as long as they are drop-in compatible, of course), without having to rely on you to change it and release a new version. I've just asked about this on https://discuss.gradle.org/t/how-to-change-the-version-of-dependency-of-a-gradle-plugin-as-an-end-user/32456 - let's see if someone is willing to shed some light on this there.

lingocoder commented 5 years ago

...any thoughts?

The first off-the-top-of-my-head thought that sprang to mind as an alternative to your hard-coded openjpa configuration, was Gradle's preferred convention for plugins: Detached Configurations.

You could adapt the code in @melix's example there. But rather than using the static, hard-coded openjpa dependency coordinates like you do now, you could instead compute it more dynamically from something like a user-supplied openjpaVersion property or something.

Here are some more references that might be informative:

lingocoder commented 5 years ago

the openjpa closure was to clearly identify the configuration and tasks available in the plugin

Ironically, that is the thing that confused me the most :) Your plugin exposes two different things with the same name:

  1. The „closure“ named openjpa (defined by this code)
  2. The custom configuration named openjpa (defined by this code)
radcortez commented 5 years ago

@lingocoder @vorburger This is not forgotten. I have some free cycles now and I'm looking into this. Sorry for the delay. I'll keep you posted.

radcortez commented 5 years ago

@lingocoder:

The issue java.lang.NoClassDefFoundError: org/gradle/api/internal/ClosureBackedAction it's fixed. This is because I was using this Gradle class in the plugin. My bad, since it was in the internal package and it was not part of the public API. This class was moved to the public API in Gradle 5, so it was not working for that Gradle version.

Regarding the JDK 11, it should also be working. There was an issue about a missing annotation not available in JDK 11 (it was removed from 9), but I added it into the class path and it should be good.

The custom configuration and dependencies, after looking into it, I've realised that I've done it that way so I could resolve the dependencies required to run the metamodel, but not leak and polute the project dependencies used by the project. I guess I was not aware about the detached configuration or it was not available when I wrote it. Anyway, I've moved that to use a detached configuration and it should be good now.

@vorburger:

You should be able to override the OpenJPA version just by setting the property metamodelDependency in the metamodel closure:

openjpa {
    metamodel {
        metamodelOutputFolder 'src/com/test'
        metamodelDependency 'org.apache.openjpa:openjpa:3.1.0'
    }
}

It defaults to org.apache.openjpa:openjpa:3.1.0, so it can be omitted.

Finally, @lingocoder @vorburger it would be great if any of you could check if these works for you. I haven't released a version yet, since I wanted your feedback. Can any of you checkout the plugin, build it and publish it locally and test it? Thank you!

radcortez commented 5 years ago

Hey @lingocoder @vorburger.

Got no news from you, so I went ahead and released the new version: https://bintray.com/radcortez/radcortez/openjpa-gradle-plugin/3.1.0

Please let me know if everything is ok.

Cheers,