Repository: incubator-freemarker Updated Branches: refs/heads/2.3-gae 5cee74f81 -> bd7498e8d
Added workaround against IllegalStateException: zip file closed issues (caused by bugs outside of FreeMarker) when loading resources included in the FreeMarker jar (see freemarker.template.utility.ClassUtil.getReasourceAsStream). Related to https://github.com/apache/incubator-freemarker/pull/37. Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/bd7498e8 Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/bd7498e8 Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/bd7498e8 Branch: refs/heads/2.3-gae Commit: bd7498e8d7e724c7bbc1f769f001b3f7df56debf Parents: 5cee74f Author: ddekany <[email protected]> Authored: Fri Oct 6 21:34:48 2017 +0200 Committer: ddekany <[email protected]> Committed: Fri Oct 6 21:34:48 2017 +0200 ---------------------------------------------------------------------- .../freemarker/ext/beans/UnsafeMethods.java | 6 +- .../java/freemarker/ext/jsp/TaglibFactory.java | 15 +---- .../java/freemarker/template/Configuration.java | 68 ++++++++++---------- .../freemarker/template/utility/ClassUtil.java | 48 ++++++++++++++ src/manual/en_US/book.xml | 8 +++ 5 files changed, 92 insertions(+), 53 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/bd7498e8/src/main/java/freemarker/ext/beans/UnsafeMethods.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/ext/beans/UnsafeMethods.java b/src/main/java/freemarker/ext/beans/UnsafeMethods.java index ed6d248..f590085 100644 --- a/src/main/java/freemarker/ext/beans/UnsafeMethods.java +++ b/src/main/java/freemarker/ext/beans/UnsafeMethods.java @@ -44,13 +44,9 @@ class UnsafeMethods { private static final Set createUnsafeMethodsSet() { Properties props = new Properties(); - InputStream in = BeansWrapper.class.getResourceAsStream("unsafeMethods.properties"); - if (in == null) { - throw new IllegalStateException("Class loader resource not found: " - + BeansWrapper.class.getPackage().getName() + UNSAFE_METHODS_PROPERTIES); - } String methodSpec = null; try { + InputStream in = ClassUtil.getReasourceAsStream(BeansWrapper.class, UNSAFE_METHODS_PROPERTIES); try { props.load(in); } finally { http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/bd7498e8/src/main/java/freemarker/ext/jsp/TaglibFactory.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/ext/jsp/TaglibFactory.java b/src/main/java/freemarker/ext/jsp/TaglibFactory.java index fbb11a4..0dc07b1 100644 --- a/src/main/java/freemarker/ext/jsp/TaglibFactory.java +++ b/src/main/java/freemarker/ext/jsp/TaglibFactory.java @@ -1257,17 +1257,10 @@ public class TaglibFactory implements TemplateHashModel { public InputStream getInputStream() throws IOException { ClassLoader tccl = tryGetThreadContextClassLoader(); if (tccl != null) { - final InputStream in = getClass().getResourceAsStream(resourcePath); - if (in != null) { - return in; - } + return ClassUtil.getReasourceAsStream(getClass(), resourcePath); } - final InputStream in = getClass().getResourceAsStream(resourcePath); - if (in == null) { - throw newResourceNotFoundException(); - } - return in; + return ClassUtil.getReasourceAsStream(getClass(), resourcePath); } public String getXmlSystemId() throws IOException { @@ -1282,10 +1275,6 @@ public class TaglibFactory implements TemplateHashModel { final URL url = getClass().getResource(resourcePath); return url == null ? null : url.toExternalForm(); } - - private IOException newResourceNotFoundException() { - return new IOException("Resource not found: classpath:" + resourcePath); - } } http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/bd7498e8/src/main/java/freemarker/template/Configuration.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/template/Configuration.java b/src/main/java/freemarker/template/Configuration.java index 95d4172..53358b1 100644 --- a/src/main/java/freemarker/template/Configuration.java +++ b/src/main/java/freemarker/template/Configuration.java @@ -151,7 +151,7 @@ public class Configuration extends Configurable implements Cloneable, ParserConf private static final Logger CACHE_LOG = Logger.getLogger("freemarker.cache"); - private static final String VERSION_PROPERTIES_PATH = "freemarker/version.properties"; + private static final String VERSION_PROPERTIES_PATH = "/freemarker/version.properties"; /** Legacy, snake case ({@code like_this}) variation of the setting name. @since 2.3.23 */ public static final String DEFAULT_ENCODING_KEY_SNAKE_CASE = "default_encoding"; @@ -436,36 +436,31 @@ public class Configuration extends Configurable implements Cloneable, ParserConf static { try { Properties vp = new Properties(); - InputStream ins = Configuration.class.getClassLoader() - .getResourceAsStream(VERSION_PROPERTIES_PATH); - if (ins == null) { - throw new RuntimeException("Version file is missing."); - } else { - try { - vp.load(ins); - } finally { - ins.close(); + InputStream ins = ClassUtil.getReasourceAsStream(Configuration.class, VERSION_PROPERTIES_PATH); + try { + vp.load(ins); + } finally { + ins.close(); + } + + String versionString = getRequiredVersionProperty(vp, "version"); + + Date buildDate; + { + String buildDateStr = getRequiredVersionProperty(vp, "buildTimestamp"); + if (buildDateStr.endsWith("Z")) { + buildDateStr = buildDateStr.substring(0, buildDateStr.length() - 1) + "+0000"; } - - String versionString = getRequiredVersionProperty(vp, "version"); - - Date buildDate; - { - String buildDateStr = getRequiredVersionProperty(vp, "buildTimestamp"); - if (buildDateStr.endsWith("Z")) { - buildDateStr = buildDateStr.substring(0, buildDateStr.length() - 1) + "+0000"; - } - try { - buildDate = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US).parse(buildDateStr); - } catch (java.text.ParseException e) { - buildDate = null; - } + try { + buildDate = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US).parse(buildDateStr); + } catch (java.text.ParseException e) { + buildDate = null; } - - final Boolean gaeCompliant = Boolean.valueOf(getRequiredVersionProperty(vp, "isGAECompliant")); - - VERSION = new Version(versionString, gaeCompliant, buildDate); } + + final Boolean gaeCompliant = Boolean.valueOf(getRequiredVersionProperty(vp, "isGAECompliant")); + + VERSION = new Version(versionString, gaeCompliant, buildDate); } catch (IOException e) { throw new RuntimeException("Failed to load and parse " + VERSION_PROPERTIES_PATH, e); } @@ -537,6 +532,8 @@ public class Configuration extends Configurable implements Cloneable, ParserConf private ConcurrentMap localeToCharsetMap = new ConcurrentHashMap(); /** + * Same as {@link #Configuration(Version) Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS)}. + * * @deprecated Use {@link #Configuration(Version)} instead. Note that the version can be still modified later with * {@link Configuration#setIncompatibleImprovements(Version)} (or * {@link Configuration#setSettings(Properties)}). @@ -555,11 +552,11 @@ public class Configuration extends Configurable implements Cloneable, ParserConf * * <p>This setting value is the FreeMarker version number where the not 100% backward compatible bug fixes and * improvements that you want to enable were already implemented. In new projects you should set this to the - * FreeMarker version that you are actually using. In older projects it's also usually better to keep this high, - * however you better check the changes activated (find them below), at least if not only the 3rd version number - * (the micro version) of {@code incompatibleImprovements} is increased. Generally, as far as you only increase the - * last version number of this setting, the changes are always low risk. The default value is 2.3.0 to maximize - * backward compatibility, but that value isn't recommended. + * version of FreeMarker that you start the development with. In older projects it's also usually better to keep + * this high, however you should check the changes activated (find them below), especially if not only the 3rd + * version number (the micro version) of {@code incompatibleImprovements} is increased. Generally, as far as you + * only increase the last version number of this setting, the changes are low risk. The default value is 2.3.0 to + * maximize backward compatibility, but that value isn't recommended. * * <p>Bugfixes and improvements that are fully backward compatible, also those that are important security fixes, * are enabled regardless of the incompatible improvements setting. @@ -576,8 +573,9 @@ public class Configuration extends Configurable implements Cloneable, ParserConf * <p>Currently the effects of this setting are: * <ul> * <li><p> - * 2.3.0: This is the lowest supported value, the version used in older projects. This is the default in the - * FreeMarker 2.3.x series. + * 2.3.0: This is the lowest supported value, the version used in very old projects. This is the default in the + * FreeMarker 2.3.x series (the one used by the deprecated {@link #Configuration()} constructor) for maximum + * backward compatibility. * </li> * <li><p> * 2.3.19 (or higher): Bug fix: Wrong {@code #} tags were printed as static text instead of http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/bd7498e8/src/main/java/freemarker/template/utility/ClassUtil.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/template/utility/ClassUtil.java b/src/main/java/freemarker/template/utility/ClassUtil.java index 0aa40cb..7d97839 100644 --- a/src/main/java/freemarker/template/utility/ClassUtil.java +++ b/src/main/java/freemarker/template/utility/ClassUtil.java @@ -19,6 +19,9 @@ package freemarker.template.utility; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; import java.util.HashSet; import java.util.Set; @@ -379,4 +382,49 @@ public class ClassUtil { || type.isPrimitive() && type != Boolean.TYPE && type != Character.TYPE && type != Void.TYPE; } + /** + * Very similar to {@link Class#getResourceAsStream(String)}, but throws {@link IOException} instead of returning + * {@code null}, and attempts to work around "IllegalStateException: zip file closed" issues (caused by bugs + * outside of FreeMarker). + * + * @return Never {@code null} + * @throws IOException If the resource wasn't found, or other {@link IOException} occurs. + */ + public static InputStream getReasourceAsStream(Class<?> baseClass, String resource) throws IOException { + InputStream ins; + try { + ins = baseClass.getResourceAsStream(resource); + } catch (IllegalStateException e) { + // Workaround for "IllegalStateException: zip file closed". This happens due to bugs outside of FreeMarker + // (sometimes caused by the caching of jar URL connection streams), but we try to work it around anyway. + URL url = baseClass.getResource(resource); + ins = url != null ? url.openStream() : null; + } + if (ins == null) { + throw new IOException("Class-loader resource not found (shown quoted): \"" + + StringUtil.jQuote(resource) + "\". The base class was " + baseClass.getName() + "."); + } + return ins; + } + + /** + * Same as {@link #getReasourceAsStream(Class, String)}, but uses a {@link ClassLoader} directly instead of a + * {@link Class}. + */ + public static InputStream getReasourceAsStream(ClassLoader classLoader, String resource) + throws IOException { + InputStream ins; + try { + ins = classLoader.getResourceAsStream(resource); + } catch (IllegalStateException e) { + URL url = classLoader.getResource(resource); + ins = url != null ? url.openStream() : null; + } + if (ins == null) { + throw new IOException("Class-loader resource not found (shown quoted): \"" + + StringUtil.jQuote(resource) + "\". The base ClassLoader was: " + classLoader); + } + return ins; + } + } http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/bd7498e8/src/manual/en_US/book.xml ---------------------------------------------------------------------- diff --git a/src/manual/en_US/book.xml b/src/manual/en_US/book.xml index 4573010..2068fe3 100644 --- a/src/manual/en_US/book.xml +++ b/src/manual/en_US/book.xml @@ -27349,6 +27349,14 @@ TemplateModel x = env.getVariable("x"); // get variable x</programlisting> </listitem> </itemizedlist> </listitem> + + <listitem> + <para>Added workaround against <quote>IllegalStateException: zip + file closed</quote> issues (caused by bugs outside of + FreeMarker) when loading resources included in the FreeMarker + jar (see + <literal>freemarker.template.utility.ClassUtil.getReasourceAsStream</literal>).</para> + </listitem> </itemizedlist> </section> </section>
