Jasypt 在 Android 5.1.1 及更高版本上无法初始化,ClassLoader 为空
Jasypt fails to initialize on Android 5.1.1 and above, ClassLoader is null
我通常使用带有标准 PBE 加密器的 Jasypt (compile 'org.jasypt:jasypt:1.9.2'
)
StandardPBEByteEncryptor strongBinaryEncryptor = new StandardPBEByteEncryptor();
strongBinaryEncryptor.setAlgorithm("...");
strongBinaryEncryptor.setKeyObtentionIterations(...);
strongBinaryEncryptor.setProviderName(BouncyCastleProvider.PROVIDER_NAME);
strongBinaryEncryptor.setPassword("...");
byte[] encryptedBytes = strongBinaryEncryptor.encrypt(bytes);
这曾经没有问题,但现在它因以下根异常而崩溃:
E/AndroidRuntime: Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Class java.lang.ClassLoader.loadClass(java.lang.String)' on a null object reference
E/AndroidRuntime: at org.jasypt.normalization.Normalizer.initializeIcu4j(Normalizer.java:139)
E/AndroidRuntime: at org.jasypt.normalization.Normalizer.normalizeToNfc(Normalizer.java:96)
E/AndroidRuntime: at org.jasypt.encryption.pbe.StandardPBEByteEncryptor.initialize(StandardPBEByteEncryptor.java:661)
E/AndroidRuntime: at org.jasypt.encryption.pbe.StandardPBEByteEncryptor.encrypt(StandardPBEByteEncryptor.java:873)
相同的代码适用于 Kitkat phone 和 Lollipop 模拟器,但例如在 OnePlusOne 上会崩溃。
如果你看源码,你看到的是这样的:
static void initializeIcu4j() throws ClassNotFoundException {
Thread.currentThread().getContextClassLoader().loadClass(ICU_NORMALIZER_CLASS_NAME);
useIcuNormalizer = Boolean.TRUE;
}
也就是说Thread.currentThread().getContextClassLoader()
是null
。这在过去不会发生,而且我真的不知道是什么导致了这种行为变化。我也不确定我应该怎么做才能解决它。
有什么想法吗?
基于已从 Google 代码中删除的 wiki 页面,这实际上也曾经是 Dalvik 中的一个错误,但在 Froyo 中提交了一个补丁。然而,ART 似乎重新出现了这个完全相同的问题。
显然根据 https://web.archive.org/web/20120303234738/http://code.google.com/p/dalvik/wiki/JavaxPackages 解决方案是在 Activity.onCreate()
中手动初始化 class 加载器。
public class HelloStax extends Activity {
@Override public void onCreate(Bundle savedInstanceState) {
...
/*
* Ensure the factory implementation is loaded from the application
* classpath (which contains the implementation classes), rather than the
* system classpath (which doesn't).
*/
Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
...
}
我通常使用带有标准 PBE 加密器的 Jasypt (compile 'org.jasypt:jasypt:1.9.2'
)
StandardPBEByteEncryptor strongBinaryEncryptor = new StandardPBEByteEncryptor();
strongBinaryEncryptor.setAlgorithm("...");
strongBinaryEncryptor.setKeyObtentionIterations(...);
strongBinaryEncryptor.setProviderName(BouncyCastleProvider.PROVIDER_NAME);
strongBinaryEncryptor.setPassword("...");
byte[] encryptedBytes = strongBinaryEncryptor.encrypt(bytes);
这曾经没有问题,但现在它因以下根异常而崩溃:
E/AndroidRuntime: Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Class java.lang.ClassLoader.loadClass(java.lang.String)' on a null object reference
E/AndroidRuntime: at org.jasypt.normalization.Normalizer.initializeIcu4j(Normalizer.java:139)
E/AndroidRuntime: at org.jasypt.normalization.Normalizer.normalizeToNfc(Normalizer.java:96)
E/AndroidRuntime: at org.jasypt.encryption.pbe.StandardPBEByteEncryptor.initialize(StandardPBEByteEncryptor.java:661)
E/AndroidRuntime: at org.jasypt.encryption.pbe.StandardPBEByteEncryptor.encrypt(StandardPBEByteEncryptor.java:873)
相同的代码适用于 Kitkat phone 和 Lollipop 模拟器,但例如在 OnePlusOne 上会崩溃。
如果你看源码,你看到的是这样的:
static void initializeIcu4j() throws ClassNotFoundException {
Thread.currentThread().getContextClassLoader().loadClass(ICU_NORMALIZER_CLASS_NAME);
useIcuNormalizer = Boolean.TRUE;
}
也就是说Thread.currentThread().getContextClassLoader()
是null
。这在过去不会发生,而且我真的不知道是什么导致了这种行为变化。我也不确定我应该怎么做才能解决它。
有什么想法吗?
基于已从 Google 代码中删除的 wiki 页面,这实际上也曾经是 Dalvik 中的一个错误,但在 Froyo 中提交了一个补丁。然而,ART 似乎重新出现了这个完全相同的问题。
显然根据 https://web.archive.org/web/20120303234738/http://code.google.com/p/dalvik/wiki/JavaxPackages 解决方案是在 Activity.onCreate()
中手动初始化 class 加载器。
public class HelloStax extends Activity {
@Override public void onCreate(Bundle savedInstanceState) {
...
/*
* Ensure the factory implementation is loaded from the application
* classpath (which contains the implementation classes), rather than the
* system classpath (which doesn't).
*/
Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
...
}