[
https://issues.apache.org/jira/browse/FREEMARKER-213?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17744857#comment-17744857
]
Simon commented on FREEMARKER-213:
----------------------------------
Comparing to Stream, which is AutoCloseable, Java itself doesn't do anything
special here.
i.e. the following will not result in the Stream being closed:
{code:java}
final boolean[] closed = { false };
Stream<String> stream = Stream.of("a", "b", "c").onClose(() -> closed[0] =
true);
String first = stream.findFirst().orElse(null);
{code}
You're supposed to use try/finally or try-with-resources in order for the
stream to be closed (FreeMarker doesn't currently seem to have a nice
equivalent to those unfortunately).
> Handling AutoCloseable Iterators in ?filter / ?first when the iterator is not
> fully consumed
> ---------------------------------------------------------------------------------------------
>
> Key: FREEMARKER-213
> URL: https://issues.apache.org/jira/browse/FREEMARKER-213
> Project: Apache Freemarker
> Issue Type: Improvement
> Components: engine
> Affects Versions: 2.3.31
> Reporter: Christoph Rueger
> Priority: Minor
>
> HI,
> We have expressions like:
> {code:java}
> ${myCatalog.getCSVFileRowsIterator()?filter(row -> row.get("categoryId") ==
> "123")?first}
> {code}
> Under the hood this becomes an IteratorModel().
> The problem is that:
> - the underlying iterator is working on a resource (file, stream)
> - which needs to be *closed when finished*.
> - but ?filter and ?first can abandon and leave the iterator somewhere in the
> middle once it has identified a match
> - this caused Resource Leaks in some cases.
> I debugged down to the following code in _freemarker.core.new
> TemplateModelIterator() {...}.ensurePrefetchDone())_
> {code:java}
> private void ensurePrefetchDone() throws TemplateModelException {
> if (prefetchDone) {
> return;
> }
> boolean conclusionReached = false;
> do {
> if (lhoIterator.hasNext()) {
> TemplateModel element =
> lhoIterator.next();
> boolean elementMatched;
> try {
> elementMatched =
> elementMatches(element, elementTransformer, env);
> } catch (TemplateException e) {
> throw new
> _TemplateModelException(e, env, "Failed to transform element");
> }
> if (elementMatched) {
> prefetchedElement = element;
> conclusionReached = true;
> }
> } else {
> prefetchedEndOfIterator = true;
> prefetchedElement = null;
> conclusionReached = true;
> }
> } while (!conclusionReached);
> prefetchDone = true;
> }
> {code}
> It looks like at this place we have the "iterator" and also know when we stop
> iterating, when finding a match.
> *Question*
> Would it be possible to check if the underlying Iterator implements
> _java.lang.AutoCloseable_ and if yes, call _.close()_ on it, when a match is
> found?
> I am not sure if that is the right thing to do here.
> We have built workarounds so that AutoCloseable objects in the datamodel are
> closed after rendering is finished.
> But it would be better to close it as soon as possible, when the iterator is
> stopped to be consumed. This would help in scenarios where the template does
> that multiple times, e.g.:
> {code:java}
> ${myCustomObject.getCSVRowsIterator()?filter(row -> row.get("categoryId") ==
> "123")?first}
> ${myCustomObject.getCSVRowsIterator()?filter(row -> row.get("categoryId") ==
> "234")?first}
> {code}
> Ideas would be welcome, where this kind of "closing" should happen.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)