View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  
19  package org.apache.commons.beanutils.converters;
20  
21  
22  import java.io.IOException;
23  import java.io.StreamTokenizer;
24  import java.io.StringReader;
25  import java.util.ArrayList;
26  import java.util.List;
27  import org.apache.commons.beanutils.ConversionException;
28  import org.apache.commons.beanutils.Converter;
29  
30  
31  
32  /***
33   * <p>Convenience base class for converters that translate the String
34   * representation of an array into a corresponding array of primitives
35   * object.  This class encapsulates the functionality required to parse
36   * the String into a list of String elements that can later be
37   * individually converted to the appropriate primitive type.</p>
38   *
39   * <p>The input syntax accepted by the <code>parseElements()</code> method
40   * is designed to be compatible with the syntax used to initialize arrays
41   * in a Java source program, except that only String literal values are
42   * supported.  For maximum flexibility, the surrounding '{' and '}'
43   * characters are optional, and individual elements may be separated by
44   * any combination of whitespace and comma characters.</p>
45   *
46   * @author Craig R. McClanahan
47   * @version $Revision: 557808 $ $Date: 2007-07-20 00:05:03 +0100 (Fri, 20 Jul 2007) $
48   * @since 1.4
49   * @deprecated Replaced by the new {@link ArrayConverter} implementation
50   */
51  
52  public abstract class AbstractArrayConverter implements Converter {
53  
54  
55      // ----------------------------------------------------------- Constructors
56  
57  
58      /***
59       * Create a {@link Converter} that will throw a {@link ConversionException}
60       * if a conversion error occurs.
61       */
62      public AbstractArrayConverter() {
63  
64          this.defaultValue = null;
65          this.useDefault = false;
66  
67      }
68  
69      /***
70       * Create a {@link Converter} that will return the specified default value
71       * if a conversion error occurs.
72       *
73       * @param defaultValue The default value to be returned
74       */
75      public AbstractArrayConverter(Object defaultValue) {
76  
77          if (defaultValue == NO_DEFAULT) {
78              this.useDefault = false;
79          } else {
80              this.defaultValue = defaultValue;
81              this.useDefault = true;
82          }
83  
84      }
85  
86      // ------------------------------------------------------- Static Variables
87  
88      /***
89       * This is a special reference that can be passed as the "default object"
90       * to the constructor to indicate that no default is desired. Note that
91       * the value 'null' cannot be used for this purpose, as the caller may
92       * want a null to be returned as the default.
93       */
94      public static final Object NO_DEFAULT = new Object();
95  
96      // ----------------------------------------------------- Instance Variables
97  
98  
99      /***
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 }