/** * Same as {@link #setParentConfiguration(Configuration)}. * * @throws IllegalArgumentException if the argument is {@code null} or not a {@link * Configuration}. */ @Override void setParent(Configurable cfg) { NullArgumentException.check("cfg", cfg); if (!(cfg instanceof Configuration)) { throw new IllegalArgumentException( "The parent of a TemplateConfigurer can only be a Configuration"); } if (parentConfigurationSet) { if (getParent() != cfg) { throw new IllegalStateException( "This TemplateConfigurer is already associated with a different Configuration instance."); } return; } if (((Configuration) cfg).getIncompatibleImprovements().intValue() < _TemplateAPI.VERSION_INT_2_3_22 && hasAnyConfigurableSet()) { throw new IllegalStateException( "This TemplateConfigurer can't be associated to a Configuration that has incompatibleImprovements " + "less than 2.3.22, because it changes non-parser settings."); } super.setParent(cfg); parentConfigurationSet = true; }
/** Creates a plain text (unparsed) template. */ private UnboundTemplate(String content, String sourceName, Configuration cfg) { NullArgumentException.check(cfg); this.cfg = cfg; this.sourceName = sourceName; this.templateLanguageVersion = normalizeTemplateLanguageVersion(cfg.getIncompatibleImprovements()); this.templateSpecifiedEncoding = null; rootElement = new TextBlock(content); actualTagSyntax = cfg.getTagSyntax(); actualNamingConvention = cfg.getNamingConvention(); }
/** * @param reader Reads the template source code * @param cfg The FreeMarker configuration settings; some of them influences parsing, also the * resulting {@link UnboundTemplate} will be bound to this. * @param assumedEncoding This is the name of the charset that we are supposed to be using. This * is only needed to check if the encoding specified in the {@code #ftl} header (if any) * matches this. If this is non-{@code null} and they don't match, a {@link * WrongEncodingException} will be thrown by the parser. * @param sourceName Shown in error messages as the template "file" location. */ UnboundTemplate(Reader reader, String sourceName, Configuration cfg, String assumedEncoding) throws IOException { NullArgumentException.check(cfg); this.cfg = cfg; this.sourceName = sourceName; this.templateLanguageVersion = normalizeTemplateLanguageVersion(cfg.getIncompatibleImprovements()); LineTableBuilder ltbReader; try { if (!(reader instanceof BufferedReader)) { reader = new BufferedReader(reader, 0x1000); } ltbReader = new LineTableBuilder(reader); reader = ltbReader; try { FMParser parser = new FMParser( this, reader, assumedEncoding, cfg.getStrictSyntaxMode(), cfg.getWhitespaceStripping(), cfg.getTagSyntax(), cfg.getNamingConvention(), cfg.getIncompatibleImprovements().intValue()); TemplateElement rootElement; try { rootElement = parser.Root(); } catch (IndexOutOfBoundsException exc) { // There's a JavaCC bug where the Reader throws a RuntimeExcepton and then JavaCC fails // with // IndexOutOfBoundsException. If that wasn't the case, we just rethrow. Otherwise we // suppress the // IndexOutOfBoundsException and let the real cause to be thrown later. if (!ltbReader.hasFailure()) { throw exc; } rootElement = null; } this.rootElement = rootElement; this.actualTagSyntax = parser._getLastTagSyntax(); this.actualNamingConvention = parser._getLastNamingConvention(); this.templateSpecifiedEncoding = parser._getTemplateSpecifiedEncoding(); } catch (TokenMgrError exc) { // TokenMgrError VS ParseException is not an interesting difference for the user, so we just // convert it // to ParseException throw exc.toParseException(this); } } catch (ParseException e) { e.setTemplateName(getSourceName()); throw e; } finally { reader.close(); } // Throws any exception that JavaCC has silently treated as EOF: ltbReader.throwFailure(); if (prefixToNamespaceURIMapping != null) { prefixToNamespaceURIMapping = Collections.unmodifiableMap(prefixToNamespaceURIMapping); namespaceURIToPrefixMapping = Collections.unmodifiableMap(namespaceURIToPrefixMapping); } }
/** * Updates the content of the {@link #typeFlagsByParamCount} field with the parameter type flags * of a method. Don't call this when {@link #bugfixed} is {@code false}! * * @param dstParamCount The parameter count for which we want to merge in the type flags * @param srcTypeFlagsByParamIdx If shorter than {@code dstParamCount}, its last item will be * repeated until dstParamCount length is reached. If longer, the excessive items will be * ignored. Maybe {@link #ALL_ZEROS_ARRAY}. Maybe a 0-length array. Can't be {@code null}. */ protected final void mergeInTypesFlags(int dstParamCount, int[] srcTypeFlagsByParamIdx) { NullArgumentException.check("srcTypesFlagsByParamIdx", srcTypeFlagsByParamIdx); // Special case of 0 param count: if (dstParamCount == 0) { if (typeFlagsByParamCount == null) { typeFlagsByParamCount = ZERO_PARAM_COUNT_TYPE_FLAGS_ARRAY; } else if (typeFlagsByParamCount != ZERO_PARAM_COUNT_TYPE_FLAGS_ARRAY) { typeFlagsByParamCount[0] = ALL_ZEROS_ARRAY; } return; } // Ensure that typesFlagsByParamCount[dstParamCount] exists: if (typeFlagsByParamCount == null) { typeFlagsByParamCount = new int[dstParamCount + 1][]; } else if (typeFlagsByParamCount.length <= dstParamCount) { int[][] newTypeFlagsByParamCount = new int[dstParamCount + 1][]; System.arraycopy( typeFlagsByParamCount, 0, newTypeFlagsByParamCount, 0, typeFlagsByParamCount.length); typeFlagsByParamCount = newTypeFlagsByParamCount; } int[] dstTypeFlagsByParamIdx = typeFlagsByParamCount[dstParamCount]; if (dstTypeFlagsByParamIdx == null) { // This is the first method added with this number of params => no merging if (srcTypeFlagsByParamIdx != ALL_ZEROS_ARRAY) { int srcParamCount = srcTypeFlagsByParamIdx.length; dstTypeFlagsByParamIdx = new int[dstParamCount]; for (int paramIdx = 0; paramIdx < dstParamCount; paramIdx++) { dstTypeFlagsByParamIdx[paramIdx] = srcTypeFlagsByParamIdx[paramIdx < srcParamCount ? paramIdx : srcParamCount - 1]; } } else { dstTypeFlagsByParamIdx = ALL_ZEROS_ARRAY; } typeFlagsByParamCount[dstParamCount] = dstTypeFlagsByParamIdx; } else { // dstTypeFlagsByParamIdx != null, so we need to merge into it. if (srcTypeFlagsByParamIdx == dstTypeFlagsByParamIdx) { // Used to occur when both are ALL_ZEROS_ARRAY return; } // As we will write dstTypeFlagsByParamIdx, it can't remain ALL_ZEROS_ARRAY anymore. if (dstTypeFlagsByParamIdx == ALL_ZEROS_ARRAY && dstParamCount > 0) { dstTypeFlagsByParamIdx = new int[dstParamCount]; typeFlagsByParamCount[dstParamCount] = dstTypeFlagsByParamIdx; } for (int paramIdx = 0; paramIdx < dstParamCount; paramIdx++) { final int srcParamTypeFlags; if (srcTypeFlagsByParamIdx != ALL_ZEROS_ARRAY) { int srcParamCount = srcTypeFlagsByParamIdx.length; srcParamTypeFlags = srcTypeFlagsByParamIdx[paramIdx < srcParamCount ? paramIdx : srcParamCount - 1]; } else { srcParamTypeFlags = 0; } final int dstParamTypesFlags = dstTypeFlagsByParamIdx[paramIdx]; if (dstParamTypesFlags != srcParamTypeFlags) { int mergedTypeFlags = dstParamTypesFlags | srcParamTypeFlags; if ((mergedTypeFlags & TypeFlags.MASK_ALL_NUMERICALS) != 0) { // Must not be set if we don't have numerical type at this index! mergedTypeFlags |= TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT; } dstTypeFlagsByParamIdx[paramIdx] = mergedTypeFlags; } } } }
/** * When the standard template loading/caching mechanism is used, this forces the charset used for * reading the template "file", overriding everything but the encoding coming from the {@code * #ftl} header. This setting overrides the locale-specific encodings set via {@link * Configuration#setEncoding(java.util.Locale, String)}. It also overrides the {@code encoding} * parameter of {@link Configuration#getTemplate(String, String)} (and of its overloads) and the * {@code encoding} parameter of the {@code #include} directive. This works like that because * specifying the encoding where you are requesting the template is error prone and deprecated. * * <p>If you are developing your own template loading/caching mechanism instead of the standard * one, note that the above behavior is not guaranteed by this class alone; you have to ensure it. * Also, read the note on {@code encoding} in the documentation of {@link #configure(Template)}. */ public void setEncoding(String encoding) { NullArgumentException.check("encoding", encoding); this.encoding = encoding; }
/** * Sets the output format of the template; see {@link Configuration#setOutputFormat(OutputFormat)} * for more. */ public void setOutputFormat(OutputFormat outputFormat) { NullArgumentException.check("outputFormat", outputFormat); this.outputFormat = outputFormat; }