加载一个包并在里面 类
Load a package and inside classes
我正在创建一个包,其中包含我使用 wsimport 动态生成的一些 classes,现在我正在尝试加载它以供使用,我该怎么做?天生的?或者使用像 byte-buddy 这样的库,我尝试使用下面的代码将每个 class 加载到一个包中:
File [] files = new File("<Path to package in filesystem with classes (*.class)>").listFiles();
List<URL> classUrls = new ArrayList<>();
for(File file : files) {
classUrls.add(new URL("file://" + file.getAbsolutePath()));
}
URL[] classz = new URL[classUrls.size()];
classz = classUrls.toArray(classz);
URLClassLoader child = new URLClassLoader(classz);
Class.forName("com.abc.external.resources.genwn239aqyhmfz.SomeClass", true, child);
但我仍然收到(包裹:com.abc.external.resources.genwn239aqyhmfz.SomeClass)
java.lang.ClassNotFoundException: com.abc.external.resources.genwn239aqyhmfz.SomeClass
class 路径的规则与启动应用程序时必须遵守的规则没有什么不同。 class 路径条目是 不是 class 文件或包含它们的目录,而是包结构的根目录。
所以如果你要加载的class是com.abc.external.resources.genwn239aqyhmfz.SomeClass
,class路径条目必须是包含com
目录的目录,其中包含abc
目录等。如果您知道 classes 之一的预期全限定名,则很容易找到正确的目录。只需遍历文件层次结构,直到限定名称包含包组件的次数。但是,当您事先不知道名称时,查找它可能会很棘手。这是一个草图:
// pass the expected name of one class contained in f or null if not known
static void loadClasses(File f, String predictedName)
throws IOException, ClassNotFoundException {
File[] classes = f.listFiles((d,n)->n.endsWith(".class"));
if(classes == null || classes.length == 0) {
System.err.println("no classes or not a directory");
return;
}
if(predictedName == null) predictedName = predictName(classes[0]);
for(int p = predictedName.indexOf('.'); p >= 0; p = predictedName.indexOf('.', p+1))
f = f.getParentFile();
URLClassLoader classLoader = new URLClassLoader(new URL[] { f.toURI().toURL() });
String packageName = predictedName.substring(0, predictedName.lastIndexOf('.')+1);
for(File cf: classes) {
String name = cf.getName();
name = name.substring(0, name.length()-6); // strip off ".class"
Class<?> cl = classLoader.loadClass(packageName+name);
// what do you wanna do with the classes?
System.out.println(cl);
}
}
private static String predictName(File classFile) throws IOException {
byte[] data = Files.readAllBytes(classFile.toPath());
return new ClassLoader() {
String getName() {
return defineClass(null, data, 0, data.length).getName();
}
}.getName();
}
predictName
实现非常简单。如果 class 依赖于 JVM 立即尝试解析的同一文件层次结构中的 classes,它将失败,因为我们还没有必要的信息。在那种情况下,只有允许在不加载 class 的情况下提取名称的字节码解析库才有帮助。但这超出了这个问题的范围......
我正在创建一个包,其中包含我使用 wsimport 动态生成的一些 classes,现在我正在尝试加载它以供使用,我该怎么做?天生的?或者使用像 byte-buddy 这样的库,我尝试使用下面的代码将每个 class 加载到一个包中:
File [] files = new File("<Path to package in filesystem with classes (*.class)>").listFiles();
List<URL> classUrls = new ArrayList<>();
for(File file : files) {
classUrls.add(new URL("file://" + file.getAbsolutePath()));
}
URL[] classz = new URL[classUrls.size()];
classz = classUrls.toArray(classz);
URLClassLoader child = new URLClassLoader(classz);
Class.forName("com.abc.external.resources.genwn239aqyhmfz.SomeClass", true, child);
但我仍然收到(包裹:com.abc.external.resources.genwn239aqyhmfz.SomeClass)
java.lang.ClassNotFoundException: com.abc.external.resources.genwn239aqyhmfz.SomeClass
class 路径的规则与启动应用程序时必须遵守的规则没有什么不同。 class 路径条目是 不是 class 文件或包含它们的目录,而是包结构的根目录。
所以如果你要加载的class是com.abc.external.resources.genwn239aqyhmfz.SomeClass
,class路径条目必须是包含com
目录的目录,其中包含abc
目录等。如果您知道 classes 之一的预期全限定名,则很容易找到正确的目录。只需遍历文件层次结构,直到限定名称包含包组件的次数。但是,当您事先不知道名称时,查找它可能会很棘手。这是一个草图:
// pass the expected name of one class contained in f or null if not known
static void loadClasses(File f, String predictedName)
throws IOException, ClassNotFoundException {
File[] classes = f.listFiles((d,n)->n.endsWith(".class"));
if(classes == null || classes.length == 0) {
System.err.println("no classes or not a directory");
return;
}
if(predictedName == null) predictedName = predictName(classes[0]);
for(int p = predictedName.indexOf('.'); p >= 0; p = predictedName.indexOf('.', p+1))
f = f.getParentFile();
URLClassLoader classLoader = new URLClassLoader(new URL[] { f.toURI().toURL() });
String packageName = predictedName.substring(0, predictedName.lastIndexOf('.')+1);
for(File cf: classes) {
String name = cf.getName();
name = name.substring(0, name.length()-6); // strip off ".class"
Class<?> cl = classLoader.loadClass(packageName+name);
// what do you wanna do with the classes?
System.out.println(cl);
}
}
private static String predictName(File classFile) throws IOException {
byte[] data = Files.readAllBytes(classFile.toPath());
return new ClassLoader() {
String getName() {
return defineClass(null, data, 0, data.length).getName();
}
}.getName();
}
predictName
实现非常简单。如果 class 依赖于 JVM 立即尝试解析的同一文件层次结构中的 classes,它将失败,因为我们还没有必要的信息。在那种情况下,只有允许在不加载 class 的情况下提取名称的字节码解析库才有帮助。但这超出了这个问题的范围......