On 05.07.2007 00:47, Grzegorz Kossakowski wrote:
As Daniel pointed out, it has been discussed but I must admit I'm not
completely sure that I "feel" the concept.
I like Daniel's post [1] a lot. It goes very much into the direction of
PropertyEditors. Quoting him:
"As a solution to the problem he sugests MVCR
(Model-View-Controller-Renderer), where the renderer is responsible for
converting (Java) data types to displayable strings. The renderer can be
responsible for localization of numbers etc as well. The renderer is an
extra step between model and view."
The renderer applies very much to the original idea of PropertyEditor.
"Displayable" in the GUI programming might be a bit more complex. That's
why there is a method getCustomEditor() returning a java.awt.Component
for example. For web programming to and from string conversion should be
sufficient.
"The simplest possible renderer is to just implement toString() in the
classes one is going to access in the view. But a better SoC is to have
a separate rendering component. In this case the object from the model
is first accessed by an expression in a suitable expression language and
then the object is rendered to a displayable string by the rendering
component and at last the displayable string is emited by the template
engine."
The externalized toString() describes quite perfectly what
PropertyEditor actually does.
How does it work (pseudo code and simplified):
BeanWrapper wrappedOM = new BeanWrapper(objectModel);
String displayString = wrappedOM.getProperty(aPath);
Internally BeanWrapper does:
Object value = getPropertyValue(objectModel, aPath);
Class valueType = getPropertyType(objectModel, aPath);
PropertyEditor editor =
PropertyEditorRegistry.findCustomEditor(valueType, aPath);
editor.setValue(value);
return editor.getAsText();
From purist's point of view it is really _bad_ idea to use interfaces
and classes for something that they were not invented for.
See above, it's not that far away. Unfortunately, Java started with GUI
programming before it founds its niche, the web programming. That's what
you still can find on this interface.
To be honest I'm not Spring specialist so I do not understand which
infrastructure exactly and how it helps. Even more confusing is that
something is going to be replaced by something else. I really don't know
what replaces what and what's for. Sorry.
I feared that my first collection of thoughts was too confusing. Will
focus on the important stuff now.
Do you want to state that you can define only one Converter for Foo
class? Or do you want to say that in Spring MVC you can register
converter for Foo class that is available by using particular epxression
(like xyz/bar/foo)?
The latter. If xyz/bar/foo would not be of type Foo it would not match.
What do you mean by registering? The idea for converters is that you
just create a bean (that implements necessary interface) and you are done.
Where does the template know from which converter to apply? For the
example ${myobj.startDate#short} "short" must actually be defined and
registered somewhere, doesn't it? How did you say: "short date (whatever
it means)" :-) That's defined by a particular converter which can be
looked up by the template in the registry.
I always found the JEXL/JXPath syntax rather counterintuitive.
What was counter-intuitive apart from switching between both that I do
not like either?
The ${} and #{}, the impedance mismatch between objects and xml model:
JXPath on beans does not behave like on xml.
How Spring syntax looks like and how it is better than JXPath/JEXL?
Bean property syntax which as used in other template languages like
Velocity and scripting languages as well: object1.object2.property.
3. Locale. PropertyEditors have no support for i18n/l10n. [..]
I had a look at Spring's CustomDateEditor [9]. It's set up with a
DateFormat. Since PropertyEditors should be prototypes anyway I
don't see a problem to inject the Locale into the editor on
registration as done via DateFormat for the CustomDateEditor.
That works without the PropertyEditors being locale-aware.
It all looks like plumbing and is counter-intuitive for my taste. It may
be that I miss the idea totally. If you could explain it and say way
such solution is better than proposed one it would be very helpful.
Ok, recently somebody posted the SimpleFormController Lifecycle Cheat
Sheet[2] in the Spring forum, which shows the request processing in the
controller. Don't try to understand it, I just want to show where we
are. One of the first things in the request processing is initBinder
which actually takes the request as parameter. That means you can
determine the locale in that method. You are supposed to register your
PropertyEditors in this method:
Binder.registerCustomEditor(Class, ProperyEditor);
So for the date converter:
Locale locale = // determine from request
DateFormat dateFormat = DateFormat.getDateInstance(SHORT, locale)
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat,
..));
So it's not the PropertyEditor being locale-aware but the PropertyEditor
instantiation. It creates the proper (= correct locale) PropertyEditor.
But yes, I don't like it that much anyway. Actually I used it very
rarely in my project. There is a much better way to do this than those
scattering the PropertyEditors all over the place. So you might drop
that complete section from mind :-)
Now the better approach while answering Daniel's mail:
On 05.07.2007 14:24, Daniel Fagerstrom wrote:
Locale awareness is part of the idea.
Yes, of course. Somehow it has to come into play. But you see above that
it is at least possible with locale-unaware converters.
Architecture
============
The "converter architecture" as I imagine it consist of three parts.
* Converters:
* Converter registry:
* Integration:
I agree completely. It's only about the details. The only difference I
see actually is on which parameters the converter is chosen.
Converters
----------
IMO it would be cleaner to have the locale dependency in the registry
instead of in the converter.
I agree. This means locale is removed from the converter methods.
Next the convertor needs a format cache, this is IIRC because date and
number formating objects not are thread safe and takes some work to construct.
They are not [3]:
"Date formats are not synchronized. It is recommended to create separate
format instances for each thread. If multiple threads access a format
concurrently, it must be synchronized externally."
Same for NumberFormat and probably others as well. So no advantage over
PropertyEditors which suffer from the same problem. I don't think we
need a "real" format cache, it only seems to complicate stuff. The
proposed ThreadLocal might be a solution. Spring holds them on the
binder where they get registered once. Might be limiting since it's
targetted to form processing obviously.
Last the convertFromString returns a ConversionResult while setAsText
throws a IllegalArgumentException for badly formated input strings.
BeanWrapper does that part (mapping IllegalArgumentException to
something "controllable", similar as you work with ConversionResult).
As a conclusion I think that PropertyEditors would work fine for us if
we find it worthwhile.
Fine. I do :-)
Converter Registry
----------
For a Cocoon framework I would prefer looking up a converter based on
class, locale and variant, while I don't see any obvious use cases for
property path.
Indeed the PropertyEditorRegistry seems not to meet our requirements.
(copied from further above, better fits in here)
The framework select based on data type and locale. But for e.g. dates
there are several different string representations (short, medium, full
and long or maybe some custom format) that the template or form author
needs to choose between. To me it seem reasonable to have a syntax for
making this possible in e.g. the template.
As I wrote repeatedly the possibility to influence the formatting from
the template breaks the two-way process. You can't parse a date
expecting a FULL pattern string when receiving a string formatted with
SHORT pattern. And there is no chance to get informed about this mismatch.
The property path could be used to determine the variant instead of
specifying it explicitly. It's obviously not that flexible - but can't
be broken in that way. That's why I would opt for class, locale and
path, so add locale to Spring's PropertyEditorRegistry methods.
So as a conclusion: it would be nice to reuse the Spring stuff and
there are big overlaps, but especially for locale handling it is not
obvious to me how to use it. Then of course there is the question if
it is worthwhile to reuse.
The concepts seem to be totally equal. We only extend the registry with
the locale. Then I mentioned a new way of registering PropertyEditors,
the PropertyEditorRegistrar. That's actually a PropertyEditor factory
which also does the registering shown above when talking about the
initBinder() method. It is possible to set up such a registrar once (!)
in the application context and reuse it in the application context
itself (e.g. for custom data types) or in the controllers. The point I
want to make is the following: This PropertyEditorRegistrar is in
contrary to initBinder() not even request-aware and so not locale-aware
at all. So I wonder how it is supposed to be done in Spring now. Maybe
filing an issue for an extension of the registry brings this into 2.1
and we do not have to invent anything new. And even if not there is
still so much to reuse and it's IMO absolutely worthwile to do it.
I hope, I did not write too much non-sense in my hurry. Have to get to
the plane to the US (finally!) soon. Maybe I could even clarify a bit of
the confusion I caused with the last mail. :-)
Regards,
Joerg
[1] http://article.gmane.org/gmane.text.xml.cocoon.devel/42968
[2]
http://home.exetel.com.au/cweatures/dev/SimpleFormControllerCheatSheet.pdf
[3] http://java.sun.com/j2se/1.4.2/docs/api/java/text/DateFormat.html