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.

Reply via email to