1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.betwixt;
18
19 import java.util.Collection;
20 import java.util.Enumeration;
21 import java.util.Iterator;
22 import java.util.Map;
23
24 import org.apache.commons.betwixt.strategy.ClassNormalizer;
25 import org.apache.commons.betwixt.strategy.DefaultNameMapper;
26 import org.apache.commons.betwixt.strategy.DefaultPluralStemmer;
27 import org.apache.commons.betwixt.strategy.MappingDerivationStrategy;
28 import org.apache.commons.betwixt.strategy.NameMapper;
29 import org.apache.commons.betwixt.strategy.NamespacePrefixMapper;
30 import org.apache.commons.betwixt.strategy.PluralStemmer;
31 import org.apache.commons.betwixt.strategy.PropertySuppressionStrategy;
32 import org.apache.commons.betwixt.strategy.SimpleTypeMapper;
33 import org.apache.commons.betwixt.strategy.StandardSimpleTypeMapper;
34 import org.apache.commons.betwixt.strategy.TypeBindingStrategy;
35 import org.apache.commons.logging.Log;
36 import org.apache.commons.logging.LogFactory;
37
38 /***
39 * <p>Stores introspection phase binding configuration.</p>
40 * <p>
41 * There are two phase in Betwixt's processing.
42 * The first phase is the introspection of the bean.
43 * Strutural configuration settings effect this phase.
44 * The second phase comes when Betwixt dynamically uses reflection
45 * to execute the mapping.
46 * This object stores configuration settings pertaining to the first phase.
47 * </p>
48 * <p>
49 * These common settings have been collected into one class so that they can
50 * be more easily shared not only between the objects that execute the introspection
51 * but also (by a user) between different <code>XMLIntrospector</code>s.
52 * </p>
53 * @author <a href='http://jakarta.apache.org/'>Jakarta Commons Team</a>
54 * @version $Revision: 190515 $
55 */
56 public class IntrospectionConfiguration {
57
58 /*** should attributes or elements be used for primitive types */
59 private boolean attributesForPrimitives = false;
60
61 /*** should we wrap collections in an extra element? */
62 private boolean wrapCollectionsInElement = true;
63
64 /*** Should the existing bean info search path for java.reflect.Introspector be used? */
65 private boolean useBeanInfoSearchPath = false;
66
67
68 /*** The strategy used to detect matching singular and plural properties */
69 private PluralStemmer pluralStemmer;
70
71 /*** The strategy used to convert bean type names into element names */
72 private NameMapper elementNameMapper;
73
74 /*** Strategy normalizes the Class of the Object before introspection */
75 private ClassNormalizer classNormalizer = new ClassNormalizer();
76
77 /*** Log for introspection messages */
78 private Log introspectionLog = LogFactory.getLog(XMLIntrospector.class);
79
80 /***
81 * The strategy used to convert bean type names into attribute names
82 * It will default to the normal nameMapper.
83 */
84 private NameMapper attributeNameMapper;
85
86 /*** Prefix naming strategy */
87 private NamespacePrefixMapper prefixMapper = new NamespacePrefixMapper();
88 /*** Mapping strategy for simple types */
89 private SimpleTypeMapper simpleTypeMapper = new StandardSimpleTypeMapper();
90 /*** Binding strategy for Java type */
91 private TypeBindingStrategy typeBindingStrategy = TypeBindingStrategy.DEFAULT;
92
93
94 /***
95 * Strategy used to determine whether the bind or introspection time type is to be used to
96 * determine the mapping.
97 */
98 private MappingDerivationStrategy mappingDerivationStrategy = MappingDerivationStrategy.DEFAULT;
99
100 /***
101 * Strategy used to determine which properties should be ignored
102 */
103 private PropertySuppressionStrategy propertySuppressionStrategy = PropertySuppressionStrategy.DEFAULT;
104
105 /***
106 * Gets the <code>ClassNormalizer</code> strategy.
107 * This is used to determine the Class to be introspected
108 * (the normalized Class).
109 *
110 * @return the <code>ClassNormalizer</code> used to determine the Class to be introspected
111 * for a given Object.
112 */
113 public ClassNormalizer getClassNormalizer() {
114 return classNormalizer;
115 }
116
117 /***
118 * Sets the <code>ClassNormalizer</code> strategy.
119 * This is used to determine the Class to be introspected
120 * (the normalized Class).
121 *
122 * @param classNormalizer the <code>ClassNormalizer</code> to be used to determine
123 * the Class to be introspected for a given Object.
124 */
125 public void setClassNormalizer(ClassNormalizer classNormalizer) {
126 this.classNormalizer = classNormalizer;
127 }
128
129 /***
130 * Should attributes (or elements) be used for primitive types.
131 * @return true if primitive types will be mapped to attributes in the introspection
132 */
133 public boolean isAttributesForPrimitives() {
134 return attributesForPrimitives;
135 }
136
137 /***
138 * Set whether attributes (or elements) should be used for primitive types.
139 * @param attributesForPrimitives pass trus to map primitives to attributes,
140 * pass false to map primitives to elements
141 */
142 public void setAttributesForPrimitives(boolean attributesForPrimitives) {
143 this.attributesForPrimitives = attributesForPrimitives;
144 }
145
146 /***
147 * Should collections be wrapped in an extra element?
148 *
149 * @return whether we should we wrap collections in an extra element?
150 */
151 public boolean isWrapCollectionsInElement() {
152 return wrapCollectionsInElement;
153 }
154
155 /***
156 * Sets whether we should we wrap collections in an extra element.
157 *
158 * @param wrapCollectionsInElement pass true if collections should be wrapped in a
159 * parent element
160 */
161 public void setWrapCollectionsInElement(boolean wrapCollectionsInElement) {
162 this.wrapCollectionsInElement = wrapCollectionsInElement;
163 }
164
165 /***
166 * Get singular and plural matching strategy.
167 *
168 * @return the strategy used to detect matching singular and plural properties
169 */
170 public PluralStemmer getPluralStemmer() {
171 if ( pluralStemmer == null ) {
172 pluralStemmer = createPluralStemmer();
173 }
174 return pluralStemmer;
175 }
176
177 /***
178 * Sets the strategy used to detect matching singular and plural properties
179 *
180 * @param pluralStemmer the PluralStemmer used to match singular and plural
181 */
182 public void setPluralStemmer(PluralStemmer pluralStemmer) {
183 this.pluralStemmer = pluralStemmer;
184 }
185
186 /***
187 * Gets the name mapping strategy used to convert bean names into elements.
188 *
189 * @return the strategy used to convert bean type names into element
190 * names. If no element mapper is currently defined then a default one is created.
191 */
192 public NameMapper getElementNameMapper() {
193 if ( elementNameMapper == null ) {
194 elementNameMapper = createNameMapper();
195 }
196 return elementNameMapper;
197 }
198
199 /***
200 * Sets the strategy used to convert bean type names into element names
201 * @param nameMapper the NameMapper to use for the conversion
202 */
203 public void setElementNameMapper(NameMapper nameMapper) {
204 this.elementNameMapper = nameMapper;
205 }
206
207 /***
208 * Gets the name mapping strategy used to convert bean names into attributes.
209 *
210 * @return the strategy used to convert bean type names into attribute
211 * names. If no attributeNamemapper is known, it will default to the ElementNameMapper
212 */
213 public NameMapper getAttributeNameMapper() {
214 if (attributeNameMapper == null) {
215 attributeNameMapper = createNameMapper();
216 }
217 return attributeNameMapper;
218 }
219
220
221 /***
222 * Sets the strategy used to convert bean type names into attribute names
223 * @param nameMapper the NameMapper to use for the convertion
224 */
225 public void setAttributeNameMapper(NameMapper nameMapper) {
226 this.attributeNameMapper = nameMapper;
227 }
228
229 /***
230 * <p>Should the original <code>java.reflect.Introspector</code> bean info search path be used?</p>
231 * <p>
232 * Default is false.
233 * </p>
234 *
235 * @return boolean if the beanInfoSearchPath should be used.
236 */
237 public boolean useBeanInfoSearchPath() {
238 return useBeanInfoSearchPath;
239 }
240
241 /***
242 * Specifies if you want to use the beanInfoSearchPath
243 * @see java.beans.Introspector for more details
244 * @param useBeanInfoSearchPath
245 */
246 public void setUseBeanInfoSearchPath(boolean useBeanInfoSearchPath) {
247 this.useBeanInfoSearchPath = useBeanInfoSearchPath;
248 }
249
250 /***
251 * A Factory method to lazily create a new strategy
252 * to detect matching singular and plural properties.
253 *
254 * @return new defualt PluralStemmer implementation
255 */
256 protected PluralStemmer createPluralStemmer() {
257 return new DefaultPluralStemmer();
258 }
259
260 /***
261 * A Factory method to lazily create a strategy
262 * used to convert bean type names into element names.
263 *
264 * @return new default NameMapper implementation
265 */
266 protected NameMapper createNameMapper() {
267 return new DefaultNameMapper();
268 }
269
270 /***
271 * Gets the common Log used for introspection.
272 * It is more convenient to use a single Log
273 * that can be easily configured.
274 * @return Log, not null
275 */
276 public Log getIntrospectionLog() {
277 return introspectionLog;
278 }
279
280 /***
281 * Sets the common Log used by introspection.
282 * It is more convenient to use a single Log
283 * that can be easily configured.
284 * @param log Log, not null
285 */
286 public void setIntrospectionLog(Log log) {
287 introspectionLog = log;
288 }
289
290
291 /***
292 * Gets the <code>NamespacePrefixMapper</code> used to convert namespace URIs
293 * into prefixes.
294 * @return NamespacePrefixMapper, not null
295 */
296 public NamespacePrefixMapper getPrefixMapper() {
297 return prefixMapper;
298 }
299
300 /***
301 * Sets the <code>NamespacePrefixMapper</code> used to convert namespave URIs
302 * into prefixes.
303 * @param mapper NamespacePrefixMapper, not null
304 */
305 public void setPrefixMapper(NamespacePrefixMapper mapper) {
306 prefixMapper = mapper;
307 }
308
309
310 /***
311 * Gets the simple type binding strategy.
312 * @return SimpleTypeMapper, not null
313 */
314 public SimpleTypeMapper getSimpleTypeMapper() {
315 return simpleTypeMapper;
316 }
317
318 /***
319 * Sets the simple type binding strategy.
320 * @param mapper SimpleTypeMapper, not null
321 */
322 public void setSimpleTypeMapper(SimpleTypeMapper mapper) {
323 simpleTypeMapper = mapper;
324 }
325
326 /***
327 * Gets the <code>TypeBindingStrategy</code> to be used
328 * to determine the binding for Java types.
329 * @return the <code>TypeBindingStrategy</code> to be used,
330 * not null
331 */
332 public TypeBindingStrategy getTypeBindingStrategy() {
333 return typeBindingStrategy;
334 }
335
336 /***
337 * Sets the <code>TypeBindingStrategy</code> to be used
338 * to determine the binding for Java types.
339 * @param typeBindingStrategy the <code>TypeBindingStrategy</code> to be used,
340 * not null
341 */
342 public void setTypeBindingStrategy(TypeBindingStrategy typeBindingStrategy) {
343 this.typeBindingStrategy = typeBindingStrategy;
344 }
345
346
347 /***
348 * Gets the <code>MappingDerivationStrategy</code>
349 * used to determine whether the bind or introspection time
350 * type should determine the mapping.
351 * @since 0.7
352 * @return <code>MappingDerivationStrategy</code>, not null
353 */
354 public MappingDerivationStrategy getMappingDerivationStrategy() {
355 return mappingDerivationStrategy;
356 }
357 /***
358 * Sets the <code>MappingDerivationStrategy</code>
359 * used to determine whether the bind or introspection time
360 * type should determine the mapping.
361 * @since 0.7
362 * @param mappingDerivationStrategy <code>MappingDerivationStrategy</code>, not null
363 */
364 public void setMappingDerivationStrategy(
365 MappingDerivationStrategy mappingDerivationStrategy) {
366 this.mappingDerivationStrategy = mappingDerivationStrategy;
367 }
368
369 /***
370 * Gets the strategy which determines the properties to be ignored.
371 * @since 0.7
372 * @return the <code>PropertySuppressionStrategy</code> to be used for introspection, not null
373 */
374 public PropertySuppressionStrategy getPropertySuppressionStrategy() {
375 return propertySuppressionStrategy;
376 }
377
378 /***
379 * Sets the strategy which determines the properties to be ignored.
380 * @since 0.7
381 * @param propertySuppressionStrategy the <code>PropertySuppressionStrategy</code> to be used for introspection, not null
382 */
383 public void setPropertySuppressionStrategy(
384 PropertySuppressionStrategy propertySuppressionStrategy) {
385 this.propertySuppressionStrategy = propertySuppressionStrategy;
386 }
387
388 /***
389 * Is this a loop type class?
390 * @since 0.7
391 * @param type is this <code>Class</code> a loop type?
392 * @return true if the type is a loop type, or if type is null
393 */
394 public boolean isLoopType(Class type) {
395
396
397 if (type == null) {
398 return false;
399 }
400 return type.isArray()
401 || Map.class.isAssignableFrom( type )
402 || Collection.class.isAssignableFrom( type )
403 || Enumeration.class.isAssignableFrom( type )
404 || Iterator.class.isAssignableFrom( type )
405 || Map.Entry.class.isAssignableFrom( type ) ;
406 }
407 }