001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018 package org.apache.commons.betwixt; 019 020 import org.apache.commons.betwixt.strategy.AttributeSuppressionStrategy; 021 import org.apache.commons.betwixt.strategy.ClassNormalizer; 022 import org.apache.commons.betwixt.strategy.CollectiveTypeStrategy; 023 import org.apache.commons.betwixt.strategy.DefaultNameMapper; 024 import org.apache.commons.betwixt.strategy.DefaultPluralStemmer; 025 import org.apache.commons.betwixt.strategy.ElementSuppressionStrategy; 026 import org.apache.commons.betwixt.strategy.MappingDerivationStrategy; 027 import org.apache.commons.betwixt.strategy.NameMapper; 028 import org.apache.commons.betwixt.strategy.NamespacePrefixMapper; 029 import org.apache.commons.betwixt.strategy.PluralStemmer; 030 import org.apache.commons.betwixt.strategy.PropertySuppressionStrategy; 031 import org.apache.commons.betwixt.strategy.SimpleTypeMapper; 032 import org.apache.commons.betwixt.strategy.StandardSimpleTypeMapper; 033 import org.apache.commons.betwixt.strategy.TypeBindingStrategy; 034 import org.apache.commons.logging.Log; 035 import org.apache.commons.logging.LogFactory; 036 037 /** 038 * <p>Stores introspection phase binding configuration.</p> 039 * <p> 040 * There are two phase in Betwixt's processing. 041 * The first phase is the introspection of the bean. 042 * Strutural configuration settings effect this phase. 043 * The second phase comes when Betwixt dynamically uses reflection 044 * to execute the mapping. 045 * This object stores configuration settings pertaining to the first phase. 046 * </p> 047 * <p> 048 * These common settings have been collected into one class so that they can 049 * be more easily shared not only between the objects that execute the introspection 050 * but also (by a user) between different <code>XMLIntrospector</code>s. 051 * </p> 052 * @author <a href='http://commons.apache.org/'>Apache Commons Team</a> 053 * @version $Revision: 561314 $ 054 */ 055 public class IntrospectionConfiguration { 056 057 /** should attributes or elements be used for primitive types */ 058 private boolean attributesForPrimitives = false; 059 060 /** should we wrap collections in an extra element? */ 061 private boolean wrapCollectionsInElement = true; 062 063 /** Should the existing bean info search path for java.reflect.Introspector be used? */ 064 private boolean useBeanInfoSearchPath = false; 065 066 /** Should existing BeanInfo classes be used at all for java.reflect.Introspector */ 067 private boolean ignoreAllBeanInfo = false; 068 069 // pluggable strategies 070 /** The strategy used to detect matching singular and plural properties */ 071 private PluralStemmer pluralStemmer; 072 073 /** The strategy used to convert bean type names into element names */ 074 private NameMapper elementNameMapper; 075 076 /** Strategy normalizes the Class of the Object before introspection */ 077 private ClassNormalizer classNormalizer = new ClassNormalizer(); 078 079 /** Log for introspection messages */ 080 private Log introspectionLog = LogFactory.getLog(XMLIntrospector.class); 081 082 /** 083 * The strategy used to convert bean type names into attribute names 084 * It will default to the normal nameMapper. 085 */ 086 private NameMapper attributeNameMapper; 087 088 /** Prefix naming strategy */ 089 private NamespacePrefixMapper prefixMapper = new NamespacePrefixMapper(); 090 /** Mapping strategy for simple types */ 091 private SimpleTypeMapper simpleTypeMapper = new StandardSimpleTypeMapper(); 092 /** Binding strategy for Java type */ 093 private TypeBindingStrategy typeBindingStrategy = TypeBindingStrategy.DEFAULT; 094 /** Strategy used for determining which types are collective */ 095 private CollectiveTypeStrategy collectiveTypeStrategy = CollectiveTypeStrategy.DEFAULT; 096 097 /** Strategy for suppressing attributes */ 098 private AttributeSuppressionStrategy attributeSuppressionStrategy = AttributeSuppressionStrategy.DEFAULT; 099 /** Strategy for suppressing elements */ 100 private ElementSuppressionStrategy elementSuppressionStrategy = ElementSuppressionStrategy.DEFAULT; 101 102 103 /** 104 * Strategy used to determine whether the bind or introspection time type is to be used to 105 * determine the mapping. 106 */ 107 private MappingDerivationStrategy mappingDerivationStrategy = MappingDerivationStrategy.DEFAULT; 108 109 /** 110 * Strategy used to determine which properties should be ignored 111 */ 112 private PropertySuppressionStrategy propertySuppressionStrategy = PropertySuppressionStrategy.DEFAULT; 113 114 /** 115 * Should the introspector use the context classloader. Defaults to true. 116 */ 117 private boolean useContextClassLoader = true; 118 119 /** 120 * Gets the <code>ClassNormalizer</code> strategy. 121 * This is used to determine the Class to be introspected 122 * (the normalized Class). 123 * 124 * @return the <code>ClassNormalizer</code> used to determine the Class to be introspected 125 * for a given Object. 126 */ 127 public ClassNormalizer getClassNormalizer() { 128 return classNormalizer; 129 } 130 131 /** 132 * Sets the <code>ClassNormalizer</code> strategy. 133 * This is used to determine the Class to be introspected 134 * (the normalized Class). 135 * 136 * @param classNormalizer the <code>ClassNormalizer</code> to be used to determine 137 * the Class to be introspected for a given Object. 138 */ 139 public void setClassNormalizer(ClassNormalizer classNormalizer) { 140 this.classNormalizer = classNormalizer; 141 } 142 143 /** 144 * Should attributes (or elements) be used for primitive types. 145 * @return true if primitive types will be mapped to attributes in the introspection 146 */ 147 public boolean isAttributesForPrimitives() { 148 return attributesForPrimitives; 149 } 150 151 /** 152 * Set whether attributes (or elements) should be used for primitive types. 153 * @param attributesForPrimitives pass trus to map primitives to attributes, 154 * pass false to map primitives to elements 155 */ 156 public void setAttributesForPrimitives(boolean attributesForPrimitives) { 157 this.attributesForPrimitives = attributesForPrimitives; 158 } 159 160 /** 161 * Should collections be wrapped in an extra element? 162 * 163 * @return whether we should we wrap collections in an extra element? 164 */ 165 public boolean isWrapCollectionsInElement() { 166 return wrapCollectionsInElement; 167 } 168 169 /** 170 * Sets whether we should we wrap collections in an extra element. 171 * 172 * @param wrapCollectionsInElement pass true if collections should be wrapped in a 173 * parent element 174 */ 175 public void setWrapCollectionsInElement(boolean wrapCollectionsInElement) { 176 this.wrapCollectionsInElement = wrapCollectionsInElement; 177 } 178 179 /** 180 * Get singular and plural matching strategy. 181 * 182 * @return the strategy used to detect matching singular and plural properties 183 */ 184 public PluralStemmer getPluralStemmer() { 185 if ( pluralStemmer == null ) { 186 pluralStemmer = createPluralStemmer(); 187 } 188 return pluralStemmer; 189 } 190 191 /** 192 * Sets the strategy used to detect matching singular and plural properties 193 * 194 * @param pluralStemmer the PluralStemmer used to match singular and plural 195 */ 196 public void setPluralStemmer(PluralStemmer pluralStemmer) { 197 this.pluralStemmer = pluralStemmer; 198 } 199 200 /** 201 * Gets the name mapping strategy used to convert bean names into elements. 202 * 203 * @return the strategy used to convert bean type names into element 204 * names. If no element mapper is currently defined then a default one is created. 205 */ 206 public NameMapper getElementNameMapper() { 207 if ( elementNameMapper == null ) { 208 elementNameMapper = createNameMapper(); 209 } 210 return elementNameMapper; 211 } 212 213 /** 214 * Sets the strategy used to convert bean type names into element names 215 * @param nameMapper the NameMapper to use for the conversion 216 */ 217 public void setElementNameMapper(NameMapper nameMapper) { 218 this.elementNameMapper = nameMapper; 219 } 220 221 /** 222 * Gets the name mapping strategy used to convert bean names into attributes. 223 * 224 * @return the strategy used to convert bean type names into attribute 225 * names. If no attributeNamemapper is known, it will default to the ElementNameMapper 226 */ 227 public NameMapper getAttributeNameMapper() { 228 if (attributeNameMapper == null) { 229 attributeNameMapper = createNameMapper(); 230 } 231 return attributeNameMapper; 232 } 233 234 235 /** 236 * Sets the strategy used to convert bean type names into attribute names 237 * @param nameMapper the NameMapper to use for the convertion 238 */ 239 public void setAttributeNameMapper(NameMapper nameMapper) { 240 this.attributeNameMapper = nameMapper; 241 } 242 243 /** 244 * <p>Should the original <code>java.reflect.Introspector</code> bean info search path be used?</p> 245 * <p> 246 * Default is false. 247 * </p> 248 * 249 * @return boolean if the beanInfoSearchPath should be used. 250 */ 251 public boolean useBeanInfoSearchPath() { 252 return useBeanInfoSearchPath; 253 } 254 255 /** 256 * Specifies if you want to use the beanInfoSearchPath 257 * @see java.beans.Introspector for more details 258 * @param useBeanInfoSearchPath 259 */ 260 public void setUseBeanInfoSearchPath(boolean useBeanInfoSearchPath) { 261 this.useBeanInfoSearchPath = useBeanInfoSearchPath; 262 } 263 264 /** 265 * <p>Should existing BeanInfo classes be ignored by <code>java.reflect.Introspector</code>.</p> 266 * <p> 267 * Default is false. 268 * </p> 269 * 270 * @return boolean if the BeanInfo classes should be used. 271 */ 272 public boolean ignoreAllBeanInfo() { 273 return ignoreAllBeanInfo; 274 } 275 276 /** 277 * Specifies if you want to ignore existing BeanInfo classes at all for introspection 278 * @see java.beans.Introspector for more details 279 * @param ignoreAllBeanInfo set to true to ignore all BeanInfo classes 280 * @since 0.8 281 */ 282 public void setIgnoreAllBeanInfo(boolean ignoreAllBeanInfo) { 283 this.ignoreAllBeanInfo = ignoreAllBeanInfo; 284 } 285 286 287 /** 288 * A Factory method to lazily create a new strategy 289 * to detect matching singular and plural properties. 290 * 291 * @return new defualt PluralStemmer implementation 292 */ 293 protected PluralStemmer createPluralStemmer() { 294 return new DefaultPluralStemmer(); 295 } 296 297 /** 298 * A Factory method to lazily create a strategy 299 * used to convert bean type names into element names. 300 * 301 * @return new default NameMapper implementation 302 */ 303 protected NameMapper createNameMapper() { 304 return new DefaultNameMapper(); 305 } 306 307 /** 308 * Gets the common Log used for introspection. 309 * It is more convenient to use a single Log 310 * that can be easily configured. 311 * @return Log, not null 312 */ 313 public Log getIntrospectionLog() { 314 return introspectionLog; 315 } 316 317 /** 318 * Sets the common Log used by introspection. 319 * It is more convenient to use a single Log 320 * that can be easily configured. 321 * @param log Log, not null 322 */ 323 public void setIntrospectionLog(Log log) { 324 introspectionLog = log; 325 } 326 327 328 /** 329 * Gets the <code>NamespacePrefixMapper</code> used to convert namespace URIs 330 * into prefixes. 331 * @return NamespacePrefixMapper, not null 332 */ 333 public NamespacePrefixMapper getPrefixMapper() { 334 return prefixMapper; 335 } 336 337 /** 338 * Sets the <code>NamespacePrefixMapper</code> used to convert namespave URIs 339 * into prefixes. 340 * @param mapper NamespacePrefixMapper, not null 341 */ 342 public void setPrefixMapper(NamespacePrefixMapper mapper) { 343 prefixMapper = mapper; 344 } 345 346 347 /** 348 * Gets the simple type binding strategy. 349 * @return SimpleTypeMapper, not null 350 */ 351 public SimpleTypeMapper getSimpleTypeMapper() { 352 return simpleTypeMapper; 353 } 354 355 /** 356 * Sets the simple type binding strategy. 357 * @param mapper SimpleTypeMapper, not null 358 */ 359 public void setSimpleTypeMapper(SimpleTypeMapper mapper) { 360 simpleTypeMapper = mapper; 361 } 362 363 /** 364 * Gets the <code>TypeBindingStrategy</code> to be used 365 * to determine the binding for Java types. 366 * @return the <code>TypeBindingStrategy</code> to be used, 367 * not null 368 */ 369 public TypeBindingStrategy getTypeBindingStrategy() { 370 return typeBindingStrategy; 371 } 372 373 /** 374 * Sets the <code>TypeBindingStrategy</code> to be used 375 * to determine the binding for Java types. 376 * @param typeBindingStrategy the <code>TypeBindingStrategy</code> to be used, 377 * not null 378 */ 379 public void setTypeBindingStrategy(TypeBindingStrategy typeBindingStrategy) { 380 this.typeBindingStrategy = typeBindingStrategy; 381 } 382 383 384 /** 385 * Gets the <code>MappingDerivationStrategy</code> 386 * used to determine whether the bind or introspection time 387 * type should determine the mapping. 388 * @since 0.7 389 * @return <code>MappingDerivationStrategy</code>, not null 390 */ 391 public MappingDerivationStrategy getMappingDerivationStrategy() { 392 return mappingDerivationStrategy; 393 } 394 /** 395 * Sets the <code>MappingDerivationStrategy</code> 396 * used to determine whether the bind or introspection time 397 * type should determine the mapping. 398 * @since 0.7 399 * @param mappingDerivationStrategy <code>MappingDerivationStrategy</code>, not null 400 */ 401 public void setMappingDerivationStrategy( 402 MappingDerivationStrategy mappingDerivationStrategy) { 403 this.mappingDerivationStrategy = mappingDerivationStrategy; 404 } 405 406 /** 407 * Gets the strategy which determines the properties to be ignored. 408 * @since 0.7 409 * @return the <code>PropertySuppressionStrategy</code> to be used for introspection, not null 410 */ 411 public PropertySuppressionStrategy getPropertySuppressionStrategy() { 412 return propertySuppressionStrategy; 413 } 414 415 /** 416 * Sets the strategy which determines the properties to be ignored. 417 * @since 0.7 418 * @param propertySuppressionStrategy the <code>PropertySuppressionStrategy</code> to be used for introspection, not null 419 */ 420 public void setPropertySuppressionStrategy( 421 PropertySuppressionStrategy propertySuppressionStrategy) { 422 this.propertySuppressionStrategy = propertySuppressionStrategy; 423 } 424 425 /** 426 * Gets the strategy used to determine which types are collective. 427 * @return <code>CollectiveTypeStrategy</code>, not null 428 * @since 0.8 429 */ 430 public CollectiveTypeStrategy getCollectiveTypeStrategy() { 431 return collectiveTypeStrategy; 432 } 433 434 /** 435 * Sets the strategy used to determine which types are collective. 436 * @param collectiveTypeStrategy <code>CollectiveTypeStrategy</code>, not null 437 * @since 0.8 438 */ 439 public void setCollectiveTypeStrategy( 440 CollectiveTypeStrategy collectiveTypeStrategy) { 441 this.collectiveTypeStrategy = collectiveTypeStrategy; 442 } 443 444 /** 445 * Is this a loop type class? 446 * @since 0.7 447 * @param type is this <code>Class</code> a loop type? 448 * @return true if the type is a loop type, or if type is null 449 */ 450 public boolean isLoopType(Class type) { 451 return getCollectiveTypeStrategy().isCollective(type); 452 } 453 454 455 /** 456 * Returns the <code>AttributeSuppressionStrategy</code>. 457 * This is used to suppress attributes, e.g. for versioning. 458 * 459 * @since 0.8 460 * @return the strategy 461 */ 462 public AttributeSuppressionStrategy getAttributeSuppressionStrategy() { 463 return attributeSuppressionStrategy; 464 } 465 466 /** 467 * Sets the <code>AttributeSuppressionStrategy</code>. 468 * This is used to suppress attributes, e.g. for versioning. 469 * 470 * @since 0.8 471 * @param attributeSuppressionStrategy the strategy 472 */ 473 public void setAttributeSuppressionStrategy( 474 AttributeSuppressionStrategy attributeSuppressionStrategy) { 475 this.attributeSuppressionStrategy = attributeSuppressionStrategy; 476 } 477 478 /** 479 * Returns the <code>ElementSuppressionStrategy</code>. 480 * This is used to suppress elements, e.g. for versioning. 481 * 482 * @since 0.8 483 * @return the strategy 484 */ 485 public ElementSuppressionStrategy getElementSuppressionStrategy() { 486 return elementSuppressionStrategy; 487 } 488 489 /** 490 * Sets the <code>ElementSuppressionStrategy</code>. 491 * This is used to suppress elements, e.g. for versioning. 492 * 493 * @since 0.8 494 * @param elementSuppressionStrategy the strategy 495 */ 496 public void setElementSuppressionStrategy( 497 ElementSuppressionStrategy elementSuppressionStrategy) { 498 this.elementSuppressionStrategy = elementSuppressionStrategy; 499 } 500 501 /** 502 * Should be context classloader be used when loading classes? 503 * @return <code>true</code> if the context classloader is to be used during introspection, 504 * <code>false</code> otherwise. 505 */ 506 public boolean isUseContextClassLoader() { 507 return useContextClassLoader; 508 } 509 510 /** 511 * <p>Specify whether the context classloader should be used to load classes during introspection; 512 * the default value is true.</p> 513 * <p> 514 * When running code that is not in a container (ie where the context classloader is the same 515 * as the system classloader), this setting has no effect. When running code in containers that 516 * do define a context classloader for loaded "components" (eg webapps), a true value will allow 517 * classes in the loaded "component" to be accessable even when Betwixt is deployed via a 518 * "higher level" classloader. 519 * </p> 520 * <p> 521 * If code is running in a container that uses a context classloader in unusual ways then it 522 * may be necessary to set this value to false. In this case, classes are always loaded using the 523 * same classloader that loaded the betwixt library. 524 * </p> 525 */ 526 public void setUseContextClassLoader(boolean useContextClassLoader) { 527 this.useContextClassLoader = useContextClassLoader; 528 } 529 }