I have a TemplateEngine interface whose implementations would be MoustacheTemplateEngine, FreemarkerTemplateEngine etc.
public interface TemplateEngine<T> {
    public T compileTemplate(String templateStr);
    public void merge(T t, Map<String, Object> data);
    public String getTemplateLang();
}
The purpose of compileTemplate method is to enable caching of compiled templates.
Here is an implementation example:
import com.github.mustachejava.Mustache;
public class MoustacheTemplateEngine implements TemplateEngine<Mustache> {
    @Override
    public Mustache compileTemplate(String templateStr) {
        // return compiled template;
    }
    @Override
    public void merge(Mustache compiledTemplate, Map<String, Object> data) {
        // merge
    }
    @Override
    public String getTemplateLang() {
        return "moustache";
    }
}
I wish to create a factory that returns a TemplateEngine depending on the template language supplied. The factory, and the client that would use the factory, do not know anything about TemplateEngine implementations.
public class TemplateEngineFactory {
    private Map<String, TemplateEngine<?>> TEMPLATE_ENGINE_REGISTRY = new HashMap<>();
    @PostConstruct
    public void init() {
        // Scan all TemplateEngine impls in classpath and populate registry
    }
    public TemplateEngine<?> getTemplateEngine(String templateLang) {
        return TEMPLATE_ENGINE_REGISTRY.get(templateLang);
    }
}
A client would use the factory as below.
Map<String, Object> data = new HashMap<>();
data.put("name", "Tom");
TemplateEngine<?> templateEngine = factory.getTemplateEngine("moustache");
Object compiledTemplate = templateEngine.compileTemplate("Hi {{name}}");
templaeEngine.merge(compiledTemplate, data); // compile error
The error being The method merge(capture#3-of ?, Map<String,Object>) in the type TemplateEngine<capture#3-of ?> is not applicable for the arguments (Object, Map<String,Object>).
I understand the error and I know my API design is flawed due to the use of wildcard in factory. My question is how to design a factory for such use case and avoid unsafe casts?
 
     
    