Discussion:
[Freemarker-devel] Implement customizable number formatter
Ernst Plüss
2015-08-21 09:20:12 UTC
Permalink
Hello

From
http://stackoverflow.com/questions/32111234/how-to-implement-logic-for-bigdecimal-rendering-in-freemarker
I learnded, that some kind of plugable number formatter should come soon.

Is there alreday any code on github for this?

If not, what's the general aproach add this functionality? After having a
look at the sources, I think I could built this into
Environmen.formatNumber(Number number). Is this the intended way to
implement this?

Regards
Ernst
Daniel Dekany
2015-08-21 12:55:26 UTC
Permalink
I haven't started working on that yet. I *hope* I can start it
tomorrow or so. So I'm not yet 100% sure how it will look. I only know
for sure that it must be finished during the next week. (: So I
recommend you to just quickly shove in your NumberFormat class where
FreeMarker creates the DecimalFormat-s, and wait what will happen next
week... You can't really work ahead.

To answer your question, Environmen.formatNumber(Number) is and
remains a point where number formatting with the current format goes
through, of course. The interesting thing is though if how will number
formatters be represented (not java.text.NumberFormat anymore [*]),
and what object will create them. The (inherited) logic of FreeMarker
is that you specify a *string* as the "number_format" setting (which
can even be changed inside the template, in runtime), and then
internally that becomes to a cached(!) DecimalFormat object for the
current Locale. So certainly, there will be some simple interface like
freemarker.core.NumberFormatter, and then you will need to register a
freemarker.core.NumberFormatterFactory with a unique name (let's say
"price"), which then you can refer to like
cfg.setNumberFormat("@price"), <#setting numberFormat="@price">,
${x?string("@price")}, etc. And so there, the factory has a chance to
cache. Furthermore, after the number format string was delegated to
the NumberFormatFactory based on the name after the "@", it will get
the format string for parsing, so that stuff like "@price 0.00" can be
implemented. So those are my initial thoughts. (I will review how date
formatting works, which has a similarly fancy architecture for a
while, only that's not a public API... yet.)

*: Why not NumberFormat? Two reasons:

(a) One important goal of pluggable number formatters will be
automatic unit printing. In some apps, the template authors
aren't supposed to print the units manually. Like ${price},
where price is a number, should automatically print "1000 EUR"
or such. That requires the formatter to get the
TemplateNumberModel instead of just the Number, as it's the
TemplateNumberModel that carries the required meta-information.

(b) Number format is way too bloated if users meant to implement it
for some ad-hoc number format.
--
Thanks,
Daniel Dekany
Post by Ernst Plüss
Hello
From
http://stackoverflow.com/questions/32111234/how-to-implement-logic-for-bigdecimal-rendering-in-freemarker
I learnded, that some kind of plugable number formatter should come soon.
Is there alreday any code on github for this?
If not, what's the general aproach add this functionality? After
having a look at the sources, I think I could built this into
Environmen.formatNumber(Number number). Is this the intended way to implement this?
Regards
Ernst
------------------------------------------------------------------------------
Ernst Plüss
2015-08-21 13:19:36 UTC
Permalink
Hello Daniel

Many thanks for your extensive response!

I didn't ask to work ahaead. I wanted to check whether I could implement
the featrue and create a pull request in reasonable time ;-) .

Actually I'm looking for something different. What I need is a way to make
sure *every* BigDecimal (or whathever type I'm after) is transformed to a
String by user defined code. Since the formatting depends on the value of
the BigDecimal, I cannot use a static pattern.

As of now I registered a "formatBigDecimal()" function which does this. But
every now and then a developer forgets to use it and we end up with wrong
output.

I think writing

${x?string("@formatBigDecimal")}

instead of

formatBigDecimal(${value})

doesn't bring any benefit in my situation.

Regards
Ernst
Post by Daniel Dekany
I haven't started working on that yet. I *hope* I can start it
tomorrow or so. So I'm not yet 100% sure how it will look. I only know
for sure that it must be finished during the next week. (: So I
recommend you to just quickly shove in your NumberFormat class where
FreeMarker creates the DecimalFormat-s, and wait what will happen next
week... You can't really work ahead.
To answer your question, Environmen.formatNumber(Number) is and
remains a point where number formatting with the current format goes
through, of course. The interesting thing is though if how will number
formatters be represented (not java.text.NumberFormat anymore [*]),
and what object will create them. The (inherited) logic of FreeMarker
is that you specify a *string* as the "number_format" setting (which
can even be changed inside the template, in runtime), and then
internally that becomes to a cached(!) DecimalFormat object for the
current Locale. So certainly, there will be some simple interface like
freemarker.core.NumberFormatter, and then you will need to register a
freemarker.core.NumberFormatterFactory with a unique name (let's say
"price"), which then you can refer to like
cache. Furthermore, after the number format string was delegated to
implemented. So those are my initial thoughts. (I will review how date
formatting works, which has a similarly fancy architecture for a
while, only that's not a public API... yet.)
(a) One important goal of pluggable number formatters will be
automatic unit printing. In some apps, the template authors
aren't supposed to print the units manually. Like ${price},
where price is a number, should automatically print "1000 EUR"
or such. That requires the formatter to get the
TemplateNumberModel instead of just the Number, as it's the
TemplateNumberModel that carries the required meta-information.
(b) Number format is way too bloated if users meant to implement it
for some ad-hoc number format.
--
Thanks,
Daniel Dekany
Post by Ernst Plüss
Hello
From
http://stackoverflow.com/questions/32111234/how-to-implement-logic-for-bigdecimal-rendering-in-freemarker
Post by Ernst Plüss
I learnded, that some kind of plugable number formatter should come soon.
Is there alreday any code on github for this?
If not, what's the general aproach add this functionality? After
having a look at the sources, I think I could built this into
Environmen.formatNumber(Number number). Is this the intended way to
implement this?
Post by Ernst Plüss
Regards
Ernst
Daniel Dekany
2015-08-21 19:46:33 UTC
Permalink
Post by Ernst Plüss
Hello Daniel
Many thanks for your extensive response!
I didn't ask to work ahaead. I wanted to check whether I could
implement the featrue and create a pull request in reasonable time
Actually I'm looking for something different. What I need is a way
to make sure *every* BigDecimal (or whathever type I'm after) is
transformed to a String by user defined code. Since the formatting
depends on the value of the BigDecimal, I cannot use a static pattern.
As of now I registered a "formatBigDecimal()" function which does
this. But every now and then a developer forgets to use it and we end up with wrong output.
I think writing
instead of
formatBigDecimal(${value})
doesn't bring any benefit in my situation.
It sounds like something that you will be able to handle easily with
the planned formatter feature. You have a shared singleton
Configuration object, and there you call setNumberFormat(String) with
"@formatBigDecimal" or whatever you will call it. As your registered
formatter, and hence your own Java code gets the Number to format (the
whole TemplateNumberModel, actually), it can decide what to do based
on the number type and value. (Parsing the part after the @name is
also entirely up to the custom number formatter; the 0.00 patterns was
just an example.) So, in the template you just write ${x}.
--
Thanks,
Daniel Dekany
Post by Ernst Plüss
Regards
Ernst
I haven't started working on that yet. I *hope* I can start it
tomorrow or so. So I'm not yet 100% sure how it will look. I only know
for sure that it must be finished during the next week. (: So I
recommend you to just quickly shove in your NumberFormat class where
FreeMarker creates the DecimalFormat-s, and wait what will happen next
week... You can't really work ahead.
To answer your question, Environmen.formatNumber(Number) is and
remains a point where number formatting with the current format goes
through, of course. The interesting thing is though if how will number
formatters be represented (not java.text.NumberFormat anymore [*]),
and what object will create them. The (inherited) logic of FreeMarker
is that you specify a *string* as the "number_format" setting (which
can even be changed inside the template, in runtime), and then
internally that becomes to a cached(!) DecimalFormat object for the
current Locale. So certainly, there will be some simple interface like
freemarker.core.NumberFormatter, and then you will need to register a
freemarker.core.NumberFormatterFactory with a unique name (let's say
"price"), which then you can refer to like
cache. Furthermore, after the number format string was delegated to
implemented. So those are my initial thoughts. (I will review how date
formatting works, which has a similarly fancy architecture for a
while, only that's not a public API... yet.)
(a) One important goal of pluggable number formatters will be
automatic unit printing. In some apps, the template authors
aren't supposed to print the units manually. Like ${price},
where price is a number, should automatically print "1000 EUR"
or such. That requires the formatter to get the
TemplateNumberModel instead of just the Number, as it's the
TemplateNumberModel that carries the required meta-information.
(b) Number format is way too bloated if users meant to implement it
for some ad-hoc number format.
--
Thanks,
Daniel Dekany
Post by Ernst Plüss
Hello
From
http://stackoverflow.com/questions/32111234/how-to-implement-logic-for-bigdecimal-rendering-in-freemarker
I learnded, that some kind of plugable number formatter should come soon.
Is there alreday any code on github for this?
If not, what's the general aproach add this functionality? After
having a look at the sources, I think I could built this into
Environmen.formatNumber(Number number). Is this the intended way to implement this?
Regards
Ernst
------------------------------------------------------------------------------
Daniel Dekany
2015-09-01 00:25:08 UTC
Permalink
So, we have the custom number formats stuff, and I hope it's very
close to the final form. You can read about it here, under "Changes on
the Java side" mostly:
http://freemarker.org/builds/2.3.24-nightly/documentation/_html/versions_2_3_24.html

Then see the JUnit tests in the repo has some examples:
https://github.com/freemarker/freemarker/blob/2.3-gae/src/test/java/freemarker/core/NumberFormatTest.java

Binary:
http://freemarker.org/builds/2.3.24-nightly/freemarker.jar

Let me know what do you think.
--
Thanks,
Daniel Dekany
Post by Ernst Plüss
Hello Daniel
Many thanks for your extensive response!
I didn't ask to work ahaead. I wanted to check whether I could
implement the featrue and create a pull request in reasonable time
Actually I'm looking for something different. What I need is a way
to make sure *every* BigDecimal (or whathever type I'm after) is
transformed to a String by user defined code. Since the formatting
depends on the value of the BigDecimal, I cannot use a static pattern.
As of now I registered a "formatBigDecimal()" function which does
this. But every now and then a developer forgets to use it and we end up with wrong output.
I think writing
instead of
formatBigDecimal(${value})
doesn't bring any benefit in my situation.
Regards
Ernst
I haven't started working on that yet. I *hope* I can start it
tomorrow or so. So I'm not yet 100% sure how it will look. I only know
for sure that it must be finished during the next week. (: So I
recommend you to just quickly shove in your NumberFormat class where
FreeMarker creates the DecimalFormat-s, and wait what will happen next
week... You can't really work ahead.
To answer your question, Environmen.formatNumber(Number) is and
remains a point where number formatting with the current format goes
through, of course. The interesting thing is though if how will number
formatters be represented (not java.text.NumberFormat anymore [*]),
and what object will create them. The (inherited) logic of FreeMarker
is that you specify a *string* as the "number_format" setting (which
can even be changed inside the template, in runtime), and then
internally that becomes to a cached(!) DecimalFormat object for the
current Locale. So certainly, there will be some simple interface like
freemarker.core.NumberFormatter, and then you will need to register a
freemarker.core.NumberFormatterFactory with a unique name (let's say
"price"), which then you can refer to like
cache. Furthermore, after the number format string was delegated to
implemented. So those are my initial thoughts. (I will review how date
formatting works, which has a similarly fancy architecture for a
while, only that's not a public API... yet.)
(a) One important goal of pluggable number formatters will be
automatic unit printing. In some apps, the template authors
aren't supposed to print the units manually. Like ${price},
where price is a number, should automatically print "1000 EUR"
or such. That requires the formatter to get the
TemplateNumberModel instead of just the Number, as it's the
TemplateNumberModel that carries the required meta-information.
(b) Number format is way too bloated if users meant to implement it
for some ad-hoc number format.
--
Thanks,
Daniel Dekany
Post by Ernst Plüss
Hello
From
http://stackoverflow.com/questions/32111234/how-to-implement-logic-for-bigdecimal-rendering-in-freemarker
I learnded, that some kind of plugable number formatter should come soon.
Is there alreday any code on github for this?
If not, what's the general aproach add this functionality? After
having a look at the sources, I think I could built this into
Environmen.formatNumber(Number number). Is this the intended way to implement this?
Regards
Ernst
------------------------------------------------------------------------------
Daniel Dekany
2015-08-23 11:44:11 UTC
Permalink
Post by Daniel Dekany
I haven't started working on that yet. I *hope* I can start it
tomorrow or so.
It's "or so"... I'm lucky if I can start it tomorrow from now.
--
Thanks,
Daniel Dekany


------------------------------------------------------------------------------
Loading...