Or... maybe you don't really need the Java type name, only to show info for
writing templates? Then:

public final class TemplateLanguageTypeNameMethod implements
TemplateMethodModelEx {
    @Override
    public Object exec(List/*<TemplateModel>*/ arguments) throws
TemplateModelException {
        if (arguments.size() != 1) {
            throw new TemplateModelException("javaType method must be
called with one argument.");
        }

        return ClassUtil.getFTLTypeDescription((TemplateModel)
arguments.get(0));
    }
}

On Sat, Feb 17, 2024 at 2:50 PM Daniel Dekany <daniel.dek...@gmail.com>
wrote:

> So you need the list of the top-level variables in your data-model (aka.
> template context). With their Java type name, and name.
>
> The basic ideas is this:
>
>   <#list .data_model as k, v>
>     ${javaTypeName(v)}: ${k}
>   </#list>
>
>   <#-- For now just let's have this: >
>   <#function javaTypeName x><#return "TODO"></#function>
>
> See if it lists all the names that you want to see. Because, the data
> model can use fallbacks, and those are (certainly) not listed. So that's
> one complication to get over.
>
> The really tricky part is implementing javaTypeName. The template
> language has its own type system, represented by the TemplatModel
> interface, and its numerous subclasses (and quite a lot of
> accumulated historical complications). So when you are inside the template,
> it's not trivial to tell what the plain Java type of a value is. Strictly
> speaking, it's impossible to tell, because you can't know what custom
> ObjectWrapper was used. (That gives flexibility, but is disadvantageous in
> this use case, among others.) Also, some TemplateModel-s do not wrap any
> "plain" Java object at all; they were just constructed to be used inside
> templates, but then, I think the Java type to show is simply the class that
> implements TemplateModel. But, if I only consider what most people use, I
> came up with the following monstrosity (untested, and probably misses some
> nuances):
>
> ----------
> public final class JavaTypeNameMethod implements TemplateMethodModelEx {
>     private static final Package JAVA_LANG_PACKAGE =
> String.class.getPackage();
>
>     @Override
>     public Object exec(List/*<TemplateModel>*/ arguments) throws
> TemplateModelException {
>         if (arguments.size() != 1) {
>             throw new TemplateModelException("javaType method must be
> called with one argument.");
>         }
>
>         TemplateModel ftlValue = (TemplateModel) arguments.get(0);
>         if (ftlValue == null) {
>             return "null";
>         }
>
>         Object javaValue;
>         if (ftlValue instanceof WrapperTemplateModel) {
>             javaValue = ((WrapperTemplateModel)
> ftlValue).getWrappedObject();
>         } else {
>             if (ftlValue instanceof SimpleScalar) {
>                 return getClassName(String.class);
>             } else if (ftlValue == TemplateBooleanModel.TRUE || ftlValue
> == TemplateBooleanModel.FALSE) {
>                 return getClassName(boolean.class);
>             } else if (ftlValue instanceof SimpleNumber) {
>                 javaValue = ((SimpleNumber) ftlValue).getAsNumber();
>             } else if (ftlValue instanceof SimpleDate) {
>                 javaValue = ((SimpleDate) ftlValue).getAsDate();
>             } else if (ftlValue instanceof SimpleHash) {
>                 return getClassName(Map.class);
>             } else if (ftlValue instanceof SimpleSequence) {
>                 return getClassName(List.class);
>             } else if (ftlValue instanceof SimpleCollection) {
>                 return getClassName(Iterable.class);
>             } else if (ftlValue instanceof SimpleMethodModel) {
>                 return getClassName(Method.class);
>             } else {
>                 // Will just show the TemplateModel implementation class
> itself, because some TemplateModels just don't wrap anything.
>                 javaValue = ftlValue;
>             }
>         }
>
>         if (javaValue == null) {
>             return "null";
>         }
>
>         Class<?> javaValueClass = javaValue.getClass();
>         return getClassName(javaValueClass);
>     }
>
>     /**
>      * Central place to decide if we use full qualified name.
>      */
>     private static String getClassName(Class<?> javaValueClass) {
>         return javaValueClass.getPackage().equals(JAVA_LANG_PACKAGE)
>                 ? javaValueClass.getSimpleName()
>                 : javaValueClass.getName();
>     }
> }
> ----------
>
> And then you create an instance of this, and put it into the data-model.
> Or you can just use this in the template, in place of the earlier
> <#function ....>, but ?new is not allowed in all projects:
>
>   <#assign javaTypeName = "com.example.JavaTypeNameMethod"?new()>
>
> BTW, I recommend StackOverflow for user questions, not this list. More
> likely that you get an answer, and way more people will find the answer
> later.
>


-- 
Best regards,
Daniel Dekany

Reply via email to