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   * @version $Id$
47   * @since 1.4
48   * @deprecated Replaced by the new {@link ArrayConverter} implementation
49   */
50  
51  @Deprecated
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       * @since 1.8.0
75       */
76      public AbstractArrayConverter(final Object defaultValue) {
77  
78          if (defaultValue == NO_DEFAULT) {
79              this.useDefault = false;
80          } else {
81              this.defaultValue = defaultValue;
82              this.useDefault = true;
83          }
84  
85      }
86  
87      // ------------------------------------------------------- Static Variables
88  
89      /**
90       * This is a special reference that can be passed as the "default object"
91       * to the constructor to indicate that no default is desired. Note that
92       * the value 'null' cannot be used for this purpose, as the caller may
93       * want a null to be returned as the default.
94       * @since 1.8.0
95       */
96      public static final Object NO_DEFAULT = new Object();
97  
98      // ----------------------------------------------------- Instance Variables
99  
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 }