The controllers in my framework look something like this :
// Actually injected in the *constructor* but bear with me..
@Inject
IControllerResultFactory controllerResultFactory;
public IControllerResult myAction(IRequestInfo requestInfo)
{
IJamonContext jamonContext = new MyJamonContext();
// "JTIndex" is the Jamon Template.
Renderer renderer = new JTIndex().setJamonContext(jamonContext).makeRenderer("some param");
JamonControllerResult controllerResult = controllerResultFactory.createJamonControllerResult(renderer);
return controllerResult;
}
As you see, the controller's action will return a JamonControllerResult. This is an object that allows the framework to decide how and when to actually render the template and how to manage errors if some occure.
My problem is that setJamonContext() has to be called on JTIndex directly. So the framework can't decide which implementation will be used. If the JamonContext could be set on the Renderer (or at least after the parameters required by JTIndex have been set), then the framework could do it by itself.
For example :
@Inject
IControllerResultFactory controllerResultFactory;
public IControllerResult myAction(IRequestInfo requestInfo)
{
IJamonContext jamonContext = new MyJamonContext();
Renderer renderer = new JTIndex().makeRenderer("some param");
JamonControllerResult controllerResult = controllerResultFactory.createJamonControllerResult(renderer);
return controllerResult;
}
// And then, in the JamonControllerResult object :
renderer.setJamonContext(jamonContextImpl);
renderer.renderTo(response.getWriter());
Otherwise, it's always the responsability of the developer to set this JamonContext even if it's always required and doesn't change...
Anonymous
It seems I can't edit the original post so :
This line, in the second example, is of course not required :
It's a little bit related to feature request #8 ( https://sourceforge.net/p/jamon/feature-requests/8/ ) since it is also related to how to configure Jamon, but the configuration I'm talking here is an application runtime one, not one required when generating .java files :
Wouldn't it be possible to call some kind of "init(...)" or "configure(...)" method to set the Jamon runtime configurations? I guess the call to this method could be optional and, if not called, the current behavior using jamon.properties files would be used to get runtime configurations?
That would be the best for my Guice based framework, because it would then allow the application developer to bind the org.jamon.contextType implementation class he wants to use the same way he will for all other dependencies in the application!
Actually, I would force the choosen ContextType class to implement an IViewUtils interface which would contain all the utility methods that would be provided by the framework. The framework would of course provide a default ViewUtils implementation which could be extended by the implementation class choosen by the developer as the ContextType.
(By the way, sorry for all my questions/feature requests, I hope I'm not a pain! But this framework I'm working on is a very important project for me and if I decide to use Jamon as the default templating engine - and I'm 90% confident I will - then I'd like the best integration possible! Thanks a lot again for Jamon and for the help!)
I just realized that org.jamon.contextType is not a "runtime configuration" but actually required when generating the .java files. So, well... I guess an init() method is not so interesting after all.
Last edit: electrotype 2013-09-01
This will be my workaround for now. A real patch would be hugely welcome since you can't get uglier than the following code!!!
In myAction :
In JamonControllerResult :
One option to consider would be to create a parent template that serves as the root of the inheritance hierarchy for all Jamon templates your controllers will directly call. The setter for the jamonContext lives at the top of the template hierarchy.In particular, if your controller calls makeParentRenderer, then it can return a Renderer which will have a setJamonContext method on it.
I've found parent templates to be quite useful in this regard; in fact, a deeper hierarchy can be useful as well. One useful pattern is to have a parallel hierarchy of template builders, at least for the abstract templates. The rough pattern is as follows:
Grandparent.jamon:
LoggedInPageParent.jamon
Matching this, you have:
GrandparentBuilder.java:
LoggedInParentBuilder.java
Finally, a controller, say MyAccountController.java
Of course, there's no need for the builders to have an inheritance hierarchy in this case, but it can make things a bit easier to track.
Very interesting, thanks a lot. I'm going to experiment with those ideas for sure.
By the way, I did a lot more experiments by my own and, actually, I'm not even sure I will use jamonContext by default in my framework anymore. What I want is a way for Jamon to work as I want without the need for the application developers to add any jamon.properties by themselves. This is my main goal.
But I'm near a solution I like. Using some black magic I'm now able to inject directly in the template implementations :
It would have been easier if Jamon provided a way to directly access the AbstractTemplateImpl implementation object (tell me if there is one, I didn't find it!), but I'm able to do it using reflection.
This solution is not as simple as a jamonContext which is automatically usable everywhere, but it allows the developers to inject any dependencies he wants, and I like this a lot. He can also use any name he wants for the object.
So, in my framework documentation , I'll suggest to start all .jamon files with :
To have access to all view utilities provided by my framework.
You can lower the priority I set for this feature request if you want (as I'm not able to do it by myself)...
Thanks a lot for the help!
Oups, I wasn't logged in while posting.
Would another way to frame your feature request be:
"Have Jamon templates actually be obtained from a Guice injector, and permit me to be able to supply some bindings to that template"
?
My initial request was about the jamonContext object only but, yes, I guess an easier way to inject into the template implementations would resume my current request!
But I would say this is not a top request anymore for me since I found a way to do it using reflection. I replace the m_templateManager (even if it's final) field in the AbstractTemplateProxy object by a wrapper which calls myGuiceInjector.injectMembers(impl) on the created implementations. It works great.
By the way, is it possible for you to "moderate" the message on this thread I posted without being logged in please? It's still in "Post awaiting moderation." status.
Thanks!
Well, if what you want to do is install a custom TemplateManager, you can already do that.
https://sourceforge.net/p/jamon/code/3054/tree/trunk/jamon/jamon-runtime/src/main/java/org/jamon/TemplateManagerSource.java
Nice, this is way better than my reflection workaround! I'll try that tonight...
Using your suggestion works perfectly, thanks a bunch!