自定义Eclipse RenameParticipant报错:无法确定URI/移动资源异常
自定义RenameParticipant修改Makefile的APPNAME变量时出现资源错误
问题现象
- 首次运行插件弹出**"Problem encountered moving resources"**错误弹窗
- 再次运行弹出**"Cannot determine URI"**错误弹窗,且参与者会被自动禁用,需重启Eclipse才能恢复
- 仅在重命名项目文件夹时触发,调试发现错误发生在
org.eclipse.ltk.core.refactoring.PerformChangeOperation的fUndoChange= fChange.perform(new SubProgressMonitor(monitor, 9))执行阶段 - 当Makefile中未匹配到
APPNAME正则表达式时,不会出现资源/URI错误,说明错误由Makefile变更操作导致
疑问
重命名过程中仅执行项目文件夹重命名,已传入IFile对象,为何仍会出现找不到Makefile路径的问题?
相关代码
public Change createChange(IProgressMonitor pm) throws CoreException, OperationCanceledException { // Hash map and variable declarations. final HashMap<IFile, TextFileChange> changes = new HashMap<IFile, TextFileChange>(); final String newProjName = getArguments().getNewName(); // WorkspaceTracker is a class for workspace utilities. final IProject proj = WorkspaceTracker.getInstance().getCurrentProject(); final String projName = proj.getName(); // Find and open the Makefile. MAKEFILE_NAME is a final class variable. IResource res = proj.findMember(MAKEFILE_NAME); IFile makeIFile = ResourcesPlugin.getWorkspace().getRoot().getFileForLocation(res.getLocation()); if (getArguments().getUpdateReferences()) { // Verify hashmap is clear for the makefile changes TextFileChange change = changes.get(makeIFile); if (change == null && getTextChange(makeIFile) == null) { try { // Read the makefile final String fileIn = new String(Files.readAllBytes(Paths.get(makeIFile.getLocationURI())), StandardCharsets.UTF_8); // Use regex matcher to find match and add it to the change hashmap. Matcher matcher = Pattern.compile(verbatim("^(APPNAME=)(.+)$")) .matcher(fileIn); // Error caused by the following code ----------------------------- // ("Problems encountered moving resources" OR "Could not locate URI") while (matcher.find()) { ReplaceEdit edit = new ReplaceEdit(matcher.start(), (matcher.end() - matcher.start()), String.format("%1$s%2$s", matcher.group(1), newProjName)); if (change == null) { // Add the changes change = new TextFileChange(MAKEFILE_NAME, makeIFile); change.setEdit(new MultiTextEdit()); changes.put(makeIFile, change); } change.addEdit(edit); change.addTextEditGroup(new TextEditGroup( String.format(verbatim("Updates Makefile APPNAME for %1$s"), newProjName), edit)); } // End of error causing code---------------------------------------- } catch (IOException e) { CyConsole.getInstance().log(Level.ERROR, String.format(verbatim("Failed to update Makefile references for %1$s. Error %2$s"), projName, e)); } } } CompositeChange result; if (changes.isEmpty()) { result = null; } else { result = new CompositeChange("Rename project dependencies"); for (Iterator<TextFileChange> iter = changes.values().iterator(); iter.hasNext();) { result.add(iter.next()); } } return result; }
问题根源与解决方案
核心问题
你通过ResourcesPlugin.getWorkspace().getRoot().getFileForLocation(res.getLocation())获取的IFile是基于文件系统路径的,项目重命名时,Eclipse先修改工作空间内的项目资源路径,但文件系统路径的更新存在滞后性,导致后续执行变更时,该IFile关联的URI已失效。同时直接读取文件系统内容的方式绕过了Eclipse的资源变更跟踪机制,引发资源状态不一致。
修复步骤
直接使用项目内的IFile引用
proj.findMember(MAKEFILE_NAME)返回的IResource如果是文件类型,直接强转为IFile即可,这是基于工作空间资源管理的引用,会自动跟随项目重命名更新:// 替换原IFile获取逻辑 IResource res = proj.findMember(MAKEFILE_NAME); if (!(res instanceof IFile)) { // 处理文件不存在的情况 return null; } IFile makeIFile = (IFile) res;同步资源状态
在处理文件前调用refreshLocal同步资源状态,避免缓存导致的路径不一致:makeIFile.refreshLocal(IResource.DEPTH_ZERO, pm);通过TextFileChange读取文件内容
不要直接读取文件系统内容,改用TextFileChange的getCurrentContent方法获取,确保内容是Eclipse工作空间管理的最新版本,符合重构事务机制:// 替换文件读取逻辑 change = new TextFileChange(MAKEFILE_NAME, makeIFile); change.setEdit(new MultiTextEdit()); changes.put(makeIFile, change); // 获取文件当前内容 String fileIn = change.getCurrentContent(new SubProgressMonitor(pm, 1)).getContents();
修复后的关键代码片段
// 修正后的IFile获取与状态同步 IResource res = proj.findMember(MAKEFILE_NAME); if (!(res instanceof IFile)) { return null; } IFile makeIFile = (IFile) res; makeIFile.refreshLocal(IResource.DEPTH_ZERO, pm); if (getArguments().getUpdateReferences()) { TextFileChange change = changes.get(makeIFile); if (change == null && getTextChange(makeIFile) == null) { try { change = new TextFileChange(MAKEFILE_NAME, makeIFile); change.setEdit(new MultiTextEdit()); changes.put(makeIFile, change); // 通过TextFileChange获取最新内容 String fileIn = change.getCurrentContent(new SubProgressMonitor(pm, 1)).getContents(); Matcher matcher = Pattern.compile(verbatim("^(APPNAME=)(.+)$")) .matcher(fileIn); while (matcher.find()) { ReplaceEdit edit = new ReplaceEdit(matcher.start(), (matcher.end() - matcher.start()), String.format("%1$s%2$s", matcher.group(1), newProjName)); change.addEdit(edit); change.addTextEditGroup(new TextEditGroup( String.format(verbatim("Updates Makefile APPNAME for %1$s"), newProjName), edit)); } } catch (CoreException | IOException e) { CyConsole.getInstance().log(Level.ERROR, String.format(verbatim("Failed to update Makefile references for %1$s. Error %2$s"), projName, e)); } } }
内容的提问来源于stack exchange,提问作者Alyzzar
相关产品推荐
相关产品推荐

