HTL (HTML Template Language) is what Adobe recommends for rendering HTML markup in AEM (Adobe Experience Manager), instead of using JSP (JavaServer Pages). Although HTL has many advantages, it leaves out several things used in JSP, so we need to consider workarounds for HTL in these situations.

For instance, consider a situation in which you need to pass a string argument from HTL to the back end. Let’s say, a user name is returned by a service, and we need to render a data-attribute containing a token associated with that user name.

<sly data-sly-use.userService="com.acme.UserService" />
<a href="#" data-user-token="__user_token_to_be_rendered_here__">
   Enter ${userService.currentUser} account
</a>

We can leverage the fact that HTL supports expressions like this:

   ${myObject['key']}

Here myObject can be an instance of the java.util.Map. So, we can create a helper class with a field that pretends to be a Map:

import java.util.Map;
import com.adobe.cq.sightly.WCMUsePojo;

public class MyHelper extends WCMUsePojo {    
    private Map<String, String> mapProxy;

    @Override
    public void activate() throws Exception {        
        mapProxy = MyProxyFactory.create();
    }

    public Map<?,?> getTokenForUser() {
        return mapProxy;
    } 
}

The helper class uses a factory to create a map proxy:

import java.lang.reflect.Proxy;
import java.util.Map;

public class MyProxyFactory {
   public static Map<String, String> create() {
       return (Map<String, String>) Proxy.newProxyInstance(
               MapProxyFactory.class.getClassLoader(),
               new Class[] { Map.class },
               new MyInvocationHandler());
   } 
}

The factory, in turn, uses the invocation handler below for the map proxy:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import org.apache.commons.lang3.ArrayUtils;

public class MyInvocationHandler implements InvocationHandler {

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (ArrayUtils.isEmpty(args)) {
            throw new IllegalArgumentException(

            "There must be a parameter for method: " + method.getName());
        }
        if (!"get".equals(method.getName())) {
            throw new UnsupportedOperationException(

                "Unsupported method: " + method.getName());
        }

        Object param = args[0];
        return handle(param);
    }
    
    private Object handle(Object param) {
        return generateToken((String)param);
    }
    
    private String generateToken(String userName) {
        String token = ... //generate a token based on a user name
        return token;
    }
}

Now that we’ve set up all that, we can use the helper class in HTL to render a username-based token:
 

<sly data-sly-use.userService="com.acme.UserService" />
<sly data-sly-use.helper="com.acme.MyHelper" />

<a href="#" data-user-token="${helper.tokenForUser[userService.currentUser]}">
    Enter to ${userService.currentUser} account
</a>