I have a custom jsp tag that outputs a spring form input field (plus other layout elements). What I need to do is to be able to accept dynamic attributes and use them in the input field as-is.
Eg of use:
<mytag:myinputtag arbitraryAttribute="value"/>
Should output
<input:form arbitraryAttribute="value" />
Unfortunately it doesn't work as expected because it throws an unterminated form:input tag exception. Following is the code I used:
<%@ tag dynamic-attributes="attributes" %>
<c:set var="expandedAttributes">
<c:forEach var="a" items="${ attributes }">
${a.key}="${a.value}"<%= " " %>
</c:forEach>
</c:set>
<form:input (...) ${expandedAttributes} />
I can understand why this doesn't work as expected because of the resolution order of the EL expr and the tags. Therefore I have also tested to inject directly using scriptlets
<form:input (...) <%= (String)jspContext.getAttribute("expandedAttributes")%> --%>
So I need a solution to this issue as I cannot preview all the attributes that could be added to the input. Therefore I thought of the following possibilities:
- Using
<input
instead of<form:input
, meaning that I have to replicate exactly the spring code for the "path" attribute (not good idea) - Extend form:input tag, copy dynamic attributes into default attributes and do standard tag rendering (don't know if is a feasible solution and if spring change its input tag implementation then it could not work properly anymore)
- Enumerating all the attributes I need, this make the tag code huge and less maintainable
I would like to know if maybe there is a better solution I haven't though of, or if the second possibility is feasible at all.
Thanks
After a month of work on this issue I've considered surrending and removing the tag file alltogheter.
There is no implementation that allows me to inject the attributes as I want so I changed approach and tried to generate a tag that generates a body and then evaluates it. Also this approach doesn't work because the jsp and tags are compiled before execution and therefore its not possible to inject JSP code in the tag body.
So I have found a solution that currently works and it goes like this:
I have created my own input tag that extends from spring's
InputTag.java
. This tag accepts a special attribute calleddynAttrs
of typejava.util.Map
; these are the dynamic attributes passed from my parent tag. The rest of valid/accepted tag attributes is the same as spring input tag.Then in the
writeTagContent
method I check if thedynAttrs
are avaiable and for each attribute i do:PropertyAccessor
to set the value (e.g.onClick
)data-customData
)From here on I simply call the super.writeTagContent() and voilĂ , spring does all the magic for me!
Example of usage:
it will be transformed in
and down the stream transformed in
and then will be rendered as
So I can dynamically inject any number of dynamic attributes, at runtime, in spring's input tag!
NOTE: Since I'm not fond of this approach yet I have prepared two other implementations of this solution:
use apache common's BeanUtils.populate to populate the tag with the dynAttrs directly but error management in this case can be critical.
cache in a hashmap all the accessible fields in this tag and update them manually with a
field.setValue(this,dynAttrs.get(attrName))
(should be faster since it doesn't need to retrieve the field each call, but maybe thePropertyAccessor
does the same?).