Xtext与Ace Web编辑器代码生成请求失败排查求助
问题描述
基于Xtext Web编辑器的Ace支持,我在前端调用代码生成服务时遭遇404错误,具体情况如下:
前端触发代码
参考文档中的「调用服务」逻辑,通过按钮点击触发生成:
var editor = xtext.createEditor(); $("#save-button").click(function() { // editor.xtextServices.saveResource(); editor.xtextServices.generate(); });
后端生成器实现
基于默认Greeting语法编写了代码生成器:
// filename: <MyLovaelyDslName>Generator.xtend class Phase0Generator extends AbstractGenerator { override void doGenerate( Resource resource, IFileSystemAccess2 fsa, IGeneratorContext context ) { fsa.generateFile('greetings.txt', 'People to greet: ' + resource.allContents .filter(Greeting) .map[name] .join(', ')) } }
错误表现
浏览器发起的10次GET请求全部返回404:
GET http://localhost:8080/xtext-service/generate?resource=67e22793.veri&requiredStateId=-7ffffff4 404 (Not Found)
随后弹出错误提示:
Xtext service 'generate' failed: Xtext service request failed after 10 attempts. xtext-ace.js:1114 Xtext service 'generate' failed: Not Found
目前语法高亮和自定义验证功能均正常工作。
已做的配置
按照文档要求创建了XtextServlet子类,重写doGet方法拦截请求,能正常处理非generate请求,但不知道如何对接generate的处理逻辑:
@WebServlet(name = "XtextServices", urlPatterns = "/xtext-service/*") public class Phase0Servlet extends XtextServlet { public void init() throws ServletException { /* ... */ } public void destroy() { /* ... */ } @Override protected void doGet( HttpServletRequest req, HttpServletResponse response ) throws ServletException, IOException { var service = getService(req); var serviceType = /* ... */.getParameter("serviceType"); if (serviceType.equals("generate")) { /* ... */ } else { /* ... */ } } }
解决方案
问题出在你的Servlet没有正确实现generate请求的处理逻辑,需要对接Xtext的生成器服务,具体步骤如下:
初始化生成器相关服务
在Servlet的init方法中,通过Xtext的依赖注入容器获取生成器、生成上下文工厂:private IGenerator generator; private IGeneratorContext.Factory contextFactory; @Override public void init() throws ServletException { super.init(); Injector injector = getInjector(); // 从父类获取Xtext注入器 generator = injector.getInstance(IGenerator.class); contextFactory = injector.getInstance(IGeneratorContext.Factory.class); }实现generate请求处理逻辑
在doGet的generate分支中,加载目标资源、执行生成并返回结果:private void handleGenerateRequest(HttpServletRequest req, HttpServletResponse response) throws IOException { String resourceId = req.getParameter("resource"); // 这里需要实现资源加载逻辑,比如从内存缓存中获取编辑器对应的Resource实例 Resource resource = loadResource(resourceId); if (resource == null) { response.sendError(HttpServletResponse.SC_NOT_FOUND, "资源不存在"); return; } // 使用内存文件系统访问器捕获生成的文件内容 MemoryFileSystemAccess fsa = new MemoryFileSystemAccess(); IGeneratorContext context = contextFactory.createContext(); try { generator.doGenerate(resource, fsa, context); // 将生成的文件列表转为JSON返回给前端 response.setContentType("application/json"); response.setCharacterEncoding("UTF-8"); new ObjectMapper().writeValue(response.getWriter(), fsa.getFiles()); } catch (Exception e) { response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "生成失败:" + e.getMessage()); } } private Resource loadResource(String resourceId) { // 替换为你的资源加载逻辑,比如从编辑器的内存缓存中获取 return YourResourceStore.getResource(resourceId); }完整Servlet代码
@WebServlet(name = "XtextServices", urlPatterns = "/xtext-service/*") public class Phase0Servlet extends XtextServlet { private IGenerator generator; private IGeneratorContext.Factory contextFactory; @Override public void init() throws ServletException { super.init(); Injector injector = getInjector(); generator = injector.getInstance(IGenerator.class); contextFactory = injector.getInstance(IGeneratorContext.Factory.class); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse response) throws ServletException, IOException { String serviceType = req.getParameter("serviceType"); if ("generate".equals(serviceType)) { handleGenerateRequest(req, response); } else { super.doGet(req, response); } } private void handleGenerateRequest(HttpServletRequest req, HttpServletResponse response) throws IOException { String resourceId = req.getParameter("resource"); Resource resource = loadResource(resourceId); if (resource == null) { response.sendError(HttpServletResponse.SC_NOT_FOUND, "资源不存在"); return; } MemoryFileSystemAccess fsa = new MemoryFileSystemAccess(); IGeneratorContext context = contextFactory.createContext(); try { generator.doGenerate(resource, fsa, context); response.setContentType("application/json"); response.setCharacterEncoding("UTF-8"); new ObjectMapper().writeValue(response.getWriter(), fsa.getFiles()); } catch (Exception e) { response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "生成失败:" + e.getMessage()); } } private Resource loadResource(String resourceId) { // 替换为你的资源加载逻辑,比如从编辑器的内存缓存中获取 return YourResourceStore.getResource(resourceId); } }注意事项
- 确保你的
Phase0Generator已被Xtext的依赖注入容器正确注册,否则injector.getInstance(IGenerator.class)会返回null - 资源加载逻辑必须和Xtext Web编辑器的资源管理一致,确保能获取到当前编辑器中的最新内容
- 前端可以通过
editor.xtextServices.generate().then(result => { ... })处理返回的生成结果
- 确保你的
内容的提问来源于stack exchange,提问作者OrenIshShalom
相关产品推荐
相关产品推荐

