Freemarker 2.3.23 是否正确处理可变参数?

Does Freemarker 2.3.23 handle varargs properly?

这个(可怕;别问;我不能修改数据模型或配置)表达式不起作用:

${statics["java.nio.file.Files"].write(statics["java.nio.file.Paths"].get("/foo/bar.stuff"), statics["java.nio.charset.Charset"].forName("UTF-8").encode(someStringContent).array(), enums["java.nio.file.StandardOpenOption"].WRITE)}

型号代码:

    model.addAttribute("statics", new BeansWrapperBuilder(Configuration.VERSION_2_3_23).build().getStaticModels());
    model.addAttribute("enums", new BeansWrapperBuilder(Configuration.VERSION_2_3_23).build().getEnumModels());

简而言之,这是一种获取一些 Freemarker 字符串内容的(粗略)方法,将其转换为 byte[] 数组,然后将其写入 Freemarker 中的 /foo/bar.stuff 路径。

该错误表明 Freemarker 无法选择正确的可变参数方法:

Error executing FreeMarker template
FreeMarker template error:
When trying to call the non-varargs overloads:
No compatible overloaded variation was found; can't convert (unwrap) the 3rd argument to the desired Java type.
The FTL type of the argument values were: extended_hash+string (sun.nio.fs.UnixPath wrapped into f.e.b.StringModel), sequence (byte[] wrapped into f.t.DefaultArrayAdapter$ByteArrayAdapter), extended_hash+string (java.nio.file.StandardOpenOption wrapped into f.e.b.StringModel).
When trying to call the varargs overloads:
Multiple compatible overloaded variations were found with the same priority.
The Java type of the argument values were: sun.nio.fs.UnixPath, byte[], java.nio.file.StandardOpenOption.
The matching overload was searched among these members:
    static java.nio.file.Files.write(java.nio.file.Path, Iterable, java.nio.file.OpenOption...),
    static java.nio.file.Files.write(java.nio.file.Path, Iterable, java.nio.charset.Charset, java.nio.file.OpenOption...),
    static java.nio.file.Files.write(java.nio.file.Path, byte[], java.nio.file.OpenOption...)

我尝试过其他技巧,包括使用 java.lang.reflect.Array#newInstance(Class, int) 创建正确类型的数组,但这没有帮助。

我假设这是不可能的?

您能否将对 Files.write() 方法的调用包装在您自己明确的方法中

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.OpenOption;
import java.nio.file.Path;

public class UnambiugousMethodWrappers{
    public static Path writeBytes (Path path, byte[] bytes, OpenOption... options) throws IOException {
        return Files.write(path, bytes, options);
    }
}

我猜这将是为 100% 向后兼容性而模拟的重载方法选择中的一个小故障。因此,您应该将 FreeMarker 配置的 incompatible_improvements 设置增加到至少 2.3.21 才能激活修复(或者如果您没有使用 object_wrapper 设置的默认值,那么类似的设置您正在创建的 ObjectWrapper 个)。但是,你说你不能碰 FreeMarker 配置...

我在其他答案中也看到您也不能添加自己的静态助手 class...

假设您的 statics 模型字段是使用 EXPOSE_ALL 构建的,您可以更深入地研究反射兔子洞:

<#assign class = statics["java.lang.Class"]>
<#assign openOptionClass = class.forName("java.nio.file.OpenOption")>
<#assign filesClass = class.forName("java.nio.file.Files")>
<#assign method = filesClass.getMethod("write", class.forName("java.nio.file.Path"),class.forName("[B"),class.forName("[Ljava.nio.file.OpenOption;"))>
<#assign path = statics["java.nio.file.Paths"].get("/foo/bar.stuff")>
<#assign utf8 = statics["java.nio.charset.Charset"].forName("UTF-8")>
<#assign writeOptions = enums["java.nio.file.StandardOpenOption"].WRITE>
<#assign writeOptionsArray = statics["java.lang.reflect.Array"].newInstance(openOptionClass,1)>
<#assign ignoreThisVoid = statics["java.lang.reflect.Array"].set(writeOptionsArray, 0, writeOptions)>
${method.invoke(null, path, utf8.encode(someStringContent).array(), writeOptionsArray)}

或者您可以尝试 PrintWriter(仍然需要 EXPOSE_ALL):

<#assign class = statics["java.lang.Class"]>
<#assign fileOutputStreamClass = class.forName("java.io.FileOutputStream")>
<#assign fileOutputStreamConstructor = fileOutputStreamClass.getConstructor(class.forName("java.lang.String"))>
<#assign fileOutputStream = fileOutputStreamConstructor.newInstance("/foo/bar.stuff")>
<#assign ignoreThisVoid = fileOutputStream.write(utf8.encode(someStringContent).array())>