Get ClassLoader Object from Caller

dan1st :

I have implemented a Plugin mechanism and language packs using ResourceBundles in Java.

It works perfectly fine if I want to get a ResourceBundle from the core program (not from a plugin).

The problem is that I want to add the possibility to create a ResourceBundle that is in the plugin and only works within the plugin.

Plugins are loaded using URLClassLoaders and Reflections. I cannot access (I don't want to) plugin ClassLoaders from the translation class. So, the program loads the plugin and executes a method inside the plugin later (The plugin is not in the Classpath) and that plugin executes the translate method.

In order to archieve this, I want to get the ClassLoader Object from the calling method.

Somethng like this or this might be useful, but I don't see a way to get the Class/ClassLoader and not the name of the class.

I thought that I could use the Stacktrace to get the ClassLoader of the calling method but I can only get the name using .getClassName and no Class or ClassLoader Object of the Caller.

This is what I have:

translate

public static String translate(Locale locale,String s) {
    for (ResourceBundle bundle : getResourceBundles(locale/*,Thread.currentThread().getStackTrace()[1].getClassLoader();*/)) {
        try {
            return bundle.getString(s);
        }catch (MissingResourceException e) {
            //ignore/next iteration
        }
    }
    return s;
}

getResourceBundles

private static Set<ResourceBundle> getResourceBundles(Locale locale,ClassLoader... loaders){
    Set<ResourceBundle> bundles=new HashSet<>();
    bundles.add(ResourceBundle.getBundle(BASE_NAME,locale,MyClass.class.getClassLoader()));
    for (ClassLoader loader : loaders) {
        ResourceBundle pluginBundle=getResourceBundle(g,loader);
        if (pluginBundle!=null) {
            bundles.add(pluginBundle);
        }
    }
    return bundles;
}
Holger :

I don’t think that this trial and error approach is a good idea. Neither is refetching all bundles for every single string. It doesn’t even seem that this translation service adds a value over the alternative of just letting the plugin read their bundle and call getString on it, at least not a value that justifies the overhead and complexity of the code.

Since the standard ResourceBundle.getBundle methods do already consider the caller’s context, the field declaration and acquisition expression would be a trivial single-liner when being placed within the plugin and invoking getString on it, is not more complicated than invoking your translation service’s method.

For completeness, getting the caller class in a standard way, is possible starting with Java 9. Then, you can do it like

private static final StackWalker STACK_WALKER
    = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);

public static String translate(Locale locale, String s) {
    for(ResourceBundle bundle: getResourceBundles(locale,
                                   STACK_WALKER.getCallerClass().getClassLoader())) {
        try {
            return bundle.getString(s);
        }catch (MissingResourceException e) {
            //ignore/next iteration
        }
    }
    return s;
}

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related