2016-09-22 91 views
3

我想註冊一個自定義的CharsetProvider能夠使用X-Gsm7Bit編碼。我使用Logica的供應商https://github.com/OpenSmpp/opensmpp/tree/master/charset/src/main/java/org/smpp/charset。 要註冊這個新的字符集提供商,我使用內容org.smpp.charset.Gsm7BitCharsetProviderMETA-INF/services/java.nio.charsets.spi.CharsetProvider文件。春季啓動1.4.x和自定義CharsetProvider

我無法使它工作。 測試應用程序的來源是這裏https://github.com/asmsoft/provider

我得到java.util.ServiceConfigurationError: java.nio.charset.spi.CharsetProvider: Provider org.smpp.charset.Gsm7BitCharsetProvider not found當我開始它作爲脂肪罐子

mvn clean 
mvn package 
java -jar target/provider-1.0-SNAPSHOT.jar 

如果我mvn spring-boot:run啓動它,我得到java.io.UnsupportedEncodingException: X-Gsm7Bit

而且一切正常時,我用我的IDE啓動應用程序。

目前我解決了我的問題,如下所示:我已經把jar提供的自定義字符集轉換爲JAVA_HOME/jre/lib/ext,並且一切按預期工作,字符集正在註冊。

我對這個解決方案不滿意,我想請求您的幫助。

+0

嵌套jar從'lib'移動到'BOOT-INF/lib'應該沒有什麼區別,因爲兩者只對Boot的類加載器而不是JVM的app類加載器可見。您能否提供一個能夠再現問題的小樣本,並說明如何以及何時嘗試使用自定義提供程序? –

+0

@AndyWilkinson,感謝您的回覆,我已經更改了問題的描述並添加了一個鏈接到測試應用程序。 –

回答

2

我想你在JDK中遇到了一個錯誤。該javadoc for CharsetProvider說:

字符集提供商通過當前線程的上下文類加載擡頭

然而,code that looks up the providers講述了一個不同的故事:

ClassLoader cl = ClassLoader.getSystemClassLoader(); 
ServiceLoader<CharsetProvider> sl = 
    ServiceLoader.load(CharsetProvider.class, cl); 

正如你所看到的,它使用系統類加載器而不是線程的上下文類加載器。

它可以在您的IDE中使用,因爲您的應用程序的類及其依賴項都可用於系統類加載器。當你將應用程序打包到一個胖的jar包中時,它會失敗,因爲你的應用程序的類和它們的依賴關係可以被Spring Boot的類加載器使用,該加載器是系統類加載器的子類。在任何使用其他類加載器的環境中,您都會遇到同樣的問題,例如傳統的戰爭部署到servlet容器。

要避免此問題,您需要使提供程序可用於系統類加載器。正如你發現的那樣,把它放在JAVA_HOME/jre/lib/ext是實現這一目標的一種方法。其他選項包括使用陰影的jar而不是fat jar,或者後處理fat jar以將提供者的類直接添加到jar的根目錄,而不是嵌套的jar。

+0

感謝您的回覆,是的,我知道關於類加載器的問題,我只是想知道是否有任何方法可以解決它適合使用特別是彈簧啓動啓動器和胖jar沒有複製提供程序jar,因爲它需要更多的部署和支持努力。 –

1

由於Andy Wilkinson mentioned,你可能打一個bug,即這一項(2002年創建):https://bugs.openjdk.java.net/browse/JDK-4619777

我不知道是否能解決你的問題,但你可以直接使用CharsetProvider得到Charset,東西線:

Charset charset = new CharsetProvider().charsetForName("..."); 

你甚至可以創建一個實用的方法來獲得具有手動回退一CharsetCharsetProvider S:

Charset getCharset(String charsetName) { 
    if (Charset.isSupported(charsetName)) { 
     return Charset.forName(charsetName); 
    } 

    Charset charset = new org.smpp.charset.Gsm7BitCharsetProvider().charsetForName(charsetName); 
    if (charset != null) { return charset; } 
    charset = new com.beetstra.jutf7.CharsetProvider().charsetForName(charsetName); 
    if (charset != null) { return charset; } 
    // more fallbacks here ... 
    return null; 
} 

儘管這只是解決所提到的JDK bug的一種解決方法,因爲這正是通過註冊CharsetProvider s自動執行的邏輯。