Tackle deprecation warning generated by Gradle 4.x #1853
Conversation
In Gradle 4.x, the method getClassesDir() in SourceSetOutput has been deprecated in favor of a new method getClassesDirs(). Use reflection to invoke this method, if it is available, so that consumers using Gradle 4.x are spared the deprecation warning. Fall back to the original method for consumers using Gradle 3.x. Fixes #1686
Method getClassesDirs = SourceSetOutput.class.getMethod("getClassesDirs"); | ||
|
||
// use alternative method available in Gradle 4.0 | ||
FileCollection classesDirs = (FileCollection)getClassesDirs.invoke(sourceSet.getOutput()); |
inikolaev
Dec 3, 2017
Contributor
I think it would be better to encapsulate this logic in some kind of SourceSetOutputResolver
or something like that which would handle differences between different versions of Gradle and would return a list of paths.
For example something like this (haven't tested the code though):
class SourceSetOutputResolver {
private static final Method getClassesDirs;
static {
try {
getClassesDirs = SourceSetOutput.class.getMethod("getClassesDirs");
} catch (NoSuchMethodException e) {
getClassesDirs = null;
}
}
public Set<File> getFiles(SourceSet sourceSet) {
SourceSetOutput sourceSetOutput = sourceSet.getOutput();
if (getClassesDirs != null) {
FileCollection classesDirs = (FileCollection) getClassesDirs.invoke(sourceSetOutput);
return classesDirs.getFiles();
} else {
return Collections.singletonSet(sourceSetOutput.getClassesDir());
}
}
}
Alternatively it could be part of the current class.
I think it would be better to encapsulate this logic in some kind of SourceSetOutputResolver
or something like that which would handle differences between different versions of Gradle and would return a list of paths.
For example something like this (haven't tested the code though):
class SourceSetOutputResolver {
private static final Method getClassesDirs;
static {
try {
getClassesDirs = SourceSetOutput.class.getMethod("getClassesDirs");
} catch (NoSuchMethodException e) {
getClassesDirs = null;
}
}
public Set<File> getFiles(SourceSet sourceSet) {
SourceSetOutput sourceSetOutput = sourceSet.getOutput();
if (getClassesDirs != null) {
FileCollection classesDirs = (FileCollection) getClassesDirs.invoke(sourceSetOutput);
return classesDirs.getFiles();
} else {
return Collections.singletonSet(sourceSetOutput.getClassesDir());
}
}
}
Alternatively it could be part of the current class.
axelfontaine
Dec 3, 2017
Contributor
Why? What would be the benefit over the current simple implementation in this pull request?
Why? What would be the benefit over the current simple implementation in this pull request?
inikolaev
Dec 3, 2017
Contributor
Well at least to keep code DRY, because right now same logic is basically repeated twice. Easier to make changes in case Gradle changes API in the future again. It doesn't have to be a separate class, I just gave one possible solution and it could be just a private/protected method which encapsulates this logic.
And IMHO it's easier to follow this logic:
for (File directory: getClassesDirs()) {
URL classesUrl = directory.toURI().toURL();
getLogger().debug("Adding directory to Classpath: " + classesUrl);
extraURLs.add(classesUrl);
}
than figuring out what is going on in all these try-catch
blocks.
It's a rather simple change, and at the same time it's not a big deal. I just wanted to point out that there's some room for improvement.
Well at least to keep code DRY, because right now same logic is basically repeated twice. Easier to make changes in case Gradle changes API in the future again. It doesn't have to be a separate class, I just gave one possible solution and it could be just a private/protected method which encapsulates this logic.
And IMHO it's easier to follow this logic:
for (File directory: getClassesDirs()) {
URL classesUrl = directory.toURI().toURL();
getLogger().debug("Adding directory to Classpath: " + classesUrl);
extraURLs.add(classesUrl);
}
than figuring out what is going on in all these try-catch
blocks.
It's a rather simple change, and at the same time it's not a big deal. I just wanted to point out that there's some room for improvement.
smoothreggae
Dec 3, 2017
Author
Contributor
I could certainly move out the code that derives classesUrl
to a private method: this would avoid duplicating two lines (the first being the logging call and the second being the one adding classesUrl
to extraURLs
). A stronger case could be made for this were there more than one place in the file that had this change. Let me know if I should do this.
A separate class seems like overkill, though, since we have just this one instance of having to deal with different versions of Gradle. If the plugin chose to support more versions of Gradle and more such changes were needed, I suspect a separate class with appropriate utility methods would evolve from the required code changes.
I could certainly move out the code that derives classesUrl
to a private method: this would avoid duplicating two lines (the first being the logging call and the second being the one adding classesUrl
to extraURLs
). A stronger case could be made for this were there more than one place in the file that had this change. Let me know if I should do this.
A separate class seems like overkill, though, since we have just this one instance of having to deal with different versions of Gradle. If the plugin chose to support more versions of Gradle and more such changes were needed, I suspect a separate class with appropriate utility methods would evolve from the required code changes.
inikolaev
Dec 4, 2017
Contributor
Also another thing is that feature detection is performed for each subclass of AbstractFlywayTask
and for multiple SourceSet
-s potentially, but I would guess that it's not executed that many times to cause any issues.
I agree that using a class is an overkill but would still argue that pulling code into a separate method would improve readability and it takes less time to implement than was spent to discuss it :)
I also agree that this a simple use-case, I just try to avoid code duplication when ever possible.
Also another thing is that feature detection is performed for each subclass of AbstractFlywayTask
and for multiple SourceSet
-s potentially, but I would guess that it's not executed that many times to cause any issues.
I agree that using a class is an overkill but would still argue that pulling code into a separate method would improve readability and it takes less time to implement than was spent to discuss it :)
I also agree that this a simple use-case, I just try to avoid code duplication when ever possible.
@smoothreggae Thanks you very much for the pull request! Merged. |
Tackle deprecation warning generated by Gradle 4.x
Tackle deprecation warning generated by Gradle 4.x
In Gradle 4.x, the method getClassesDir() in SourceSetOutput has been
deprecated in favor of a new method getClassesDirs().
Use reflection to invoke this method, if it is available, so that
consumers using Gradle 4.x are spared the deprecation warning. Fall back
to the original method for consumers using Gradle 3.x.
Fixes #1686