Eclipse RCP:编织时如何添加内部 class
Eclipse RCP: How can I add an inner class when weaving
在我的 RCP 应用程序中,我使用 WeavingHook 服务在加载时修改第三方 class。我无法对第三方代码进行任何更改,因此我的编织实现必须按原样使用它。
除一个问题外,我可以正常使用它。对于我制作的其中一个模组,我实例化了一个内部 class。它必须是内部 class,因为它依赖于定义在其中一个超级 class 中的内部 class。
现在,当第三方代码加载修改后的 class 时,它的 class 路径上没有内部 class 的文件,该文件仅在插件中可用- 在我实施编织的地方。如果第三方插件声明了 registered
的伙伴策略,我可以在清单中添加一个 Eclipse-RegisterBuddy
指令,但事实并非如此。
是否有某种编织方式可以使修改后的 class 能够访问通过二进制编织添加的内部匿名 class?
我能想到的唯一解决办法是在发生二进制编织时将内部class文件复制到第三方代码的bin/目录下。看起来像一个 hack,所以我希望有更好的方法。
您可以在使用 getDynamicImports()
方法通过 WeavingHook 编织 class 时动态添加 Import-Package :
wovenClass.getDynamicImports().add("my.package.to.import");
这个包显然应该由另一个包导出。
这是一个有效的解决方案,将内部 class 的 class 文件复制到包含 weave 目标的第三方插件的 bin/ 目录。如果有人知道更简单的方法来做到这一点,请 post 单独回答。
编辑:使原来的解决方案更通用,发现正在编织的 class 的所有内部 class 文件,如果缺少或大小不合适,将它们复制到编织目标插件不同。
public class Activator extends Plugin {
...
public static final String CLASS_FILE_ROOT = "bin/";
/**
* Binary weaving of a class file may result in the addition or modification of
* inner class files in this plug-in which need to be placed on the classpath
* of the plug-in containing the weave target. This method compares inner class
* files for a given class in this plug-in with inner class files in the plug-in
* that contains the weave target. Any inner class files missing from the weave
* target or with a different size than the corresponding file in this plug-in
* are copied to the appropriate package directory in the weave target plug-in.
*
* @param bundle the bundle of the class being woven
* @param className the fully qualified name of the class being woven
* @return true if no errors were encountered in copying the inner class files
*/
private boolean checkInnerClassFileSync(Bundle bundle, String className) {
className = className.replaceAll("\.", "/");
String classDir = CLASS_FILE_ROOT + className.substring(
0, FilenameUtils.indexOfLastSeparator(className));
for (String innerClass : getInnerClassNames(classDir, FilenameUtils.getName(className))) {
try {
URL srcUrl = getBundle().getEntry(classDir + "/" + innerClass);
File srcFile = new File(FileLocator.resolve(srcUrl).toURI());
URL destUrl = bundle.getEntry(classDir);
File destDir = new File(FileLocator.resolve(destUrl).toURI());
File destFile = FileUtils.getFile(destDir, innerClass);
if (srcFile.isFile() && (!destFile.exists() || destFile.length() != srcFile.length())) {
FileUtils.copyFile(srcFile, destFile);
}
} catch (IOException | URISyntaxException e) {
logger.log(Level.ERROR, "An error occurred while trying to copy an inner class file to the weave target bundle", e);
return false;
}
}
return true;
}
/**
* Get the class files representing inner classes defined in a specified class and
* found in a specified directory.
*
* @param dir a sub-directory containing a class file for <code>className</code>
* and possibly one or more class files representing inner classes defined in
* <code>className</code>
* @param className a class whose class file is found in <code>dir</code>
* @return class files names representing every inner class defined in
* <code>className</code> and found in <code>dir</code>.
*/
private String[] getInnerClassNames(String dir, String className) {
List<String> classNames = new ArrayList<String>();
try {
File classDir = new File(FileLocator.resolve(getBundle().getEntry(dir)).toURI());
for (String fName : classDir.list()) {
Pattern p = Pattern.compile("^" + className + "\$.+$");
Matcher m = p.matcher(fName);
if (m.matches()) {
classNames.add(fName);
}
}
return classNames.toArray(new String[0]);
} catch (URISyntaxException | IOException e) {
logger.log(Level.ERROR, "An error occured while scanning for inner class files", e);
return classNames.toArray(new String[0]);
}
}
....
}
在我的 RCP 应用程序中,我使用 WeavingHook 服务在加载时修改第三方 class。我无法对第三方代码进行任何更改,因此我的编织实现必须按原样使用它。
除一个问题外,我可以正常使用它。对于我制作的其中一个模组,我实例化了一个内部 class。它必须是内部 class,因为它依赖于定义在其中一个超级 class 中的内部 class。
现在,当第三方代码加载修改后的 class 时,它的 class 路径上没有内部 class 的文件,该文件仅在插件中可用- 在我实施编织的地方。如果第三方插件声明了 registered
的伙伴策略,我可以在清单中添加一个 Eclipse-RegisterBuddy
指令,但事实并非如此。
是否有某种编织方式可以使修改后的 class 能够访问通过二进制编织添加的内部匿名 class?
我能想到的唯一解决办法是在发生二进制编织时将内部class文件复制到第三方代码的bin/目录下。看起来像一个 hack,所以我希望有更好的方法。
您可以在使用 getDynamicImports()
方法通过 WeavingHook 编织 class 时动态添加 Import-Package :
wovenClass.getDynamicImports().add("my.package.to.import");
这个包显然应该由另一个包导出。
这是一个有效的解决方案,将内部 class 的 class 文件复制到包含 weave 目标的第三方插件的 bin/ 目录。如果有人知道更简单的方法来做到这一点,请 post 单独回答。
编辑:使原来的解决方案更通用,发现正在编织的 class 的所有内部 class 文件,如果缺少或大小不合适,将它们复制到编织目标插件不同。
public class Activator extends Plugin {
...
public static final String CLASS_FILE_ROOT = "bin/";
/**
* Binary weaving of a class file may result in the addition or modification of
* inner class files in this plug-in which need to be placed on the classpath
* of the plug-in containing the weave target. This method compares inner class
* files for a given class in this plug-in with inner class files in the plug-in
* that contains the weave target. Any inner class files missing from the weave
* target or with a different size than the corresponding file in this plug-in
* are copied to the appropriate package directory in the weave target plug-in.
*
* @param bundle the bundle of the class being woven
* @param className the fully qualified name of the class being woven
* @return true if no errors were encountered in copying the inner class files
*/
private boolean checkInnerClassFileSync(Bundle bundle, String className) {
className = className.replaceAll("\.", "/");
String classDir = CLASS_FILE_ROOT + className.substring(
0, FilenameUtils.indexOfLastSeparator(className));
for (String innerClass : getInnerClassNames(classDir, FilenameUtils.getName(className))) {
try {
URL srcUrl = getBundle().getEntry(classDir + "/" + innerClass);
File srcFile = new File(FileLocator.resolve(srcUrl).toURI());
URL destUrl = bundle.getEntry(classDir);
File destDir = new File(FileLocator.resolve(destUrl).toURI());
File destFile = FileUtils.getFile(destDir, innerClass);
if (srcFile.isFile() && (!destFile.exists() || destFile.length() != srcFile.length())) {
FileUtils.copyFile(srcFile, destFile);
}
} catch (IOException | URISyntaxException e) {
logger.log(Level.ERROR, "An error occurred while trying to copy an inner class file to the weave target bundle", e);
return false;
}
}
return true;
}
/**
* Get the class files representing inner classes defined in a specified class and
* found in a specified directory.
*
* @param dir a sub-directory containing a class file for <code>className</code>
* and possibly one or more class files representing inner classes defined in
* <code>className</code>
* @param className a class whose class file is found in <code>dir</code>
* @return class files names representing every inner class defined in
* <code>className</code> and found in <code>dir</code>.
*/
private String[] getInnerClassNames(String dir, String className) {
List<String> classNames = new ArrayList<String>();
try {
File classDir = new File(FileLocator.resolve(getBundle().getEntry(dir)).toURI());
for (String fName : classDir.list()) {
Pattern p = Pattern.compile("^" + className + "\$.+$");
Matcher m = p.matcher(fName);
if (m.matches()) {
classNames.add(fName);
}
}
return classNames.toArray(new String[0]);
} catch (URISyntaxException | IOException e) {
logger.log(Level.ERROR, "An error occured while scanning for inner class files", e);
return classNames.toArray(new String[0]);
}
}
....
}