Discussion:
[FreeMarker-user] FreeMarker and java.util.Optional
Eirik Lygre
2014-12-01 11:19:57 UTC
Permalink
Hi,

Starting with java 8, java supports the new "Optional" class (
https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html).

* Did anybody give any thought to how this integrates with FreeMarker, for
example through a (custom?) ObjectWrapper or the like?

We will probably start exposing certain elements in our java layer as
Optional<SomeBusinessObject>. We haven't yet really thought about how this
integrates with FreeMarker, but I thought it better to ask sooner rather
than later, in case somebody has already been through this!

Eirik
Daniel Dekany
2014-12-02 22:33:34 UTC
Permalink
Not yet AFAIK, but that's good point. I guess FreeMarker should call
Optional.orElse(null) whenever it accesses an Optional. Thus ${user}
and ${user!'unknown'} will work even if `user` is a String or a
Optional<String>.
Post by Eirik Lygre
Hi,
Starting with java 8, java supports the new "Optional" class
(https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html).
* Did anybody give any thought to how this integrates with
FreeMarker, for example through a (custom?) ObjectWrapper or the like?
We will probably start exposing certain elements in our java layer
as Optional<SomeBusinessObject>. We haven't yet really thought about
how this integrates with FreeMarker, but I thought it better to ask
sooner rather than later, in case somebody has already been through this!
Eirik
--
Thanks,
Daniel Dekany
Eirik Lygre
2015-04-16 11:07:10 UTC
Permalink
We ended up adding the following to the wrap() function of our custom
ObjectWrapper, which works for our use-cases. Looking at it now, it should
probably be simplified (and fixed!) to "this.wrap(optional.orElse(null))",
but that's for another day.

if (obj instanceof Optional) {
Optional optional = (Optional)obj;
if (optional.isPresent()) {
return this.wrap(optional.get());
} else {
return null;
}
}
Post by Daniel Dekany
Not yet AFAIK, but that's good point. I guess FreeMarker should call
Optional.orElse(null) whenever it accesses an Optional. Thus ${user}
and ${user!'unknown'} will work even if `user` is a String or a
Optional<String>.
Post by Eirik Lygre
Hi,
Starting with java 8, java supports the new "Optional" class
(https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html).
* Did anybody give any thought to how this integrates with
FreeMarker, for example through a (custom?) ObjectWrapper or the like?
We will probably start exposing certain elements in our java layer
as Optional<SomeBusinessObject>. We haven't yet really thought about
how this integrates with FreeMarker, but I thought it better to ask
sooner rather than later, in case somebody has already been through this!
Eirik
--
Thanks,
Daniel Dekany
Daniel Dekany
2015-04-16 11:38:10 UTC
Permalink
Yes, just getting rid of the enclosing Optional is a possible quick
fix. Problems will arise when you try to do
ObjectWrapperAndUnwrapper.unwrap(TemplateModel) that value, since the
fact that the value was once an Optional is lost. FreeMarker will call
unwrap if it has to pass the value back to a plain Java method as
parameter (to be more precise, BeansWrapper does that). If the
unwrapping doesn't result in an Optional, now it should be smart
enough to convert it to an Optional. But then there's the problem of
overloaded method selection too (no wonder new static languages try to
avoid that tick... it's the source of lot pain when you have to
interact with dynamic languages), so certainly it had to be unwrapped
to Optional on the first place.

Then there's the question if how closely should FM follow Java's
rules. Concretely, in Java you can't pass an Optional<String> in where
a String is expected, or the other way around, but in a language with
no static typing that's possibly just annoying, and while unwrapping
should give back the original object, when calling a Java method there
should be still automatic conversion. Then we are back to the problem
of overloaded methods selection again, because then for an Optional
that holds a String, a method with a String parameter should ba a
candidate, even if with lower priority than an Optional<String>.
(Then, how do I know if an Optional of what type do I have, especially
if it's empty, since Java generics aren't reifiable...)
Post by Eirik Lygre
We ended up adding the following to the wrap() function of our
custom ObjectWrapper, which works for our use-cases. Looking at it
now, it should probably be simplified (and fixed!) to
"this.wrap(optional.orElse(null))", but that's for another day.
if (obj instanceof Optional) {
Optional optional = (Optional)obj;
if (optional.isPresent()) {
return this.wrap(optional.get());
} else {
return null;
}
}
Not yet AFAIK, but that's good point. I guess FreeMarker should call
Optional.orElse(null) whenever it accesses an Optional. Thus ${user}
and ${user!'unknown'} will work even if `user` is a String or a
Optional<String>.
Post by Eirik Lygre
Hi,
Starting with java 8, java supports the new "Optional" class
(https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html).
* Did anybody give any thought to how this integrates with
FreeMarker, for example through a (custom?) ObjectWrapper or the like?
We will probably start exposing certain elements in our java layer
as Optional<SomeBusinessObject>. We haven't yet really thought about
how this integrates with FreeMarker, but I thought it better to ask
sooner rather than later, in case somebody has already been through this!
Eirik
--
Thanks,
Daniel Dekany
--
Thanks,
Daniel Dekany
Loading...