1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
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;
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 }