All Downloads are FREE. Search and download functionalities are using the official Maven repository.

freemarker.cache.ClassTemplateLoader Maven / Gradle / Ivy

There is a newer version: 7.0.58
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package freemarker.cache;

import java.net.URL;

import freemarker.template.utility.NullArgumentException;
import freemarker.template.utility.StringUtil;

/**
 * A {@link TemplateLoader} that can load templates from the "classpath". Naturally, it can load from jar files, or from
 * anywhere where Java can load classes from. Internally, it uses {@link Class#getResource(String)} or
 * {@link ClassLoader#getResource(String)} to load templates.
 */
public class ClassTemplateLoader extends URLTemplateLoader {
    
    private final Class resourceLoaderClass;
    private final ClassLoader classLoader;
    private final String basePackagePath;

    /**
     * Creates a template loader that will use the {@link Class#getResource(String)} method of its own class to load the
     * resources, and {@code "/"} as base package path. This means that that template paths will be resolved relatively
     * the root package of the class hierarchy, so you hardly ever should use this constructor, rather do something like
     * this:
* {@link #ClassTemplateLoader(Class, String) new ClassTemplateLoader(com.example.myapplication.SomeClass.class, * "templates")} * *

* If you extend this class, then the extending class will be used to load the resources. * * @deprecated It's a confusing constructor, and seldom useful; use {@link #ClassTemplateLoader(Class, String)} * instead. */ @Deprecated public ClassTemplateLoader() { this(null, true, null, "/"); } /** * Creates a template loader that will use the {@link Class#getResource(String)} method of the specified class to * load the resources, and {@code ""} as base package path. This means that template paths will be resolved * relatively to the class location, that is, relatively to the directory (package) of the class. * * @param resourceLoaderClass * the class whose {@link Class#getResource(String)} will be used to load the templates. * * @deprecated It's confusing that the base path is {@code ""}; use {@link #ClassTemplateLoader(Class, String)} * instead. */ @Deprecated public ClassTemplateLoader(Class resourceLoaderClass) { this(resourceLoaderClass, ""); } /** * Creates a template loader that will use the {@link Class#getResource(String)} method of the specified class to * load the resources, and the specified base package path (absolute or relative). * *

* Examples: *

    *
  • Relative base path (will load from the {@code com.example.myapplication.templates} package):
    * {@code new ClassTemplateLoader(com.example.myapplication.SomeClass.class, "templates")} *
  • Absolute base path:
    * {@code new ClassTemplateLoader(somepackage.SomeClass.class, "/com/example/myapplication/templates")} *
* * @param resourceLoaderClass * The class whose {@link Class#getResource(String)} method will be used to load the templates. Be sure * that you chose a class whose defining class-loader sees the templates. This parameter can't be * {@code null}. * @param basePackagePath * The package that contains the templates, in path ({@code /}-separated) format. If it doesn't start * with a {@code /} then it's relative to the path (package) of the {@code resourceLoaderClass} class. If * it starts with {@code /} then it's relative to the root of the package hierarchy. Note that path * components should be separated by forward slashes independently of the separator character used by the * underlying operating system. This parameter can't be {@code null}. * * @see #ClassTemplateLoader(ClassLoader, String) */ public ClassTemplateLoader(Class resourceLoaderClass, String basePackagePath) { this(resourceLoaderClass, false, null, basePackagePath); } /** * Similar to {@link #ClassTemplateLoader(Class, String)}, but instead of {@link Class#getResource(String)} it uses * {@link ClassLoader#getResource(String)}. Because a {@link ClassLoader} isn't bound to any Java package, it * doesn't mater if the {@code basePackagePath} starts with {@code /} or not, it will be always relative to the root * of the package hierarchy * * @since 2.3.22 */ public ClassTemplateLoader(ClassLoader classLoader, String basePackagePath) { this(null, true, classLoader, basePackagePath); } private ClassTemplateLoader(Class resourceLoaderClass, boolean allowNullResourceLoaderClass, ClassLoader classLoader, String basePackagePath) { if (!allowNullResourceLoaderClass) { NullArgumentException.check("resourceLoaderClass", resourceLoaderClass); } NullArgumentException.check("basePackagePath", basePackagePath); // Either set a non-null resourceLoaderClass or a non-null classLoader, not both: this.resourceLoaderClass = classLoader == null ? (resourceLoaderClass == null ? this.getClass() : resourceLoaderClass) : null; if (this.resourceLoaderClass == null && classLoader == null) { throw new NullArgumentException("classLoader"); } this.classLoader = classLoader; String canonBasePackagePath = canonicalizePrefix(basePackagePath); if (this.classLoader != null && canonBasePackagePath.startsWith("/")) { canonBasePackagePath = canonBasePackagePath.substring(1); } this.basePackagePath = canonBasePackagePath; } @Override protected URL getURL(String name) { String fullPath = basePackagePath + name; // Block java.net.URLClassLoader exploits: if (basePackagePath.equals("/") && !isSchemeless(fullPath)) { return null; } return resourceLoaderClass != null ? resourceLoaderClass.getResource(fullPath) : classLoader .getResource(fullPath); } private static boolean isSchemeless(String fullPath) { int i = 0; int ln = fullPath.length(); // Skip a single initial /, as things like "/file:/..." might work: if (i < ln && fullPath.charAt(i) == '/') i++; // Check if there's no ":" earlier than a '/', as the URLClassLoader // could interpret that as an URL scheme: while (i < ln) { char c = fullPath.charAt(i); if (c == '/') return true; if (c == ':') return false; i++; } return true; } /** * Show class name and some details that are useful in template-not-found errors. * * @since 2.3.21 */ @Override public String toString() { return TemplateLoaderUtils.getClassNameForToString(this) + "(" + (resourceLoaderClass != null ? "resourceLoaderClass=" + resourceLoaderClass.getName() : "classLoader=" + StringUtil.jQuote(classLoader)) + ", basePackagePath" + "=" + StringUtil.jQuote(basePackagePath) + (resourceLoaderClass != null ? (basePackagePath.startsWith("/") ? "" : " /* relatively to resourceLoaderClass pkg */") : "" ) + ")"; } /** * See the similar parameter of {@link #ClassTemplateLoader(Class, String)}; {@code null} when other mechanism is * used to load the resources. * * @since 2.3.22 */ public Class getResourceLoaderClass() { return resourceLoaderClass; } /** * See the similar parameter of {@link #ClassTemplateLoader(ClassLoader, String)}; {@code null} when other mechanism * is used to load the resources. * * @since 2.3.22 */ public ClassLoader getClassLoader() { return classLoader; } /** * See the similar parameter of {@link #ClassTemplateLoader(ClassLoader, String)}; note that this is a normalized * version of what was actually passed to the constructor. * * @since 2.3.22 */ public String getBasePackagePath() { return basePackagePath; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy