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 019package org.apache.commons.beanutils.converters; 020 021 022import java.io.IOException; 023import java.io.StreamTokenizer; 024import java.io.StringReader; 025import java.util.ArrayList; 026import java.util.List; 027import org.apache.commons.beanutils.ConversionException; 028import 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 * @version $Id$ 047 * @since 1.4 048 * @deprecated Replaced by the new {@link ArrayConverter} implementation 049 */ 050 051@Deprecated 052public 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 * @since 1.8.0 075 */ 076 public AbstractArrayConverter(final Object defaultValue) { 077 078 if (defaultValue == NO_DEFAULT) { 079 this.useDefault = false; 080 } else { 081 this.defaultValue = defaultValue; 082 this.useDefault = true; 083 } 084 085 } 086 087 // ------------------------------------------------------- Static Variables 088 089 /** 090 * This is a special reference that can be passed as the "default object" 091 * to the constructor to indicate that no default is desired. Note that 092 * the value 'null' cannot be used for this purpose, as the caller may 093 * want a null to be returned as the default. 094 * @since 1.8.0 095 */ 096 public static final Object NO_DEFAULT = new Object(); 097 098 // ----------------------------------------------------- Instance Variables 099 100 101 /** 102 * <p>Model object for string arrays.</p> 103 */ 104 protected static String[] strings = new String[0]; 105 106 107 /** 108 * The default value specified to our Constructor, if any. 109 */ 110 protected Object defaultValue = null; 111 112 113 /** 114 * Should we return the default value on conversion errors? 115 */ 116 protected boolean useDefault = true; 117 118 119 // --------------------------------------------------------- Public Methods 120 121 122 /** 123 * Convert the specified input object into an output object of the 124 * specified type. This method must be implemented by a concrete 125 * subclass. 126 * 127 * @param type Data type to which this value should be converted 128 * @param value The input value to be converted 129 * @return The converted value 130 * 131 * @throws ConversionException if conversion cannot be performed 132 * successfully 133 */ 134 public abstract Object convert(Class type, Object value); 135 136 137 // ------------------------------------------------------ Protected Methods 138 139 140 /** 141 * <p>Parse an incoming String of the form similar to an array initializer 142 * in the Java language into a <code>List</code> individual Strings 143 * for each element, according to the following rules.</p> 144 * <ul> 145 * <li>The string is expected to be a comma-separated list of values.</li> 146 * <li>The string may optionally have matching '{' and '}' delimiters 147 * around the list.</li> 148 * <li>Whitespace before and after each element is stripped.</li> 149 * <li>Elements in the list may be delimited by single or double quotes. 150 * Within a quoted elements, the normal Java escape sequences are valid.</li> 151 * </ul> 152 * 153 * @param svalue String value to be parsed 154 * @return The parsed list of String values 155 * 156 * @throws ConversionException if the syntax of <code>svalue</code> 157 * is not syntactically valid 158 * @throws NullPointerException if <code>svalue</code> 159 * is <code>null</code> 160 */ 161 protected List parseElements(String svalue) { 162 163 // Validate the passed argument 164 if (svalue == null) { 165 throw new NullPointerException(); 166 } 167 168 // Trim any matching '{' and '}' delimiters 169 svalue = svalue.trim(); 170 if (svalue.startsWith("{") && svalue.endsWith("}")) { 171 svalue = svalue.substring(1, svalue.length() - 1); 172 } 173 174 try { 175 176 // Set up a StreamTokenizer on the characters in this String 177 final StreamTokenizer st = 178 new StreamTokenizer(new StringReader(svalue)); 179 st.whitespaceChars(',',','); // Commas are delimiters 180 st.ordinaryChars('0', '9'); // Needed to turn off numeric flag 181 st.ordinaryChars('.', '.'); 182 st.ordinaryChars('-', '-'); 183 st.wordChars('0', '9'); // Needed to make part of tokens 184 st.wordChars('.', '.'); 185 st.wordChars('-', '-'); 186 187 // Split comma-delimited tokens into a List 188 final ArrayList list = new ArrayList(); 189 while (true) { 190 final int ttype = st.nextToken(); 191 if ((ttype == StreamTokenizer.TT_WORD) || 192 (ttype > 0)) { 193 list.add(st.sval); 194 } else if (ttype == StreamTokenizer.TT_EOF) { 195 break; 196 } else { 197 throw new ConversionException 198 ("Encountered token of type " + ttype); 199 } 200 } 201 202 // Return the completed list 203 return (list); 204 205 } catch (final IOException e) { 206 207 throw new ConversionException(e); 208 209 } 210 211 212 213 } 214 215 216}