1993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira/* 2993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Copyright (C) 2007 Google Inc. 3993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 4993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Licensed under the Apache License, Version 2.0 (the "License"); 5993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * you may not use this file except in compliance with the License. 6993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * You may obtain a copy of the License at 7993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 8993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * http://www.apache.org/licenses/LICENSE-2.0 9993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 10993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Unless required by applicable law or agreed to in writing, software 11993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * distributed under the License is distributed on an "AS IS" BASIS, 12993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * See the License for the specific language governing permissions and 14993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * limitations under the License. 15993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira */ 16993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 171bdbfefe4b144c7b031a1d9242a0fa061a0ae6b5Scott Kennedypackage com.google.android.mail.common.base; 18993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 19993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereiraimport java.util.NoSuchElementException; 20993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 21993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira/** 22993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Simple static methods to be called at the start of your own methods to verify 23993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * correct arguments and state. This allows constructs such as 24993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * <pre> 25993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * if (count <= 0) { 26993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * throw new IllegalArgumentException("must be positive: " + count); 27993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * }</pre> 28993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 29993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * to be replaced with the more compact 30993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * <pre> 31993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * checkArgument(count > 0, "must be positive: %s", count);</pre> 32993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 33993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Note that the sense of the expression is inverted; with {@code Preconditions} 34993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * you declare what you expect to be <i>true</i>, just as you do with an 35993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * <a href="http://java.sun.com/j2se/1.5.0/docs/guide/language/assert.html"> 36993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * {@code assert}</a> or a JUnit {@code assertTrue} call. 37993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 38993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * <p><b>Warning:</b> only the {@code "%s"} specifier is recognized as a 39993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * placeholder in these messages, not the full range of {@link 40993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * String#format(String, Object[])} specifiers. 41993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 42993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * <p>Take care not to confuse precondition checking with other similar types 43993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * of checks! Precondition exceptions -- including those provided here, but also 44993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * {@link IndexOutOfBoundsException}, {@link NoSuchElementException}, {@link 45993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * UnsupportedOperationException} and others -- are used to signal that the 46993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * <i>calling method</i> has made an error. This tells the caller that it should 47993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * not have invoked the method when it did, with the arguments it did, or 48993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * perhaps ever. Postcondition or other invariant failures should not throw 49993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * these types of exceptions. 50993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 51993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @author Kevin Bourrillion 52993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @since 2010.01.04 <b>stable</b> (imported from Google Collections Library) 53993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira */ 54993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereirapublic class Preconditions { 55993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira private Preconditions() {} 56993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 57993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira /** 58993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Ensures the truth of an expression involving one or more parameters to the 59993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * calling method. 60993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 61993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @param expression a boolean expression 62993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @throws IllegalArgumentException if {@code expression} is false 63993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira */ 64993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira public static void checkArgument(boolean expression) { 65993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira if (!expression) { 66993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira throw new IllegalArgumentException(); 67993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 68993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 69993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 70993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira /** 71993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Ensures the truth of an expression involving one or more parameters to the 72993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * calling method. 73993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 74993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @param expression a boolean expression 75993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @param errorMessage the exception message to use if the check fails; will 76993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * be converted to a string using {@link String#valueOf(Object)} 77993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @throws IllegalArgumentException if {@code expression} is false 78993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira */ 79993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira public static void checkArgument(boolean expression, Object errorMessage) { 80993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira if (!expression) { 81993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira throw new IllegalArgumentException(String.valueOf(errorMessage)); 82993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 83993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 84993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 85993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira /** 86993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Ensures the truth of an expression involving one or more parameters to the 87993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * calling method. 88993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 89993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @param expression a boolean expression 90993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @param errorMessageTemplate a template for the exception message should the 91993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * check fail. The message is formed by replacing each {@code %s} 92993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * placeholder in the template with an argument. These are matched by 93993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * position - the first {@code %s} gets {@code errorMessageArgs[0]}, etc. 94993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Unmatched arguments will be appended to the formatted message in square 95993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * braces. Unmatched placeholders will be left as-is. 96993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @param errorMessageArgs the arguments to be substituted into the message 97993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * template. Arguments are converted to strings using 98993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * {@link String#valueOf(Object)}. 99993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @throws IllegalArgumentException if {@code expression} is false 100993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @throws NullPointerException if the check fails and either {@code 101993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * errorMessageTemplate} or {@code errorMessageArgs} is null (don't let 102993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * this happen) 103993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira */ 104993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira public static void checkArgument(boolean expression, 105993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira String errorMessageTemplate, Object... errorMessageArgs) { 106993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira if (!expression) { 107993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira throw new IllegalArgumentException( 108993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira format(errorMessageTemplate, errorMessageArgs)); 109993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 110993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 111993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 112993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira /** 113993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Ensures the truth of an expression involving the state of the calling 114993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * instance, but not involving any parameters to the calling method. 115993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 116993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @param expression a boolean expression 117993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @throws IllegalStateException if {@code expression} is false 118993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira */ 119993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira public static void checkState(boolean expression) { 120993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira if (!expression) { 121993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira throw new IllegalStateException(); 122993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 123993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 124993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 125993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira /** 126993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Ensures the truth of an expression involving the state of the calling 127993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * instance, but not involving any parameters to the calling method. 128993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 129993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @param expression a boolean expression 130993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @param errorMessage the exception message to use if the check fails; will 131993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * be converted to a string using {@link String#valueOf(Object)} 132993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @throws IllegalStateException if {@code expression} is false 133993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira */ 134993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira public static void checkState(boolean expression, Object errorMessage) { 135993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira if (!expression) { 136993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira throw new IllegalStateException(String.valueOf(errorMessage)); 137993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 138993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 139993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 140993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira /** 141993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Ensures the truth of an expression involving the state of the calling 142993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * instance, but not involving any parameters to the calling method. 143993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 144993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @param expression a boolean expression 145993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @param errorMessageTemplate a template for the exception message should the 146993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * check fail. The message is formed by replacing each {@code %s} 147993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * placeholder in the template with an argument. These are matched by 148993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * position - the first {@code %s} gets {@code errorMessageArgs[0]}, etc. 149993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Unmatched arguments will be appended to the formatted message in square 150993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * braces. Unmatched placeholders will be left as-is. 151993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @param errorMessageArgs the arguments to be substituted into the message 152993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * template. Arguments are converted to strings using 153993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * {@link String#valueOf(Object)}. 154993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @throws IllegalStateException if {@code expression} is false 155993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @throws NullPointerException if the check fails and either {@code 156993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * errorMessageTemplate} or {@code errorMessageArgs} is null (don't let 157993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * this happen) 158993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira */ 159993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira public static void checkState(boolean expression, 160993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira String errorMessageTemplate, Object... errorMessageArgs) { 161993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira if (!expression) { 162993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira throw new IllegalStateException( 163993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira format(errorMessageTemplate, errorMessageArgs)); 164993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 165993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 166993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 167993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira /** 168993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Ensures that an object reference passed as a parameter to the calling 169993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * method is not null. 170993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 171993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @param reference an object reference 172993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @return the non-null reference that was validated 173993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @throws NullPointerException if {@code reference} is null 174993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira */ 175993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira public static <T> T checkNotNull(T reference) { 176993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira if (reference == null) { 177993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira throw new NullPointerException(); 178993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 179993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return reference; 180993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 181993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 182993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira /** 183993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Ensures that an object reference passed as a parameter to the calling 184993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * method is not null. 185993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 186993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @param reference an object reference 187993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @param errorMessage the exception message to use if the check fails; will 188993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * be converted to a string using {@link String#valueOf(Object)} 189993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @return the non-null reference that was validated 190993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @throws NullPointerException if {@code reference} is null 191993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira */ 192993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira public static <T> T checkNotNull(T reference, Object errorMessage) { 193993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira if (reference == null) { 194993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira throw new NullPointerException(String.valueOf(errorMessage)); 195993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 196993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return reference; 197993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 198993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 199993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira /** 200993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Ensures that an object reference passed as a parameter to the calling 201993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * method is not null. 202993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 203993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @param reference an object reference 204993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @param errorMessageTemplate a template for the exception message should the 205993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * check fail. The message is formed by replacing each {@code %s} 206993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * placeholder in the template with an argument. These are matched by 207993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * position - the first {@code %s} gets {@code errorMessageArgs[0]}, etc. 208993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Unmatched arguments will be appended to the formatted message in square 209993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * braces. Unmatched placeholders will be left as-is. 210993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @param errorMessageArgs the arguments to be substituted into the message 211993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * template. Arguments are converted to strings using 212993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * {@link String#valueOf(Object)}. 213993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @return the non-null reference that was validated 214993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @throws NullPointerException if {@code reference} is null 215993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira */ 216993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira public static <T> T checkNotNull(T reference, String errorMessageTemplate, 217993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira Object... errorMessageArgs) { 218993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira if (reference == null) { 219993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira // If either of these parameters is null, the right thing happens anyway 220993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira throw new NullPointerException( 221993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira format(errorMessageTemplate, errorMessageArgs)); 222993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 223993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return reference; 224993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 225993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 226993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira /* 227993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * All recent hotspots (as of 2009) *really* like to have the natural code 228993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 229993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * if (guardExpression) { 230993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * throw new BadException(messageExpression); 231993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * } 232993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 233993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * refactored so that messageExpression is moved to a separate 234993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * String-returning method. 235993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 236993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * if (guardExpression) { 237993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * throw new BadException(badMsg(...)); 238993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * } 239993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 240993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * The alternative natural refactorings into void or Exception-returning 241993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * methods are much slower. This is a big deal - we're talking factors of 242993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 2-8 in microbenchmarks, not just 10-20%. (This is a hotspot optimizer 243993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * bug, which should be fixed, but that's a separate, big project). 244993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 245993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * The coding pattern above is heavily used in java.util, e.g. in ArrayList. 246993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * There is a RangeCheckMicroBenchmark in the JDK that was used to test this. 247993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 248993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * But the methods in this class want to throw different exceptions, 249993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * depending on the args, so it appears that this pattern is not directly 250993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * applicable. But we can use the ridiculous, devious trick of throwing an 251993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * exception in the middle of the construction of another exception. 252993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Hotspot is fine with that. 253993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira */ 254993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 255993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira /** 256993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Ensures that {@code index} specifies a valid <i>element</i> in an array, 257993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * list or string of size {@code size}. An element index may range from zero, 258993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * inclusive, to {@code size}, exclusive. 259993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 260993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @param index a user-supplied index identifying an element of an array, list 261993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * or string 262993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @param size the size of that array, list or string 263993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @return the value of {@code index} 264993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @throws IndexOutOfBoundsException if {@code index} is negative or is not 265993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * less than {@code size} 266993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @throws IllegalArgumentException if {@code size} is negative 267993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira */ 268993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira public static int checkElementIndex(int index, int size) { 269993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return checkElementIndex(index, size, "index"); 270993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 271993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 272993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira /** 273993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Ensures that {@code index} specifies a valid <i>element</i> in an array, 274993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * list or string of size {@code size}. An element index may range from zero, 275993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * inclusive, to {@code size}, exclusive. 276993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 277993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @param index a user-supplied index identifying an element of an array, list 278993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * or string 279993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @param size the size of that array, list or string 280993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @param desc the text to use to describe this index in an error message 281993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @return the value of {@code index} 282993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @throws IndexOutOfBoundsException if {@code index} is negative or is not 283993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * less than {@code size} 284993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @throws IllegalArgumentException if {@code size} is negative 285993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira */ 286993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira public static int checkElementIndex(int index, int size, String desc) { 287993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira // Carefully optimized for execution by hotspot (explanatory comment above) 288993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira if (index < 0 || index >= size) { 289993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira throw new IndexOutOfBoundsException(badElementIndex(index, size, desc)); 290993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 291993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return index; 292993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 293993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 294993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira private static String badElementIndex(int index, int size, String desc) { 295993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira if (index < 0) { 296993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return format("%s (%s) must not be negative", desc, index); 297993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } else if (size < 0) { 298993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira throw new IllegalArgumentException("negative size: " + size); 299993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } else { // index >= size 300993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return format("%s (%s) must be less than size (%s)", desc, index, size); 301993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 302993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 303993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 304993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira /** 305993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Ensures that {@code index} specifies a valid <i>position</i> in an array, 306993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * list or string of size {@code size}. A position index may range from zero 307993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * to {@code size}, inclusive. 308993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 309993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @param index a user-supplied index identifying a position in an array, list 310993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * or string 311993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @param size the size of that array, list or string 312993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @return the value of {@code index} 313993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @throws IndexOutOfBoundsException if {@code index} is negative or is 314993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * greater than {@code size} 315993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @throws IllegalArgumentException if {@code size} is negative 316993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira */ 317993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira public static int checkPositionIndex(int index, int size) { 318993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return checkPositionIndex(index, size, "index"); 319993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 320993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 321993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira /** 322993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Ensures that {@code index} specifies a valid <i>position</i> in an array, 323993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * list or string of size {@code size}. A position index may range from zero 324993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * to {@code size}, inclusive. 325993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 326993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @param index a user-supplied index identifying a position in an array, list 327993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * or string 328993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @param size the size of that array, list or string 329993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @param desc the text to use to describe this index in an error message 330993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @return the value of {@code index} 331993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @throws IndexOutOfBoundsException if {@code index} is negative or is 332993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * greater than {@code size} 333993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @throws IllegalArgumentException if {@code size} is negative 334993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira */ 335993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira public static int checkPositionIndex(int index, int size, String desc) { 336993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira // Carefully optimized for execution by hotspot (explanatory comment above) 337993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira if (index < 0 || index > size) { 338993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira throw new IndexOutOfBoundsException(badPositionIndex(index, size, desc)); 339993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 340993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return index; 341993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 342993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 343993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira private static String badPositionIndex(int index, int size, String desc) { 344993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira if (index < 0) { 345993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return format("%s (%s) must not be negative", desc, index); 346993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } else if (size < 0) { 347993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira throw new IllegalArgumentException("negative size: " + size); 348993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } else { // index > size 349993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return format("%s (%s) must not be greater than size (%s)", 350993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira desc, index, size); 351993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 352993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 353993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 354993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira /** 355993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Ensures that {@code start} and {@code end} specify a valid <i>positions</i> 356993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * in an array, list or string of size {@code size}, and are in order. A 357993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * position index may range from zero to {@code size}, inclusive. 358993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 359993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @param start a user-supplied index identifying a starting position in an 360993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * array, list or string 361993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @param end a user-supplied index identifying a ending position in an array, 362993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * list or string 363993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @param size the size of that array, list or string 364993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @throws IndexOutOfBoundsException if either index is negative or is 365993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * greater than {@code size}, or if {@code end} is less than {@code start} 366993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @throws IllegalArgumentException if {@code size} is negative 367993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira */ 368993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira public static void checkPositionIndexes(int start, int end, int size) { 369993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira // Carefully optimized for execution by hotspot (explanatory comment above) 370993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira if (start < 0 || end < start || end > size) { 371993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira throw new IndexOutOfBoundsException(badPositionIndexes(start, end, size)); 372993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 373993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 374993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 375993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira private static String badPositionIndexes(int start, int end, int size) { 376993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira if (start < 0 || start > size) { 377993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return badPositionIndex(start, size, "start index"); 378993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 379993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira if (end < 0 || end > size) { 380993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return badPositionIndex(end, size, "end index"); 381993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 382993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira // end < start 383993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return format("end index (%s) must not be less than start index (%s)", 384993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira end, start); 385993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 386993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 387993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira /** 388993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Substitutes each {@code %s} in {@code template} with an argument. These 389993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * are matched by position - the first {@code %s} gets {@code args[0]}, etc. 390993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * If there are more arguments than placeholders, the unmatched arguments will 391993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * be appended to the end of the formatted message in square braces. 392993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * 393993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @param template a non-null string containing 0 or more {@code %s} 394993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * placeholders. 395993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @param args the arguments to be substituted into the message 396993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * template. Arguments are converted to strings using 397993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * {@link String#valueOf(Object)}. Arguments can be null. 398993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira */ 399993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira static String format(String template, Object... args) { 400993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira // start substituting the arguments into the '%s' placeholders 401993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira StringBuilder builder = new StringBuilder( 402993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira template.length() + 16 * args.length); 403993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira int templateStart = 0; 404993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira int i = 0; 405993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira while (i < args.length) { 406993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira int placeholderStart = template.indexOf("%s", templateStart); 407993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira if (placeholderStart == -1) { 408993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira break; 409993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 410993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira builder.append(template.substring(templateStart, placeholderStart)); 411993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira builder.append(args[i++]); 412993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira templateStart = placeholderStart + 2; 413993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 414993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira builder.append(template.substring(templateStart)); 415993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 416993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira // if we run out of placeholders, append the extra args in square braces 417993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira if (i < args.length) { 418993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira builder.append(" ["); 419993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira builder.append(args[i++]); 420993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira while (i < args.length) { 421993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira builder.append(", "); 422993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira builder.append(args[i++]); 423993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 424993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira builder.append("]"); 425993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 426993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira 427993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira return builder.toString(); 428993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira } 429993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira} 430