Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java ObjectInputStream#readObject使用外部Jar类引发ClassNotFoundException_Java_Spring_Spring Boot_Java 8 - Fatal编程技术网

Java ObjectInputStream#readObject使用外部Jar类引发ClassNotFoundException

Java ObjectInputStream#readObject使用外部Jar类引发ClassNotFoundException,java,spring,spring-boot,java-8,Java,Spring,Spring Boot,Java 8,因此,我有一个Spring引导应用程序,它从以下路径加载外部JAR: java -cp "main-0.0.1-SNAPSHOT.jar" -Dloader.path="%USERPROFILE%\Addons\" -Dloader.main=moe.ofs.backend.BackendApplication org.springframework.boot.loader.PropertiesLauncher 主jar在编译时不知道外部jar。通过指定 -Dloader.path=… 所有外

因此,我有一个Spring引导应用程序,它从以下路径加载外部JAR:

java -cp "main-0.0.1-SNAPSHOT.jar" -Dloader.path="%USERPROFILE%\Addons\" -Dloader.main=moe.ofs.backend.BackendApplication org.springframework.boot.loader.PropertiesLauncher
主jar在编译时不知道外部jar。通过指定

-Dloader.path=…

所有外部jar都依赖于“main-0.0.1-SNAPSHOT.jar”中的接口,它们或多或少都应该进行对象序列化。 该接口称为
Configurable
,它提供了如下两种默认方法:

default <T extends Serializable> void writeFile(T object, String fileName) throws IOException {
    Path configFilePath = configPath.resolve(fileName + ".data");
    FileOutputStream fileOutputStream = new FileOutputStream(configFilePath.toFile());
    ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
    objectOutputStream.writeObject(object);
    objectOutputStream.close();
}

在一些测试之后,我觉得Class.forName()抛出了
ClassNotFoundException
,因为默认的类加载器很难找到
moe.ofs.addon.navdata.domain.Navaid
,这正是我试图反序列化的类

导航设备实现可序列化
,并且它还有一个
静态最终长serialVersionUID

我曾希望通过为当前线程设置上下文类加载器来解决这个问题,以便
ObjectInputStream
将使用Spring引导类加载器来解析
Navaid
类:

Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
当打印出来时,它会给出如下信息

Thread.currentThread().getContextClassLoader() = org.springframework.boot.loader.LaunchedURLClassLoader@7a0b4753
除了
ObjectInputStream#readObject
仍然抛出
ClassNotFoundException
。 如果我显式调用从Spring引导加载程序加载Navaid类,例如:

getClass().getClassLoader().loadClass("moe.ofs.addon.navdata.domain.Navaid");
它返回一个无任何问题的
导航设备
实例

正如所料,当直接呼叫时

Class.forName("moe.ofs.addon.navdata.domain.Navaid")
抛出
ClassNotFoundException
,即使线程上下文加载程序已显式设置为
launchDurlClassLoader
ObjectInputStream#readObject
总是通过调用系统默认类加载器加载类来尝试解析类

然后,我尝试使用
LaunchedURLClassLoader
加载
ObjectInputStream
,但实例仍然使用系统默认类加载器中的
Class.forName()

ClassLoader cl = getClass().getClassLoader();

Thread.currentThread().setContextClassLoader(cl);

System.out.println("Thread.currentThread().getContextClassLoader() = " + Thread.currentThread().getContextClassLoader());

Class<?> tClass = getClass().getClassLoader().loadClass("java.io.ObjectInputStream");
System.out.println("tClass = " + tClass);

Path configFilePath = configPath.resolve(fileName + ".data");
FileInputStream fileInputStream = new FileInputStream(configFilePath.toFile());

Constructor<?> constructor = tClass.getConstructor(InputStream.class);

ObjectInputStream objectInputStream = (ObjectInputStream) constructor.newInstance(fileInputStream);

objectInputStream.readObject();  // throws ClassNotFoundException
ClassLoader cl=getClass().getClassLoader();
Thread.currentThread().setContextClassLoader(cl);
System.out.println(“Thread.currentThread().getContextClassLoader()=”+Thread.currentThread().getContextClassLoader());
类tClass=getClass().getClassLoader().loadClass(“java.io.ObjectInputStream”);
System.out.println(“tClass=“+tClass”);
路径configFilePath=configPath.resolve(文件名+“.data”);
FileInputStream FileInputStream=新的FileInputStream(configFilePath.toFile());
Constructor=tClass.getConstructor(InputStream.class);
ObjectInputStream ObjectInputStream=(ObjectInputStream)构造函数.newInstance(fileInputStream);
objectInputStream.readObject();//抛出ClassNotFoundException

欢迎您的任何意见。提前感谢。

据我所知,您应该在
ObjectInputStream

诸如此类:

default <T extends Serializable> T readFile(String fileName, ClassLoader loader) throws IOException, ClassNotFoundException {
    Path configFilePath = configPath.resolve(fileName + ".data");
    FileInputStream fileInputStream = new FileInputStream(configFilePath.toFile());
    ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream){
       protected Class<?> resolveClass(ObjectStreamClass desc)
                     throws IOException, ClassNotFoundException {
          try {
              return Class.forName(desc.getName(), false, loader);
          } catch(ClassNotFoundException cnfe) {
              return super.resolveClass(desc);
          }
       }
   };
   return (T) objectInputStream.readObject();
}
default T readFile(字符串文件名、类加载器)抛出IOException、ClassNotFoundException{
路径configFilePath=configPath.resolve(文件名+“.data”);
FileInputStream FileInputStream=新的FileInputStream(configFilePath.toFile());
ObjectInputStream ObjectInputStream=新ObjectInputStream(fileInputStream){
受保护类resolveClass(ObjectStreamClass desc)
抛出IOException,ClassNotFoundException{
试一试{
返回类.forName(desc.getName(),false,loader);
}捕获(ClassNotFoundException cnfe){
返回super.resolveClass(desc);
}
}
};
返回(T)objectInputStream.readObject();
}
我自己从未试过,但值得一试

如果您的项目中有commons io,也会有问题

ClassLoader cl = getClass().getClassLoader();

Thread.currentThread().setContextClassLoader(cl);

System.out.println("Thread.currentThread().getContextClassLoader() = " + Thread.currentThread().getContextClassLoader());

Class<?> tClass = getClass().getClassLoader().loadClass("java.io.ObjectInputStream");
System.out.println("tClass = " + tClass);

Path configFilePath = configPath.resolve(fileName + ".data");
FileInputStream fileInputStream = new FileInputStream(configFilePath.toFile());

Constructor<?> constructor = tClass.getConstructor(InputStream.class);

ObjectInputStream objectInputStream = (ObjectInputStream) constructor.newInstance(fileInputStream);

objectInputStream.readObject();  // throws ClassNotFoundException
default <T extends Serializable> T readFile(String fileName, ClassLoader loader) throws IOException, ClassNotFoundException {
    Path configFilePath = configPath.resolve(fileName + ".data");
    FileInputStream fileInputStream = new FileInputStream(configFilePath.toFile());
    ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream){
       protected Class<?> resolveClass(ObjectStreamClass desc)
                     throws IOException, ClassNotFoundException {
          try {
              return Class.forName(desc.getName(), false, loader);
          } catch(ClassNotFoundException cnfe) {
              return super.resolveClass(desc);
          }
       }
   };
   return (T) objectInputStream.readObject();
}