Cette expression (hideuse; ne demandez pas; je ne peux pas modifier le modèle de données ou la configuration) ne fonctionne pas:

${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)}

Code modèle:

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

En bref, c'est une manière (grossière) de prendre du contenu de chaîne Freemarker, de le transformer en un tableau byte[] et de l'écrire dans le chemin /foo/bar.stuff depuis Freemarker.

L'erreur indique que Freemarker ne peut pas choisir la méthode varargs appropriée:

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...)

J'ai essayé d'autres hacks, y compris la création d'un tableau du type approprié en utilisant java.lang.reflect.Array#newInstance(Class, int), mais cela n'a pas aidé.

Je suppose que c'est impossible?

0
Laird Nelson 19 avril 2017 à 22:55

3 réponses

Meilleure réponse

En supposant que votre champ de modèle statics est construit avec EXPOSE_ALL, vous pouvez aller plus loin dans le trou du lapin de réflexion:

<#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)}

Ou vous pouvez essayer un PrintWriter (a encore besoin de 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())>
0
Charlie 20 avril 2017 à 00:06

Je suppose que cela va être un problème dans la sélection de méthodes surchargée qui est émulée pour une compatibilité ascendante à 100%. Vous devez donc augmenter le paramètre incompatible_improvements de votre configuration FreeMarker à au moins 2.3.21 pour que le correctif soit activé (ou si vous n'utilisez pas la valeur par défaut pour le paramètre object_wrapper, alors le paramètre similaire du ObjectWrapper que vous créez). Mais vous avez dit que vous ne pouviez pas toucher à la configuration FreeMarker ...

J'ai également vu dans l'autre réponse que vous ne pouvez pas non plus ajouter votre propre classe d'assistance statique ...

0
ddekany 19 avril 2017 à 20:42

Vous pouvez encapsuler l'appel à la méthode Files.write() dans votre propre méthode sans ambiguïté

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);
    }
}
0
Dave Newton 19 avril 2017 à 23:46