@@ -1636,36 +1636,81 @@ public void setDirectoryForTemplateLoading(File dir) throws IOException {
16361636 *
16371637 * @param servletContext the {@code javax.servlet.ServletContext} object. (The declared type is {@link Object}
16381638 * to prevent class loading error when using FreeMarker in an environment where
1639- * there's no servlet classes available.)
1640- * @param path the path relative to the ServletContext.
1639+ * there's no servlet classes available.) Can't be {@code null}.
1640+ * @param path the path relative to the ServletContext; maybe {@code null} .
16411641 *
16421642 * @see #setTemplateLoader(TemplateLoader)
16431643 */
16441644 public void setServletContextForTemplateLoading (Object servletContext , String path ) {
1645+ NullArgumentException .check ("servletContext" , servletContext );
1646+
1647+ // To not introduce linking-time dependency on servlets, we load all related classes on runtime.
1648+ Class <?> servletContextClass = null ;
1649+ Boolean jakartaMode = null ;
1650+
1651+ Exception jakartaServletClassLoadingException = null ;
16451652 try {
1646- // Don't introduce linking-time dependency on servlets
1647- final Class webappTemplateLoaderClass = ClassUtil .forName ("freemarker.cache.WebappTemplateLoader" );
1648-
1649- // Don't introduce linking-time dependency on servlets
1650- final Class servletContextClass = ClassUtil .forName ("javax.servlet.ServletContext" );
1651-
1652- final Class [] constructorParamTypes ;
1653- final Object [] constructorParams ;
1654- if (path == null ) {
1655- constructorParamTypes = new Class [] { servletContextClass };
1656- constructorParams = new Object [] { servletContext };
1657- } else {
1658- constructorParamTypes = new Class [] { servletContextClass , String .class };
1659- constructorParams = new Object [] { servletContext , path };
1653+ servletContextClass = ClassUtil .forName ("jakarta.servlet.ServletContext" );
1654+ if (servletContextClass .isInstance (servletContext )) {
1655+ jakartaMode = true ;
16601656 }
1661-
1662- setTemplateLoader ( (TemplateLoader )
1663- webappTemplateLoaderClass
1657+ } catch (Exception e ) {
1658+ jakartaServletClassLoadingException = e ;
1659+ }
1660+
1661+ Exception javaxServletClassLoadingException = null ;
1662+ if (jakartaMode == null ) {
1663+ try {
1664+ servletContextClass = ClassUtil .forName ("javax.servlet.ServletContext" );
1665+ if (servletContextClass .isInstance (servletContext )) {
1666+ jakartaMode = false ;
1667+ }
1668+ } catch (Exception e ) {
1669+ javaxServletClassLoadingException = e ;
1670+ }
1671+ }
1672+
1673+ if (servletContextClass == null ) {
1674+ throw new UnsupportedOperationException ("Failed to get ServletContext class; probably Servlet API-s "
1675+ + "are not supported in this environment, but check the exceptions:"
1676+ + "\n - When attempted use Jakarta Servlet support: " + jakartaServletClassLoadingException
1677+ + "\n - When attempted use javax Servlet support: " + javaxServletClassLoadingException );
1678+ }
1679+ if (jakartaMode == null ) {
1680+ throw new IllegalArgumentException ("servletContext must implement ServletContext, but "
1681+ + servletContext .getClass ().getName () + " does not." );
1682+ }
1683+
1684+ Class <?> webappTemplateLoaderClass ;
1685+ try {
1686+ webappTemplateLoaderClass = ClassUtil .forName (
1687+ jakartaMode
1688+ ? "freemarker.ext.jakarta.servlet.WebappTemplateLoader"
1689+ : "freemarker.cache.WebappTemplateLoader" );
1690+ } catch (ClassNotFoundException e ) {
1691+ throw new RuntimeException ("Failed to get WebappTemplateLoader class" , e );
1692+ }
1693+
1694+ final Class <?>[] constructorParamTypes ;
1695+ final Object [] constructorParams ;
1696+ if (path == null ) {
1697+ constructorParamTypes = new Class <?>[] { servletContextClass };
1698+ constructorParams = new Object [] { servletContext };
1699+ } else {
1700+ constructorParamTypes = new Class [] { servletContextClass , String .class };
1701+ constructorParams = new Object [] { servletContext , path };
1702+ }
1703+
1704+ TemplateLoader templateLoader ;
1705+ try {
1706+ templateLoader = (TemplateLoader ) webappTemplateLoaderClass
16641707 .getConstructor (constructorParamTypes )
1665- .newInstance (constructorParams ) );
1708+ .newInstance (constructorParams );
16661709 } catch (Exception e ) {
1667- throw new BugException ( e );
1710+ throw new RuntimeException ( "Failed to instantiate " + webappTemplateLoaderClass . getName (), e );
16681711 }
1712+
1713+ setTemplateLoader (templateLoader );
16691714 }
16701715
16711716 /**
0 commit comments