Just digging through my posts of the last years, I found that my last post to ResourceResolvers and JCR sessions is more than a year old. But unfortunately that does not mean, that this aspects seems widely understood; I still see a lot of improper use of these topics, when I review project code as part of my job.
But instead of explaining again and again, that you should never forget to close them, I want to introduce a different pattern, which can help you to avoid the “old pattern” of opening and closing completely. It’s a pattern, which encapsulates the opening and closing of a ResourceResolver, and your code is executed then as a Consumer or Function within. The ResourceResolver cannot leak, and you cannot do anything wrong. The only pre-requisite is Java 8, but that must not be a problem in 2020.
// does not return anything public void withResourceResolver (Map<String,Object> authenticationInfo, Consumer<ResourceResolver> consumer) { try (ResourceResolver resolver = ResourceResolverFactory.getResourceResolver(authenticationInfo);) { consumer.accept (resolver); } catch (Exception e) { LOGGER.error ("Exception happend while opening ResourceResolver",e); } }
Same is possible with a function to return a value
// return a value from the lambda public <T> T withResourceResolver (Map<String,Object> authenticationInfo, Function<ResourceResolver,T> function, T defaultValue) { try (ResourceResolver resolver = ResourceResolverFactory.getResourceResolver(authenticationInfo);) { return function.apply(resolver); } catch (Exception e) { LOGGER.error ("Exception happend while opening ResourceResolver",e); } return defaultValue; } // convenience function public <T> T withResourceResolver (Map<String,Object> authenticationInfo, Function<ResourceResolver,T> function) { return withSession(authenticationInfo,function, null;) }
So if you are not familiar with the functional style of Java 8, some small examples how to use these methods:
Map<String,Object> authenticationInfo = … withResourceResolver(authenticationInfo, resolver -> { Resource res = resolver.getResource("/"); // do something more useful, but return nothing }); // return a value from the lambda Map<String,Object> authenticationInfo = … String result = withResourceResolver(authenticationInfo, resolver -> { Resource res = resolver.getResource("/"); return res.getPath(); });
As you can easily see, you don’t need to deal anymore with the lifecycle of ResourceResolvers anymore. And if your authenticationInfo map is always the same, you can even hardcode it within the withSession() methods, so the only parameter remains the consumer or the function.