I have a custom-made class that extends java.nio.charset.spi.CharsetProvider whose name is written in META-INF/services/java.nio.charset.spi.CharsetProvider. I have found two problems when the VM loads the custom-made CharsetProvider. (1) We can put blank lines, spaces, tabs and comments following '#' in META-INF/services/java.nio.charset.spi.CharsetProvider. But java.nio.charset.Charset does not ignore them. (2) java.nio.charset.Charset tries to load the class using Class.forName(className), which means that the ClassLoader that loaded java.nio.charset.Charset is used. Most likely, java.nio.charset.Charset is in the VM's bootstrap classpath, so the custom-made CharsetProvider must also be found somewhere in the VM's bootstrap classpath. Just putting it in the usual classpath does not work. And here is my proposed patch: --- java/nio/charset/Charset.java.orig Wed Jun 1 16:56:01 2005 +++ java/nio/charset/Charset.java Wed Jun 1 17:28:43 2005 @@ -267,8 +267,29 @@ String s = rdr.readLine(); if (s == null) break; + int i = -1, j = -1; + for (int k = 0; k < s.length(); k++) + { + char c = s.charAt(k); + if (c == ' ' || c == ' ') + continue; + if (c == '#') + break; + i = k; + break; + } + if (i < 0) + continue; + for (j = i + 1; j < s.length(); j++) + { + char c = s.charAt(j); + if (c == ' ' || c == ' ' || c == '#') + break; + } + s = s.substring(i, j); CharsetProvider p = - (CharsetProvider) ((Class.forName(s)).newInstance()); + (CharsetProvider) ((Class.forName(s, true, + ClassLoader.getSystemClassLoader())).newInstance()); set.add(p); } }
> + (CharsetProvider) ((Class.forName(s, true, > + ClassLoader.getSystemClassLoader())).newInstance()); This must be Thread.currentThread().getContextClassLoader() instead of ClassLoader.getSystemClassLoader().
This is the patch applied in Kaffe. ChangeLog: 2005-06-05 Ito Kazumitsu <kaz@maczuka.gcd.org> * java/nio/charset/Charset.java (providers2): Allow spaces and comments in META-INF/services/java.nio.charset.spi.CharsetProvider. Load the provider using the context class loader. --- java/nio/charset/Charset.java.orig Wed May 18 06:28:40 2005 +++ java/nio/charset/Charset.java Sun Jun 5 10:52:25 2005 @@ -267,8 +267,29 @@ String s = rdr.readLine(); if (s == null) break; + int i = -1, j = -1; + for (int k = 0; k < s.length(); k++) + { + char c = s.charAt(k); + if (c == ' ' || c == '\t') + continue; + if (c == '#') + break; + i = k; + break; + } + if (i < 0) + continue; + for (j = i + 1; j < s.length(); j++) + { + char c = s.charAt(j); + if (c == ' ' || c == '\t' || c == '#') + break; + } + s = s.substring(i, j); CharsetProvider p = - (CharsetProvider) ((Class.forName(s)).newInstance()); + (CharsetProvider) ((Class.forName(s, true, + Thread.currentThread().getContextClassLoader())).newInstance()); set.add(p); } }
Thanks, I'll check this into Classpath.
Confirmed.
Actually I think Charset should use the ServiceFactory class for this. And, I don't see why the context class loader should be used -- it seems to me that the system class loader is a reasonable choice, but that, in addition, we should write a test case to see which is correct.
> And, I don't see why the context class loader should be used -- it seems > to me that the system class loader is a reasonable choice, but that, > in addition, we should write a test case to see which is correct. I think the context class loader should be used because (1) Sun's API document of java.nio.charset.spi.CharsetProvider says: Charset providers are looked up via the current thread's context class loader. (2) If charset providers are to be loaded via the system class loader, the user may have to specify -bootclasspath or something. Just putting the custom-made provider somewhere in the classpath may not work.
I have a patch which uses ServiceFactory and the context class loader.
Subject: Bug 22963 CVSROOT: /cvsroot/classpath Module name: classpath Branch: Changes by: Tom Tromey <tromey@savannah.gnu.org> 05/09/18 00:56:22 Modified files: . : ChangeLog java/nio/charset: Charset.java Log message: PR classpath/22963: * java/nio/charset/Charset.java (forName): Javadoc fix. (providers2): Use ServiceFactory. CVSWeb URLs: http://savannah.gnu.org/cgi-bin/viewcvs/classpath/classpath/ChangeLog.diff?tr1=1.4843&tr2=1.4844&r1=text&r2=text http://savannah.gnu.org/cgi-bin/viewcvs/classpath/classpath/java/nio/charset/Charset.java.diff?tr1=1.25&tr2=1.26&r1=text&r2=text
Fix checked in