Accessing message bundles in buildsrc


(Barry Becker) #1

Back in 2013 I asked a question (now on old forum) about how to access message bundles in gradle scripts.

The answer, to put them in buildSrc/src/main/resources worked great for many years. However, in recent versions, somewhere around 2.10 to 2.14 something changed, and it no longer works. It also does not work in version 3.x or 4.0 of gradle. I don’t know what changed, but I would very much like to know how to get it working again with more recent versions of gradle.

The error I get is
"Can’t find bundle for base name html, locale en"


(uklance) #2

Perhaps the classloading hierarchy has changed and the plugin is no longer loaded by the same classloader as the rest of the script. In which case you’ll need to use ResourceBundle.getBundle(String, Locale, Classloader) instead.

See here

Gets a resource bundle using the specified base name and locale, and the caller’s class loader. Calling this method is equivalent to calling

getBundle(baseName, locale, this.getClass().getClassLoader()),

Eg:

ResourceBundle.getBundle('html', locale, MyPlugin.classLoader)


(Barry Becker) #3

Thanks, but I’m not sure what plugin you are referring to. I do not have
anything in the buildSrc directory except src/main/resources/*.properties.


(uklance) #4

Perhaps you could fabricate a UrlClassloader

URL[] urls = buildscript.configurations.classpath.files.collect { it.toURI().toURL() } 
Classloader cl = new java.net.URLClassloader(urls, null)
def bundle = ResourceBundle.getBundle('html', locale, cl)

(Barry Becker) #5

Unfortunately that did not work. I still get the same error. Here is the exact code I tried:

URL[] urls = buildscript.configurations.classpath.files.collect { it.toURI().toURL() }
ClassLoader classLoader = new URLClassLoader(urls, (ClassLoader) null)
def labels = ResourceBundle.getBundle(‘html’, Locale.ENGLISH, classLoader)


(uklance) #6

Can you add buildSrc/src/main/java/DummyClass.java then do

Classloader classLoader = DummyClass.classloader
def labels = ResourceBundle.getBundle('html', Locale.ENGLISH, classLoader)

(Barry Becker) #7

That did not work either, but I did notice something interesting.
I can access the resource bundle from the build.gradle in the root project.
In other words, ResourceBundle.getBundle(‘html’, Locale.ENGLISH) successfully retrieves the resource bundle from buildSrc when called in the root project, but not when called from a build.gradle in a subproject. Why is that? All the documentation says that there can only be a single buildSrc directory at the top level and all subprojects should be able to access it. Furthermore, it used to work fine (before version 2.10 or so).


(uklance) #8

Please post your settings.gradle and tell us which subproject can’t ‘see’ buildSrc


(Barry Becker) #9

The contents of my settings.gradle file (in root project) is

include ‘imageproc’, ‘apps’, ‘webdeployment’

It was the webdeployment projects build.gradle file that was nuable to get the resource bundle.
Since I can get the resource bundle in the root project, I am unblocked, but it would be nice to understand why the subproject cannot get the bundle.


(uklance) #10

This is strange, all projects in a multi-module build should have buildSrc on the buildscript classpath

Where is your code? In a Task.doLast { ... }? Or somewhere else? (I know there’s some strangeness with the buildscript { ... } classloader)


(Barry Becker) #11

The full project is on github if you want to look closer:
https://github.com/bb4/applets


(uklance) #12

You have a gradle wrapper in the root folder but then you also have a gradle wrapper in the webdeployment folder. How are you executing gradlew? From root folder (correct) or from webdeployment folder? (may have issues)

Try ./gradlew :webdeployment:build
from the root folder


(Barry Becker) #13

I think I do not need it in the webdeployment folder. I am going to try removing it there. I had originally added it there because I thought I needed an older version of gradle to run there in order to get the localeBundle. I would like to run from the root, but running in webdeployment should work too.


(Barry Becker) #14

I created a minimal-locale-test branch in https://github.com/bb4/applets hoping to create a simple reproducible case, however, it then worked as expected. So when I removed all the subprojects, it was able to read the message bundle from buildSrc, but with the subprojects present it could not. Maybe I can add things back gradually and see where it stops working.


(uklance) #15

I suspect it’s the extra wrapper in the webdeployment directory. When you run gradlew from that directory gradle thinks it’s the root (ie not a multi-module build)

Have you tried ./gradlew :webdeployment:build from the root directory?


(Barry Becker) #16

I removed the gradle wrapper from the webdeployment directory.
I made a change that fixed the problem.
Moving this line
ext.depVersion = getDependentVersion()
from the top of /webdeployment/build.grade to the top of /build.gradle
seemed to allow it to work.
The working version is now on the master branch.


(uklance) #17

You didn’t fix the problem, you moved the code from a place where it wasn’t working to a place where it is working. It’s still unexplained why the buildSrc isn’t on the subproject classpath