首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ResourceBundle与ClassLoader

ResourceBundle与ClassLoader
EN

Stack Overflow用户
提问于 2020-11-30 14:28:13
回答 2查看 359关注 0票数 0

我希望构建由属性文件中的键/值对的一部分组成的ResourceBundles,从而与将这些部分或部分存储在单个文件中相比,节省了相当数量的文件。这些部分由以"#“开头的标题行标记,并以空行分隔。下面代码之后的示例属性文件包含两个部分:

  • #FileChooser
  • #OptionPane

我试图通过在ClassLoader (.)中传递一个只读取所需部分的自定义ClassLoader来实现这一点。方法。CustomClassLoader可以很好地减少键定义,但是ResourceBundle仍然包含属性文件的所有键。

代码语言:javascript
复制
import java.io.*;
import java.util.*;

public class ResourceReader {

  public ResourceReader() {
    Locale locale= Locale.getDefault();
    ResourceBundle i18n= ResourceBundle.getBundle("ComponentBundle", locale,
                    new CustomClassLoader("#FileChooser"));
    Enumeration<String> enu= i18n.getKeys();
    System.out.println("Keys of ResourceBundle");
    printEnumeration(enu);
  }


  public static void main(String args[]) {
    new ResourceReader();
  }

  public void printEnumeration(Enumeration<String> enu) {
    int i= 1;
    while (enu.hasMoreElements()) {
      System.out.println(i+".: "+enu.nextElement());
      i++;
    }
  }


//////////////////////////////////////////////////////////////////////////////

  public class CustomClassLoader extends ClassLoader {
    String section;

    public CustomClassLoader(String section) {
      this.section= section;
    }

    @Override
    public Class findClass(String name) throws ClassNotFoundException {
      byte[] b = loadClassFromFile(name);
//System.out.writeBytes(b); // OK.
      return defineClass(name, b, 0, b.length);
    }
 
    private byte[] loadClassFromFile(String fileName)  {
      InputStream inputStream = getClass().getClassLoader().getResourceAsStream(
                      fileName.replace('.', File.separatorChar) + ".properties");
      byte[] buffer;
      ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
      int nextValue = 0;
      try {
        while ( (nextValue = inputStream.read()) != -1 ) {
          byteStream.write(nextValue);
        }
      } catch (IOException e) {
        e.printStackTrace();
      }
      buffer = extractSection(byteStream.toString(), section);
      return buffer;
    }

    private byte[] extractSection(String stream, String caption)  {
      final String LINE_SEP= System.getProperty("line.separator", "\n");
      String[] lines= stream.split(LINE_SEP);
//    Detect first and last line (exclusive) of section.
      int iEnd= 0, iStart= -1;
      for (int i=0; i<lines.length; i++) {
        lines[i]= lines[i].trim();
        if (iStart==-1) {
          if (!lines[i].equals(caption)) continue;
          iStart= i+1;
          i++;
        }
        else if (lines[i].isEmpty()) {
          iEnd= i;
          break;
        }
      }
      if (iEnd==0) iEnd= lines.length+1;
      StringBuilder sb= new StringBuilder();
      for (int i=iStart; i<iEnd; i++)
        sb.append(lines[i]+LINE_SEP);
      return sb.toString().getBytes();
    }
  }

}
//////////////////////////////////////////////////////////////////////////////

/* // File ComponentBundle.properties

代码语言:javascript
复制
#FileChooser
acceptAllFileFilterText= All files (*.*)
cancelButtonText= Cancel
cancelButtonToolTipText= Cancel

#OptionPane
Cancel= Cancel
Input= Input
Message= Message
No= No
// End of ComponentBundle.properties

*/

EN

回答 2

Stack Overflow用户

发布于 2020-12-01 13:16:03

您不会以这种方式获得受限的资源包,因为您已经重写了findClass,可以将属性文件的字节作为一个类返回。要了解正在发生的事情,请添加以下代码:

代码语言:javascript
复制
public URL getResource(String name)
{
    var url = super.getResource(name);
    System.out.println("getResource "+name+" -> "+url);
    return url;
}
public Class findClass(String name) throws ClassNotFoundException {
    System.out.println("findClass "+name);
...

然后,您可以看到ResourceBundle的内部工作方式,它查找所有键,因为它正在加载文件url的内容--您的代码是而不是使用的:

代码语言:javascript
复制
findClass ComponentBundle
getResource ComponentBundle.properties -> file:/C:/some/path/to/ComponentBundle.properties
findClass ComponentBundle_en
getResource ComponentBundle_en.properties -> null
findClass ComponentBundle_en_GB
getResource ComponentBundle_en_GB.properties -> null

如果覆盖getResource(String name)并使生成的文件适合键的子集,并将URL传回子集文件,那么就有可能让您的绑定器工作。

当您只为所有应用程序定义一个资源包文件,或者为每个子组件定义一个资源包文件时,这似乎需要做很多工作。

票数 1
EN

Stack Overflow用户

发布于 2020-12-02 23:46:34

如果一个人绝对想使用ResourceBundle的一个子集,这可能是一种方法--尽管不是很优雅,因为完整的包需要被读取和过滤。

代码语言:javascript
复制
int componentFlag= ...;
final int FILE_CHOOSER= 1, OPTION_PANE= 2;

ResourceBundle i18n= ResourceBundle.getBundle("ComponentBundle", locale);
String prefix;
Set<String> set= i18n.keySet();
if ((componentFlag&FILE_CHOOSER)>0)
  prefix= "FileChooser.";
else if ((componentFlag&OPTION_PANE)>0)
  prefix= "OptionPane.";
set.stream().filter(s -> s.startsWith(prefix))
    .forEach(s -> UIManager.put(s, i18n.getString(s)));
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65075437

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档