Java 17升级:SoyTofu迁移到SoySauce遇ijData识别异常求助
问题描述
应用从Java 8升级到Java 17,需将原基于SoyTofu的代码迁移为SoySauce(Google Closure Templates),目标是最小化代码改动,但迁移中遇到核心问题:注入数据(ijData)无法正常工作,单元测试抛出编译异常。
现有代码
Foobar类代码
import com.google.template.soy.SoyFileSet; import com.google.template.soy.tofu.SoyTofu; public class Foobar { ... private SoyTofu soyTemplates; ... @Override protected void startUp() throws Exception { ... String templatesProperty = "templates/mail.soy templates/mail-admin.soy"; try { String[] templates = templatesProperty.split("\\s+"); if (templates.length > 0) { SoyFileSet.Builder builder = SoyFileSet.builder(); for (String t : templates) { URL url = getUrl(t); builder.add(url); } soyTemplates = builder.build().compileToTofu(); } } ... } public Message compose(MailItem item) { ... Map<String, Object> ijData = new HashMap<String, Object>(); ijData.put("supported", true); ijData.put("brand", "Accounts"); String renderSubject = soyTemplates.newRenderer(item.subject).setData(item.data).setIjData(ijData).render(); message.setSubject(renderSubject); String renderBody = soyTemplates.newRenderer(item.body).setData(item.data).setIjData(ijData).render(); message.setContent(renderBody, MediaType.TEXT_HTML); ... } }
Soy模板片段
/** * Account request submitted subject */ {template accountRequestSubmittedSubject} {@param username : string} {$ij.brand} account request: {$username} {/template}
错误信息
Caused by: com.google.template.soy.error.SoyCompilationException: errors during Soy compilation file:/target/test-classes/templates/mail-admin.soy:8: error: Unknown variable. 8: {$ij.brand} account request: {$requestorUsername} ~~~
已尝试创建独立SoySauce构建器、将SoyTofu构建器转为SoySauce等方式,但均未解决问题。愿意接受实时编译的性能损耗(仅2个模板)。
解决方案
1. 修正模板:显式声明注入参数(ij)
新版本Google Closure Templates要求必须显式声明注入参数,不能隐式使用$ij。这是编译报错的核心原因,需修改模板:
单模板声明示例
/** * Account request submitted subject */ {template accountRequestSubmittedSubject} {@param username : string} {@inject brand : string} {@inject supported : boolean} {$brand} account request: {$username} {/template}
多模板共用注入参数(推荐)
如果多个模板用到相同的ij参数,可在命名空间级别统一声明,避免重复:
{namespace mail.templates} {@inject brand : string} {@inject supported : boolean} /** * Account request submitted subject */ {template accountRequestSubmittedSubject} {@param username : string} {$brand} account request: {$username} {/template}
2. 替换SoyTofu为SoySauce,调整代码逻辑
SoySauce的API与SoyTofu存在差异,需逐步替换:
步骤1:替换导入语句
// 移除原有导入 // import com.google.template.soy.tofu.SoyTofu; // 添加SoySauce导入 import com.google.template.soy.SoySauce;
步骤2:修改类成员变量
// 原代码 // private SoyTofu soyTemplates; // 修改后 private SoySauce soyTemplates;
步骤3:调整编译逻辑
将编译方法从compileToTofu()改为compileToSauce():
// 原代码 // soyTemplates = builder.build().compileToTofu(); // 修改后 soyTemplates = builder.build().compileToSauce();
步骤4:修改渲染代码
SoySauce使用renderTemplate()方法渲染,注入数据通过withIj()传递:
// 原代码 // String renderSubject = soyTemplates.newRenderer(item.subject).setData(item.data).setIjData(ijData).render(); // 修改后 String renderSubject = soyTemplates.renderTemplate(item.subject, item.data) .withIj(ijData) .render(); // 同理修改邮件正文渲染 String renderBody = soyTemplates.renderTemplate(item.body, item.data) .withIj(ijData) .render();
3. (可选)启用实时编译
若要使用实时编译(仅建议开发场景),可直接通过SoySauce.builder()加载模板,跳过提前编译步骤:
try { String[] templates = templatesProperty.split("\\s+"); if (templates.length > 0) { SoySauce.Builder sauceBuilder = SoySauce.builder(); for (String t : templates) { URL url = getUrl(t); sauceBuilder.add(url); } soyTemplates = sauceBuilder.build(); } }
内容的提问来源于stack exchange,提问作者commadelimited
相关产品推荐
相关产品推荐

