Skip to content
This repository has been archived by the owner on Jan 8, 2020. It is now read-only.

Commit

Permalink
Continued number/date/time formatter API and code reworkings.
Browse files Browse the repository at this point in the history
  • Loading branch information
ddekany committed Aug 30, 2015
1 parent 9c73c09 commit e0a3ff0
Show file tree
Hide file tree
Showing 10 changed files with 294 additions and 164 deletions.
13 changes: 8 additions & 5 deletions src/main/java/freemarker/core/BuiltInsForMultipleTypes.java
Original file line number Diff line number Diff line change
Expand Up @@ -572,10 +572,11 @@ private class NumberFormatter
this.numberModel = numberModel;
this.env = env;
try {
defaultFormat = env.getTemplateNumberFormat(env.getNumberFormat());
} catch (InvalidFormatDescriptorException e) {
throw new _MiscTemplateException(
stringBI.this, e, env, "Failed to get default number format; see cause exception");
defaultFormat = env.getTemplateNumberFormat(stringBI.this);
} catch (TemplateException e) {
// Must convert TemplateException-s to TemplateModelException-s due to API restriction.
throw new _TemplateModelException(
target, e.getCause(), env, e.getMessage());
}
}

Expand All @@ -588,6 +589,7 @@ public TemplateModel get(String key) throws TemplateModelException {
try {
return new SimpleScalar(env.formatNumber(numberModel, key, target));
} catch (TemplateException e) {
// Must convert TemplateException-s to TemplateModelException-s due to API restriction.
throw new _TemplateModelException(
target, e.getCause(), env, e.getMessage());
}
Expand All @@ -596,8 +598,9 @@ public TemplateModel get(String key) throws TemplateModelException {
public String getAsString() throws TemplateModelException {
if (cachedValue == null) {
try {
cachedValue = env.formatNumber(numberModel, target);
cachedValue = env.formatNumber(numberModel, defaultFormat, target);
} catch (TemplateException e) {
// Must convert TemplateException-s to TemplateModelException-s due to API restriction.
throw new _TemplateModelException(
target, e.getCause(), env, e.getMessage());
}
Expand Down
261 changes: 151 additions & 110 deletions src/main/java/freemarker/core/Environment.java
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ public final class Environment extends Configurable {

private TemplateNumberFormat cachedTemplateNumberFormat;
private Map<String, TemplateNumberFormat> cachedTemplateNumberFormats;
private Map<String, LocalTemplateNumberFormatFactory> cachedTemplateNumberFormatFactories;
private Map<String, LocalTemplateNumberFormatFactory> cachedLocalTemplateNumberFormatFactories;

/**
* Stores the date/time/date-time formatters that are used when no format is explicitly given at the place of
Expand Down Expand Up @@ -827,7 +827,14 @@ public void setLocale(Locale locale) {
super.setLocale(locale);
if (!locale.equals(prevLocale)) {
cachedTemplateNumberFormats = null;
cachedTemplateNumberFormat = null;
if (cachedTemplateNumberFormat != null && cachedTemplateNumberFormat.isLocaleBound()) {
cachedTemplateNumberFormat = null;
}
if (cachedLocalTemplateNumberFormatFactories != null) {
for (LocalTemplateNumberFormatFactory factory : cachedLocalTemplateNumberFormatFactories.values()) {
factory.setLocale(locale);
}
}

if (javaLocTempNumberFormatFactory != null) {
javaLocTempNumberFormatFactory.setLocale(locale);
Expand All @@ -842,25 +849,25 @@ public void setLocale(Locale locale) {
}
}

if (cachedXSLocTempDateFormatFactory != null && cachedXSLocTempDateFormatFactory.isLocaleBound()) {
cachedXSLocTempDateFormatFactory = null;
if (cachedXSLocTempDateFormatFactory != null) {
cachedXSLocTempDateFormatFactory.setLocale(locale);
}
if (cachedSQLDTXSLocTempDateFormatFactory != null && cachedSQLDTXSLocTempDateFormatFactory.isLocaleBound()) {
cachedSQLDTXSLocTempDateFormatFactory = null;
if (cachedSQLDTXSLocTempDateFormatFactory != null) {
cachedSQLDTXSLocTempDateFormatFactory.setLocale(locale);;
}

if (cachedISOLocTempDateFormatFactory != null && cachedISOLocTempDateFormatFactory.isLocaleBound()) {
cachedISOLocTempDateFormatFactory = null;
if (cachedISOLocTempDateFormatFactory != null) {
cachedISOLocTempDateFormatFactory.setLocale(locale);
}
if (cachedSQLDTISOLocTempDateFormatFactory != null && cachedSQLDTISOLocTempDateFormatFactory.isLocaleBound()) {
cachedSQLDTISOLocTempDateFormatFactory = null;
if (cachedSQLDTISOLocTempDateFormatFactory != null) {
cachedSQLDTISOLocTempDateFormatFactory.setLocale(locale);
}

if (cachedJavaLocTempDateFormatFactory != null && cachedJavaLocTempDateFormatFactory.isLocaleBound()) {
cachedJavaLocTempDateFormatFactory = null;
if (cachedJavaLocTempDateFormatFactory != null) {
cachedJavaLocTempDateFormatFactory.setLocale(locale);
}
if (cachedSQLDTJavaLocTempDateFormatFactory != null && cachedSQLDTJavaLocTempDateFormatFactory.isLocaleBound()) {
cachedSQLDTJavaLocTempDateFormatFactory = null;
if (cachedSQLDTJavaLocTempDateFormatFactory != null) {
cachedSQLDTJavaLocTempDateFormatFactory.setLocale(locale);
}

cachedCollator = null;
Expand Down Expand Up @@ -1039,48 +1046,152 @@ public Writer getOut() {
return out;
}

@Override
public void setNumberFormat(String formatName) {
super.setNumberFormat(formatName);
cachedTemplateNumberFormat = null;
}

/**
* Format number with the default number format.
*/
String formatNumber(TemplateNumberModel number, Expression exp) throws TemplateException {
if (cachedTemplateNumberFormat == null) {
String formatDesc = getNumberFormat();
try {
cachedTemplateNumberFormat = getTemplateNumberFormat(formatDesc);
} catch (InvalidFormatDescriptorException e) {
throw new _MiscTemplateException(exp, e, this,
"Failed to get number format for the default format descriptor, ",
new _DelayedJQuote(formatDesc), "; see cause exception");
}
}
return formatNumber(number, getTemplateNumberFormat(exp), exp);
}

/**
* Format number with the number format specified as the parameter.
*/
String formatNumber(TemplateNumberModel number, String formatDesc, Expression exp) throws TemplateException {
return formatNumber(number, getTemplateNumberFormat(formatDesc, exp), exp);
}

String formatNumber(TemplateNumberModel number, TemplateNumberFormat format, Expression exp)
throws TemplateModelException, _MiscTemplateException {
try {
return cachedTemplateNumberFormat.format(number);
return format.format(number);
} catch (UnformattableNumberException e) {
throw new _MiscTemplateException(exp, e, this, "Failed to format number with "
+ new _DelayedJQuote(getNumberFormat()) + ": " + e.getMessage());
throw new _MiscTemplateException(exp, e, this,
"Failed to format number with ", new _DelayedJQuote(format.getDescription()), ": ",
e.getMessage());
}
}

/**
* Format number with the number format specified as the parameter.
* Returns the current number format.
*
* @since 2.3.24
*/
String formatNumber(TemplateNumberModel number, String formatDesc, Expression exp) throws TemplateException {
public TemplateNumberFormat getTemplateNumberFormat() throws InvalidFormatDescriptorException {
TemplateNumberFormat format = cachedTemplateNumberFormat;
if (format == null) {
format = getTemplateNumberFormat(getNumberFormat());
cachedTemplateNumberFormat = format;
}
return format;
}

/**
* Returns the number format for the given format descriptor. The returned value shouldn't be stored for later
* reuse, as the returned instance can be different when this method is called later again, for example if the
* locale has been changed since then.
*
* @since 2.3.24
*/
public TemplateNumberFormat getTemplateNumberFormat(String formatDesc) throws InvalidFormatDescriptorException {
if (cachedTemplateNumberFormats == null) {
cachedTemplateNumberFormats = new HashMap<String, TemplateNumberFormat>();
}

{
TemplateNumberFormat format = cachedTemplateNumberFormats.get(formatDesc);
if (format != null) {
return format;
}
}

TemplateNumberFormat format;
int ln = formatDesc.length();
char c;
if (ln > 0 && formatDesc.charAt(0) == '@') {
String name;
{
int endIdx;
findNameEnd: for (endIdx = 1; endIdx < ln; endIdx++) {
c = formatDesc.charAt(endIdx);
if (c == ' ' || c == '_') {
break findNameEnd;
}
}
name = formatDesc.substring(1, endIdx);
}

LocalTemplateNumberFormatFactory localFormatFactory =
cachedLocalTemplateNumberFormatFactories != null ? cachedLocalTemplateNumberFormatFactories.get(name) : null;
if (localFormatFactory == null) {
TemplateNumberFormatFactory formatFactory = getCustomNumberFormat(name);
if (formatFactory == null) {
throw new InvalidFormatDescriptorException(
"No custom number format was defined with name " + StringUtil.jQuote(name), formatDesc);
}
localFormatFactory = formatFactory.createLocalFactory(this, getLocale());
if (cachedLocalTemplateNumberFormatFactories == null) {
cachedLocalTemplateNumberFormatFactories = new HashMap<String, LocalTemplateNumberFormatFactory>();
}
cachedLocalTemplateNumberFormatFactories.put(name, localFormatFactory);
}

format = localFormatFactory.get(formatDesc);
} else {
if (javaLocTempNumberFormatFactory == null) {
javaLocTempNumberFormatFactory = new JavaLocalTemplateNumberFormatFactory(this);
javaLocTempNumberFormatFactory.setLocale(getLocale());
}
format = javaLocTempNumberFormatFactory.get(formatDesc);
}

cachedTemplateNumberFormats.put(formatDesc, format);
return format;
}

/**
* Returns the {@link NumberFormat} used for the <tt>c</tt> built-in.
* This is always US English <code>"0.################"</code>, without
* grouping and without superfluous decimal separator.
*/
public NumberFormat getCNumberFormat() {
// It can't be cached in a static field, because DecimalFormat-s aren't
// thread-safe.
if (cNumberFormat == null) {
cNumberFormat = (DecimalFormat) C_NUMBER_FORMAT.clone();
}
return cNumberFormat;
}

TemplateNumberFormat getTemplateNumberFormat(Expression exp)
throws _MiscTemplateException {
TemplateNumberFormat format;
try {
return getTemplateNumberFormat(formatDesc).format(number);
format = getTemplateNumberFormat();
} catch (InvalidFormatDescriptorException e) {
throw new _MiscTemplateException(exp, e, this,
"Failed to get number format for the format descriptor, ",
new _DelayedJQuote(formatDesc), "; see cause exception");
} catch (UnformattableNumberException e) {
throw new _MiscTemplateException(exp, e, this, "Failed to format number with "
+ new _DelayedJQuote(getNumberFormat()) + ": " + e.getMessage());
"Failed to get number format object for the current number format string, ",
new _DelayedJQuote(getNumberFormat()), "; see cause exception");
}
return format;
}

@Override
public void setNumberFormat(String formatName) {
super.setNumberFormat(formatName);
cachedTemplateNumberFormat = null;

TemplateNumberFormat getTemplateNumberFormat(String formatDesc, Expression exp)
throws _MiscTemplateException {
TemplateNumberFormat format;
try {
format = getTemplateNumberFormat(formatDesc);
} catch (InvalidFormatDescriptorException e) {
throw new _MiscTemplateException(exp, e, this,
"Failed to get number format object for the ", new _DelayedJQuote(formatDesc),
" number format string; see cause exception");
}
return format;
}

@Override
Expand Down Expand Up @@ -1138,62 +1249,6 @@ void clearLastReturnValue() {
this.lastReturnValue = null;
}

TemplateNumberFormat getTemplateNumberFormat(String formatDesc) throws InvalidFormatDescriptorException {
if (cachedTemplateNumberFormats == null) {
cachedTemplateNumberFormats = new HashMap<String, TemplateNumberFormat>();
}

{
TemplateNumberFormat format = cachedTemplateNumberFormats.get(formatDesc);
if (format != null) {
return format;
}
}

TemplateNumberFormat format;
int ln = formatDesc.length();
char c;
if (ln > 0 && formatDesc.charAt(0) == '@') {
String name;
{
int endIdx;
findNameEnd: for (endIdx = 1; endIdx < ln; endIdx++) {
c = formatDesc.charAt(endIdx);
if (c == ' ' || c == '_') {
break findNameEnd;
}
}
name = formatDesc.substring(1, endIdx);
}

LocalTemplateNumberFormatFactory localFormatFactory =
cachedTemplateNumberFormatFactories != null ? cachedTemplateNumberFormatFactories.get(name) : null;
if (localFormatFactory == null) {
TemplateNumberFormatFactory formatFactory = getCustomNumberFormat(name);
if (formatFactory == null) {
throw new InvalidFormatDescriptorException(
"No custom number format was defined with name " + StringUtil.jQuote(name), formatDesc);
}
localFormatFactory = formatFactory.createLocalFactory(this, getLocale());
if (cachedTemplateNumberFormatFactories == null) {
cachedTemplateNumberFormatFactories = new HashMap<String, LocalTemplateNumberFormatFactory>();
}
cachedTemplateNumberFormatFactories.put(name, localFormatFactory);
}

format = localFormatFactory.get(formatDesc);
} else {
if (javaLocTempNumberFormatFactory == null) {
javaLocTempNumberFormatFactory = new JavaLocalTemplateNumberFormatFactory(this);
javaLocTempNumberFormatFactory.setLocale(getLocale());
}
format = javaLocTempNumberFormatFactory.get(formatDesc);
}

cachedTemplateNumberFormats.put(formatDesc, format);
return format;
}

String formatDate(TemplateDateModel tdm, Expression tdmSourceExpr) throws TemplateModelException {
Date date = EvalUtil.modelToDate(tdm, tdmSourceExpr);
try {
Expand Down Expand Up @@ -1435,20 +1490,6 @@ DateToISO8601CalendarFactory getISOBuiltInCalendarFactory() {
return isoBuiltInCalendarFactory;
}

/**
* Returns the {@link NumberFormat} used for the <tt>c</tt> built-in.
* This is always US English <code>"0.################"</code>, without
* grouping and without superfluous decimal separator.
*/
public NumberFormat getCNumberFormat() {
// It can't be cached in a static field, because DecimalFormat-s aren't
// thread-safe.
if (cNumberFormat == null) {
cNumberFormat = (DecimalFormat) C_NUMBER_FORMAT.clone();
}
return cNumberFormat;
}

TemplateTransformModel getTransform(Expression exp) throws TemplateException {
TemplateTransformModel ttm = null;
TemplateModel tm = exp.eval(this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,6 @@ public ISOLikeLocalTemplateDateFormatFactory(Environment env) {
super(env);
}

@Override
public boolean isLocaleBound() {
return false;
}

public DateToISO8601CalendarFactory getISOBuiltInCalendar() {
DateToISO8601CalendarFactory r = dateToCalenderFieldsCalculator;
if (r == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,6 @@ public JavaLocalTemplateDateFormatFactory(Environment env) {
super(env);
}

@Override
public boolean isLocaleBound() {
return true;
}

/**
* @param zonelessInput Has no effect in this implementation.
*/
Expand Down
Loading

0 comments on commit e0a3ff0

Please sign in to comment.