Is it possible to define the type of the view commands in Spring? As it is right now, it is dangerous for us to change anything in our command classes. Properties on these classes may be used by the view (path="myDto.persons[0].name"), but if anything in the command class changes, the view will only fail runtime.
All other parts of our MVC stack is tested, so we can safely do refactorings when needed. The only problem is with the view, as the paths are "just strings", and we cannot in any reasonable way search and replace everywhere we use the specific command.
It would be a great help if there was some way to tell Spring what type the command actually is, so it could be validated when we do precompilation of our .jsp's. An added bonus would also be completion when editing the view, but I guess that is more of an IDE issue.
So, do any of you know how and if this is possible?
It might be possible to add type safety to your views if you completely redesign your JSP files (in a very ugly way if I may say so myself).
Servlets offer you type safety since that's Java code. If you refactor your classes and miss something, the compiler will immediately tell you you missed it. But JSPs replace servlets as a view technology offering a much more dynamic/rapid development pace (no more endless out.write instructions opening tags, closing them, escaping quotes etc).
EL expressions, as you noticed, are basically strings which later get evaluated and fail at runtime if something is off. Even if you precompile the JSPs, it would still fail because ELs remains as strings in the generated servlet. They are either passed as such to tags and they evaluate it themselves, or if using a JSP 2.x version, the servlet container itself wraps the expression in an evaluation call before passing it as a value.
Basically for a version less than JSP 2, for a tag like:
<my:tag value="${bean.someProp}" />
You get a result like:
myTagInstance.setValue("${bean.someProp}");
in the servlet.
The tag itself will do the evaluation of that string, at runtime.
For JSP 2 you don't get any better, the evaluation still occurs at runtime but the servlet container takes this burden away from the tag, generating a code like:
myTagInstance.setValue((SomePropTypeCastHere) ProprietaryServletContainerEvaluationUtil.evaluate("${bean.someProp}"));
If the content of the object itself isn't the expected one when evaluation occurs, you get weird results or errors.
The only way (I know) to enforce static typing in a JSP is to bring Java code back in the JSP (the thing EL was invented to eliminate). That is why I said at the begging that you have to change your JSP in an ugly way.
If all your tags can use <rtexprvalue>true</rtexprvalue> values, you can use scriptlets to enforce type safety.
A tag like:
<my:tag value="<%=bean.getSomeProp()%>" />
now gets converted to this:
myTagInstance.setValue(bean.getSomeProp());
If the someProp property was renamed, deleted, changed type or whatever, the compiler can tell you about it. The IDE itself should be able to tell you, you don't even need to precompile the JSPs.
If I'm not mistaken, the Spring tags support runtime expressions so this should work... if you are willing to mess up your JSPs that is!
As for the IDE support for completion, you have that for scriptlets but not for EL. That's because for EL it's the same discussion, it happens at runtime. How is the IDE to know what's in context (page, request, session etc) when the JSP is executed, and know that when you are developing the JSP?
Related
Consider this line of jsp code:
function clearCart(){
cartForm.action="cart_clear?method=clear";
cartForm.submit();
}
Clearly it's trying to call a method on the back end to clear the cart. My question is how does the service (Tomcat most likely, correct me if I'm wrong) which hosts this site that contains this snippet of code know how and where to find this method, how it "indexes" it with string values etc. In my java file, the clear method is defined as:
public String clear( )
{
this.request = ServletActionContext.getRequest();
this.session = this.request.getSession();
logger.info("Cart is clearing...");
Cart cart = ( Cart ) this.session.getAttribute(Constants.SESSION_CART );
cart.clear();
for( Long id : cart.getCartItems().keySet() )
{
Item it = cart.getCartItems().get(id);
System.out.println( it.getProduct().getName() + " " + it.getNumber()
);
}
return "cart";
}
By which module/what mechanism does Tomcat know how to locate precisely that method? By copycatting online tutorials and textbooks I know how to write these codes, but I want to get a bit closer to the bottom of it all, or at least something very basic.
Here's my educated (or not so much) guess: Since I'm basing my entire project on struts, hibernate and spring, I've inadvertently/invariably configured the build path and dependencies in such ways that when I hit the "compile" button, all the "associating" and "navigating" are done by these framework, in other words, as long as I correctly configured the project and got spring etc. "involved" (sorry I can't think of that technical jargon that's on the tip of my tongue), and as long as I inherit a class or implement an interface, when compiling, the compiler will expose these java methods to the jsp script - it's part the work done by compiler, part the work done by the people who composed spring framework. Or, using a really bad analogy, consider a C++ project whereby you use a 3rd party library which came in compiled binary form, all you have to do is to do the right inclusion (.h/.hpp file) and call the right function and you'll get the function during run time when calling those functions - note that this really is a really bad analogy.
Is that how it is done or am I overthinking it? For example it's all handled by Tomcat?
Sorry for all the verbosity. Things get lengthy when you need to express slightly more complicated and nuanced ideas. Also - please go deep and go low-level don't go too deep, by that I mean you are free to lecture on how hibernate and spring etc. work, how its code is being run on a server, but try not to touch the java virtue machine, byte code and C++ pointers etc. unless of course, it is helpful.
Thanks in advance!
Tomcat doesn't do much except obey the Servlet specification. Spring tells Tomcat that all requests to http://myserver.com/ should be directed to Spring's DispatcherServlet, which is the main entry point.
Then it's up to Spring to further direct those requests to the code that handles them. There are different strategies for mapping a specific URL to the code that handles the request, but it's not set in stone and you could easily create your own strategy that would allow you to use whatever kind of URLs you want. For a simple (and stupid) example you could have http://myserver.com/1 that would execute the first method in a single massive handler class, http://myserver.com/2 would execute the second, etc.
The example is with Spring, but it's the same general idea with other frameworks. You have a mapper that maps an URL to the handler code.
These days it's all hidden under layers of abstraction so you don't have to care about the specifics of the mapping and can develop quickly and concentrate on the business code.
Is there a chance to automate the search for non-localized text on startup in Thymeleaf Templates and log occurrences?
My Infrastructure: Ant, Spring, Thymeleaf.
Unfortunately there is no clean documented way in which to do it (that I know of).
Having said that, I have done something similar where I wanted to check the template for something and log an occurrence, however the implementation is ugly.
I have to warn you that this is beyond horrible and because it is not standard is likely to break in future releases so I would use sparingly, and definitely not use in any production code.
This requires for you template resolver to be cacheble to be true - org.thymeleaf.templateresolver.TemplateResolver#setCacheable(true) the default is true.
I was able to do it by extending org.thymeleaf.cache.StandardCacheManager (you need to set the cache manager on the org.thymeleaf.TemplateEngine) and overriding initializeTemplateCache() that returned a custom version of org.thymeleaf.cache.StandardCache. My implementation of the cache override the put(..) method which passed in a org.thymeleaf.Template as the value.
That then has org.thymeleaf.dom.Document accessible via getDocument() and from there you can recursivly iterate through the children (some of which will be org.thymeleaf.dom.AbstractTextNode). In your case you may also want to iterate through all the attributes on element nodes as well.
For you, you will then have to write some logic to determine if the text is not going to be localised, working out whether the #{} expression is not being used or if that expression in not in a th:...="#{}" tag or being inline [[#{}]]
Ugly I know but it works for me. If anyone has a cleaner solution I'm all ears.
Our code - which has not changed, is behaving differently in JavaEE1.4 than it did in 1.6 with respect to HttpServletRequest attributes and parameters. However this different behavior is not (always) consistent. We are also using BEA Weblogic 10 (vs. version 8, where it still works).
For example:
In some cases when we do a "request.setAttribute(name, value)" and later on do a "request.getAttribute(name)" - there seems so be no such "name" at all in the request - as if we've never set it. I have run this through our Eclipse debugger in both 8v3 and Ja11 and I do see this attribute in 8v3 but cannot find it in Ja11, which is consistent with how the code is behaving.
Our code consistently fails in in at least one case, where the values of "name" and "value" are both defined as "public final static String;"
I have coded around this one particular instance line by getting the information I need via "request.getPathInfo" instead, however I SUSPECT the same or similar problem is occurring elsewhere in our code - but in one other such instance it is so entirely SPORADIC that I have been unable to recreate it while in debug mode (or even in putting Sysout statements) and therefore cannot trap the line that is the problem. In another instance, also one I can't definitively trap - I believe that it's the request.getParameter(name) that is not returning anything even though that "name" does exist on the jsp form, with data.
(Note that I am somewhat simplifying what our code actually looks like as we have an entire RequestContext class which mplementsSerializable and encapsulates all the relevant data and methods for one request cycle of an HttpServlet - ie HttpServletRequest, HttpServletResponse, HttpSession, HttpServlet
Anyway I have heard that the Java Servlet spec has had some changes in 1.6 - but does it somewhere explicity state what those differences are or do I literally have to pull up the 1.4 spec next to it and do my own compare???
I am admittedly not well versed in dealing with HttpServeltRequest, but this code has been working FINE for YEARS - have a hard time believing something so basic/common as get/setAttribute and getParameter would have changed...
Servlets are not thread-safe and do not get recreated per request. All requests are being served by one and the same servlet object. Are you storing variables in public static final fields of the servlet class?
I have a simple requirement: The number of columns of my <tr:table/> is dynamic. I will have a list of objects, someBean.features which will determine how many columns are rendered.
The following diagram should clarify my requirement.
In the code that I was given, there was usage of the JSTL <c:forEach/> tag which obviously created problems when used in a JSF environment. They had done something like this:
<tr:table value="#{someBean.values}">
<tr:column headerText="Name">
<tr:outputText value="#{someBean.name}"/>
</tr:column>
<c:forEach var="col" items="#{someBean.features}">
<tr:column headerText="Column-#{col.id}">
<tr:outputText value="#{col.name}"/>
</tr:column>
</c:forEach>
</tr:table>
But when I profiled the above code, the method someBean.getValues which is the input to the <tr:table/> tag above was getting called several thousands of times rather than about 20. This - as I figured out - was due to the fact that <c:forEach/> tag is a compile time tag where as <tr:*/> are render time tags.
So, here's what I intend to do (replace <c:forEach/> with <tr:iterator/>:
<tr:table value="#{someBean.values}">
<tr:column headerText="Name">
<tr:outputText value="#{someBean.name}"/>
</tr:column>
<tr:iterator var="col" value="#{someBean.features}">
<tr:column headerText="Column-#{col.id}">
<tr:outputText value="#{col.name}"/>
</tr:column>
</tr:iterator>
</tr:table>
But, for some reason, the <tr:iterator/> doesn't seem to like being placed inside a <tr:table/> and it never gets executed.
Any solution, tips, guidelines will be greatly appreciated.
Oh and we're using JSF 1.1 with a MyFaces Trinidad 1.0.13 implementation.
Thanks.
Only way i think (about which you may know already ;) ) is to write extend UIXTable and provide a custom taghandler to process <tr:columns items="#{columns}"> and expand the columns array into html columns
A getter call is a particularly cheap operation. If your getters do their job as they are intented for, just returning the bean property, then this should really not harm.
This concern gives me the impression that you're incorrectly doing some expensive business job inside a getter method instead of a constructor or some event method which is invoked only once upon a request. You should really fix that accordingly. Getters should not do any business job or at highest just do some lazy loading.
As to why the <c:forEach> works and the <tr:iterator> not, that's because JSTL tags runs during view build time, not during view render time and that the only valid child of an UIData component is an UIColumn component. Basically, when the view is to be built, all JSTL tags will run and you end up with a pure JSF view with all <tr:column> in the right places already. When the view is to be rendered, all JSF tags will run and you end up with a pure HTML result which can then be sent to the browser.
See also:
Why JSF calls getters multiple times
Our Topic object has BOTH isChannel and getChannel public methods. The object graph is too complex to change this. Channel has an Integer type.
We are migrating from one application server to Tomcat. When using this expression ${topic.channel.type}, in JSPs our current app server finds the getChannel method. However, Tomcat finds the isChannel method and we get errors since the return type is a Boolean, not a Channel. Is there a way to tell Tomcat to prefer getters over boolean public methods?
For now I'm just going to write a helper function or expose a new method, but I have a feeling I'm going to come across this quite a bit during the migration.
Unfortunately, you can't force a method call like that.
I have checked the Javabeans and EL specifications, but nowhere is specified what the preferred method is when both isXXX() and getXXX() methods are present. However, I do agree that it makes more sense to prefer the getXXX() one in this particular case. This should also be programmatically possible. I think it's worth the effort to report this as an issue against the Tomcat EL implementation.
In theory, this should be more of a JavaBeans issue than an EL implementation issue. One thing you might try is to find out how the java.beans.Introspector views your Topic class. One way to do that would be to run this code I wrote a while back for the Struts wiki. Depending on the complexity of your class, it might make sense to create an explicit java.beans.BeanInfo class to force the channel property to always be exposed as an Integer.