/*
 * Licensed 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 org.jdbi.v3.core.statement;

import java.text.MessageFormat;
import java.util.AbstractMap;
import java.util.Comparator;
import java.util.Set;

Uses the equivalent of MessageFormat.format(String, Object...) as a template engine. You must use "0", "1", "2", etc as keys: start at 0, increment by 1. Keys must be numerically unique. You must Configurable.define(String, Object) as many key/value pairs as there are placeholders in the pattern string. You may define key/value pairs in any order. Keys may contain leading '0's. Any invalid use will trigger an IllegalArgumentException (or subclasses such as NumberFormatException) when render(String, StatementContext) is called – typically when the statement is about to be executed. Example usage:

    // select bar from foo where col = 'abc'
    jdbi.useHandle(handle -> handle.createCall("select {1} from {0} where col = ''{2}''")
        .setTemplateEngine(MessageFormatTemplateEngine.INSTANCE)
        .define("0", "foo")
        .define("1", "bar")
        .define("2", "abc")
        .invoke());
Deprecated:MessageFormat formats integers with decimal separators, e.g. 1000"1,000". This hindsight realization has led us to discourage its use.
/** * Uses the equivalent of {@link MessageFormat#format(String, Object...)} as a template engine. * * You must use "0", "1", "2", etc as keys: start at 0, increment by 1. Keys must be numerically unique. You must {@link org.jdbi.v3.core.config.Configurable#define(String, Object)} as many key/value pairs as there are placeholders in the pattern string. * * You may {@code define} key/value pairs in any order. Keys may contain leading {@code '0'}s. * * Any invalid use will trigger an {@link IllegalArgumentException} (or subclasses such as {@link NumberFormatException}) when {@link #render(String, StatementContext)} is called – typically when the statement is about to be executed. * * Example usage: * <pre>{@code * // select bar from foo where col = 'abc' * jdbi.useHandle(handle -> handle.createCall("select {1} from {0} where col = ''{2}''") * .setTemplateEngine(MessageFormatTemplateEngine.INSTANCE) * .define("0", "foo") * .define("1", "bar") * .define("2", "abc") * .invoke()); * }</pre> * * @deprecated {@link MessageFormat} formats integers with decimal separators, e.g. <code>1000</code> &rarr; <code>"1,000"</code>. This hindsight realization has led us to discourage its use. */
@Deprecated public class MessageFormatTemplateEngine implements TemplateEngine { public MessageFormatTemplateEngine() {} @Override public String render(String template, StatementContext ctx) { MessageFormat msgFormat = new MessageFormat(template); validateKeys(ctx.getAttributes().keySet(), msgFormat.getFormats().length); Object[] args = ctx.getAttributes() .entrySet() .stream() .map(x -> new AbstractMap.SimpleImmutableEntry<>(Integer.valueOf(x.getKey()), x.getValue())) .sorted(Comparator.comparingInt(AbstractMap.SimpleImmutableEntry::getKey)) .map(AbstractMap.SimpleImmutableEntry::getValue) .toArray(Object[]::new); return msgFormat.format(args); } private static void validateKeys(Set<String> keySet, int expectedCount) { if (keySet.size() != expectedCount) { throw new IllegalArgumentException("expected " + expectedCount + " keys but got " + keySet.size()); } if (keySet.isEmpty()) { return; } // keys inherently cannot be null, so we only need to check the content final int[] keys = keySet.stream() // throws IllegalArgumentException for us .mapToInt(Integer::parseInt) .sorted() .toArray(); if (keys[0] != 0) { throw new IllegalArgumentException("lowest key must be 0"); } for (int i = 1; i < keys.length; i++) { final int key = keys[i]; if (key < i) { throw new IllegalArgumentException("key " + key + " was given more than once"); } if (key > i) { throw new IllegalArgumentException("keys skip from " + (i - 1) + " to " + key); } } } }