View Javadoc

1   /*
2    * Copyright 2004-2005, 2007-2008 the original author or authors.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5    * use this file except in compliance with the License. You may obtain a copy of
6    * the License at
7    * 
8    * http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations under
14   * the License.
15   */
16  package net.sf.morph.transform.converters;
17  
18  import java.lang.reflect.Array;
19  import java.util.HashMap;
20  import java.util.Locale;
21  import java.util.Map;
22  
23  import net.sf.morph.Defaults;
24  import net.sf.morph.transform.Converter;
25  import net.sf.morph.transform.DecoratedConverter;
26  import net.sf.morph.transform.transformers.BaseTransformer;
27  import net.sf.morph.util.StringUtils;
28  
29  /**
30   * Converts a basic text type ({@link java.lang.String} or
31   * {@link java.lang.StringBuffer}) into a {@link java.lang.Class}.  Array types
32   * are supported, by appending <code>[]</code> to the end of the contained
33   * class name.  If <code>[]</code> is appended <i>n</i> times, the returned
34   * class will be <i>n</i>-dimensional.
35   * 
36   * @author Matt Sgarlata
37   * @since Jan 2, 2005
38   */
39  public class TextToClassConverter extends BaseTransformer implements Converter, DecoratedConverter {
40  	/** Array indicator */
41  	public static final String ARRAY_INDICATOR = "[]";
42  
43  	private static final HashMap CACHE_MAP = new HashMap();
44  	private static final Class[] DESTINATION_TYPES = { Class.class };
45  
46  	//one default instance:
47  	private static final Converter DEFAULT_TEXT_CONVERTER = Defaults.createTextConverter();
48  
49  	private Converter textConverter;
50  	private boolean useCache = true;
51  
52  	/**
53  	 * {@inheritDoc}
54  	 */
55  	protected Object convertImpl(Class destinationClass, Object source,
56  		Locale locale) throws Exception {
57  		String string = StringUtils.removeWhitespace((String) getTextConverter().convert(
58  				String.class, source, locale));
59  		Class result;
60  		Map cache = useCache ? getCache() : null;
61  		Object lock = useCache ? (Object) cache : string; //trick to synch on optional cache w/o duplicating code
62  		synchronized (lock) {
63  			result = useCache ? (Class) cache.get(string) : null;
64  			if (result == null) {
65  				int arrayAt = string.indexOf(ARRAY_INDICATOR);
66  				Class c = Class.forName(arrayAt < 0 ? string : string.substring(0, arrayAt));
67  				result = arrayAt < 0 ? c : Array.newInstance(c,
68  						new int[StringUtils.numOccurrences(string, ARRAY_INDICATOR)])
69  						.getClass();
70  				if (useCache) {
71  					cache.put(string, result);
72  				}
73  			}
74  		}
75  		return result;
76  	}
77  
78  	/**
79  	 * {@inheritDoc}
80  	 */
81  	protected Class[] getDestinationClassesImpl() throws Exception {
82  		return DESTINATION_TYPES;
83  	}
84  
85  	/**
86  	 * {@inheritDoc}
87  	 */
88  	protected Class[] getSourceClassesImpl() throws Exception {
89  		return getTextConverter().getSourceClasses();
90  	}
91  
92  	/**
93  	 * Get the text converter used by this TextToClassConverter.
94  	 * @return Converter
95  	 */
96  	public Converter getTextConverter() {
97  		if (textConverter == null) {
98  			setTextConverter(DEFAULT_TEXT_CONVERTER);
99  		}
100 		return textConverter;
101 	}
102 
103 	/**
104 	 * Set the text converter used by this TextToClassConverter.
105 	 * @param textConverter
106 	 */
107 	public void setTextConverter(Converter textConverter) {
108 		this.textConverter = textConverter;
109 	}
110 
111 	/**
112 	 * Get the useCache of this TextToClassConverter.
113 	 * @return the useCache
114 	 */
115 	public boolean isUseCache() {
116 		return useCache;
117 	}
118 
119 	/**
120 	 * Set the useCache of this TextToClassConverter.
121 	 * @param useCache the useCache to set
122 	 */
123 	public void setUseCache(boolean useCache) {
124 		this.useCache = useCache;
125 	}
126 
127 	/**
128 	 * Get the cache map associated with the operative text converter.
129 	 * @return Map
130 	 */
131 	private Map getCache() {
132 		Map result;
133 		synchronized (CACHE_MAP) {
134 			Converter cnv = getTextConverter();
135 			result = (Map) CACHE_MAP.get(cnv);
136 			if (result == null) {
137 				result = new HashMap();
138 				CACHE_MAP.put(cnv, result);
139 			}
140 		}
141 		return result;
142 	}
143 
144 	/**
145 	 * {@inheritDoc}
146 	 */
147 	protected boolean isWrappingRuntimeExceptions() {
148 	    return true;
149     }
150 
151 }