001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018 019 package org.apache.commons.beanutils.converters; 020 021 022 import java.io.IOException; 023 import java.io.StreamTokenizer; 024 import java.io.StringReader; 025 import java.util.ArrayList; 026 import java.util.List; 027 import org.apache.commons.beanutils.ConversionException; 028 import org.apache.commons.beanutils.Converter; 029 030 031 032 /** 033 * <p>Convenience base class for converters that translate the String 034 * representation of an array into a corresponding array of primitives 035 * object. This class encapsulates the functionality required to parse 036 * the String into a list of String elements that can later be 037 * individually converted to the appropriate primitive type.</p> 038 * 039 * <p>The input syntax accepted by the <code>parseElements()</code> method 040 * is designed to be compatible with the syntax used to initialize arrays 041 * in a Java source program, except that only String literal values are 042 * supported. For maximum flexibility, the surrounding '{' and '}' 043 * characters are optional, and individual elements may be separated by 044 * any combination of whitespace and comma characters.</p> 045 * 046 * @author Craig R. McClanahan 047 * @version $Revision: 557808 $ $Date: 2007-07-20 00:05:03 +0100 (Fri, 20 Jul 2007) $ 048 * @since 1.4 049 * @deprecated Replaced by the new {@link ArrayConverter} implementation 050 */ 051 052 public abstract class AbstractArrayConverter implements Converter { 053 054 055 // ----------------------------------------------------------- Constructors 056 057 058 /** 059 * Create a {@link Converter} that will throw a {@link ConversionException} 060 * if a conversion error occurs. 061 */ 062 public AbstractArrayConverter() { 063 064 this.defaultValue = null; 065 this.useDefault = false; 066 067 } 068 069 /** 070 * Create a {@link Converter} that will return the specified default value 071 * if a conversion error occurs. 072 * 073 * @param defaultValue The default value to be returned 074 */ 075 public AbstractArrayConverter(Object defaultValue) { 076 077 if (defaultValue == NO_DEFAULT) { 078 this.useDefault = false; 079 } else { 080 this.defaultValue = defaultValue; 081 this.useDefault = true; 082 } 083 084 } 085 086 // ------------------------------------------------------- Static Variables 087 088 /** 089 * This is a special reference that can be passed as the "default object" 090 * to the constructor to indicate that no default is desired. Note that 091 * the value 'null' cannot be used for this purpose, as the caller may 092 * want a null to be returned as the default. 093 */ 094 public static final Object NO_DEFAULT = new Object(); 095 096 // ----------------------------------------------------- Instance Variables 097 098 099 /** 100 * <p>Model object for string arrays.</p> 101 */ 102 protected static String[] strings = new String[0]; 103 104 105 /** 106 * The default value specified to our Constructor, if any. 107 */ 108 protected Object defaultValue = null; 109 110 111 /** 112 * Should we return the default value on conversion errors? 113 */ 114 protected boolean useDefault = true; 115 116 117 // --------------------------------------------------------- Public Methods 118 119 120 /** 121 * Convert the specified input object into an output object of the 122 * specified type. This method must be implemented by a concrete 123 * subclass. 124 * 125 * @param type Data type to which this value should be converted 126 * @param value The input value to be converted 127 * @return The converted value 128 * 129 * @exception ConversionException if conversion cannot be performed 130 * successfully 131 */ 132 public abstract Object convert(Class type, Object value); 133 134 135 // ------------------------------------------------------ Protected Methods 136 137 138 /** 139 * <p>Parse an incoming String of the form similar to an array initializer 140 * in the Java language into a <code>List</code> individual Strings 141 * for each element, according to the following rules.</p> 142 * <ul> 143 * <li>The string is expected to be a comma-separated list of values.</li> 144 * <li>The string may optionally have matching '{' and '}' delimiters 145 * around the list.</li> 146 * <li>Whitespace before and after each element is stripped.</li> 147 * <li>Elements in the list may be delimited by single or double quotes. 148 * Within a quoted elements, the normal Java escape sequences are valid.</li> 149 * </ul> 150 * 151 * @param svalue String value to be parsed 152 * @return The parsed list of String values 153 * 154 * @exception ConversionException if the syntax of <code>svalue</code> 155 * is not syntactically valid 156 * @exception NullPointerException if <code>svalue</code> 157 * is <code>null</code> 158 */ 159 protected List parseElements(String svalue) { 160 161 // Validate the passed argument 162 if (svalue == null) { 163 throw new NullPointerException(); 164 } 165 166 // Trim any matching '{' and '}' delimiters 167 svalue = svalue.trim(); 168 if (svalue.startsWith("{") && svalue.endsWith("}")) { 169 svalue = svalue.substring(1, svalue.length() - 1); 170 } 171 172 try { 173 174 // Set up a StreamTokenizer on the characters in this String 175 StreamTokenizer st = 176 new StreamTokenizer(new StringReader(svalue)); 177 st.whitespaceChars(',',','); // Commas are delimiters 178 st.ordinaryChars('0', '9'); // Needed to turn off numeric flag 179 st.ordinaryChars('.', '.'); 180 st.ordinaryChars('-', '-'); 181 st.wordChars('0', '9'); // Needed to make part of tokens 182 st.wordChars('.', '.'); 183 st.wordChars('-', '-'); 184 185 // Split comma-delimited tokens into a List 186 ArrayList list = new ArrayList(); 187 while (true) { 188 int ttype = st.nextToken(); 189 if ((ttype == StreamTokenizer.TT_WORD) || 190 (ttype > 0)) { 191 list.add(st.sval); 192 } else if (ttype == StreamTokenizer.TT_EOF) { 193 break; 194 } else { 195 throw new ConversionException 196 ("Encountered token of type " + ttype); 197 } 198 } 199 200 // Return the completed list 201 return (list); 202 203 } catch (IOException e) { 204 205 throw new ConversionException(e); 206 207 } 208 209 210 211 } 212 213 214 }