[ 
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)

Reply via email to