| Method from org.apache.commons.betwixt.XMLIntrospector Detail: |
protected void addProperties(BeanInfo beanInfo,
List elements,
List attributes) throws IntrospectionException {
PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors();
if ( descriptors != null ) {
for ( int i = 0, size = descriptors.length; i < size; i++ ) {
addProperty(beanInfo, descriptors[i], elements, attributes);
}
}
if (getLog().isTraceEnabled()) {
getLog().trace(elements);
getLog().trace(attributes);
}
} Deprecated! 0.5 - this method does not support mixed content.
Use #addProperties(BeanInfo, List, List, List) instead.
Loop through properties and process each one |
protected void addProperties(BeanInfo beanInfo,
List elements,
List attributes,
List contents) throws IntrospectionException {
PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors();
if ( descriptors != null ) {
for ( int i = 0, size = descriptors.length; i < size; i++ ) {
addProperty(beanInfo, descriptors[i], elements, attributes, contents);
}
}
if (getLog().isTraceEnabled()) {
getLog().trace(elements);
getLog().trace(attributes);
getLog().trace(contents);
}
} Deprecated! 0.5 - use #addProperties(BeanProperty[], List, List,List)
Loop through properties and process each one |
protected void addProperties(BeanProperty[] beanProperties,
List elements,
List attributes,
List contents) {
if ( beanProperties != null ) {
if (getLog().isTraceEnabled()) {
getLog().trace(beanProperties.length + " properties to be added");
}
for ( int i = 0, size = beanProperties.length; i < size; i++ ) {
addProperty(beanProperties[i], elements, attributes, contents);
}
}
if (getLog().isTraceEnabled()) {
getLog().trace("After properties have been added (elements, attributes, contents):");
getLog().trace(elements);
getLog().trace(attributes);
getLog().trace(contents);
}
}
Loop through properties and process each one |
protected void addProperty(PropertyDescriptor propertyDescriptor,
List elements,
List attributes,
List contents) throws IntrospectionException {
addProperty(new BeanProperty( propertyDescriptor ), elements, attributes, contents);
} Deprecated! 0.5 - use #addProperty(BeanProperty, List, List, List) instead
Process a property.
Go through and work out whether it's a loop property, a primitive or a standard.
The class property is ignored. |
protected void addProperty(BeanProperty beanProperty,
List elements,
List attributes,
List contents) {
Descriptor nodeDescriptor = createXMLDescriptor(beanProperty);
if (nodeDescriptor == null) {
return;
}
if (nodeDescriptor instanceof ElementDescriptor) {
elements.add(nodeDescriptor);
} else if (nodeDescriptor instanceof AttributeDescriptor) {
attributes.add(nodeDescriptor);
} else {
contents.add(nodeDescriptor);
}
}
Process a property.
Go through and work out whether it's a loop property, a primitive or a standard.
The class property is ignored. |
protected void addProperty(BeanInfo beanInfo,
PropertyDescriptor propertyDescriptor,
List elements,
List attributes) throws IntrospectionException {
NodeDescriptor nodeDescriptor = XMLIntrospectorHelper
.createDescriptor(propertyDescriptor,
isAttributesForPrimitives(),
this);
if (nodeDescriptor == null) {
return;
}
if (nodeDescriptor instanceof ElementDescriptor) {
elements.add(nodeDescriptor);
} else {
attributes.add(nodeDescriptor);
}
} Deprecated! 0.5 - this method does not support mixed content.
Use #addProperty(BeanInfo, PropertyDescriptor, List, List, List) instead.
Process a property.
Go through and work out whether it's a loop property, a primitive or a standard.
The class property is ignored. |
protected void addProperty(BeanInfo beanInfo,
PropertyDescriptor propertyDescriptor,
List elements,
List attributes,
List contents) throws IntrospectionException {
addProperty( propertyDescriptor, elements, attributes, contents);
} Deprecated! 0.5 - BeanInfo is no longer required.
Use #addProperty(PropertyDescriptor, List, List, List) instead.
Process a property.
Go through and work out whether it's a loop property, a primitive or a standard.
The class property is ignored. |
public void assignAdder(Method twinParameterAdderMethod,
ElementDescriptor matchingDescriptor) {
if ( matchingDescriptor != null
&& Map.class.isAssignableFrom( matchingDescriptor.getPropertyType() )) {
// this may match a map
getLog().trace("Matching map");
ElementDescriptor[] children
= matchingDescriptor.getElementDescriptors();
// see if the descriptor's been set up properly
if ( children.length == 0 ) {
getLog().info(
"'entry' descriptor is missing for map. "
+ "Updaters cannot be set");
} else {
assignAdder(twinParameterAdderMethod, children);
}
}
}
Assigns the given method as an adder method to the given descriptor. |
public Descriptor createDescriptor(PropertyDescriptor propertyDescriptor,
boolean useAttributesForPrimitives) throws IntrospectionException {
return createXMLDescriptor( new BeanProperty( propertyDescriptor ) );
} Deprecated! 0.5 - use #createXMLDescriptor .
Create a XML descriptor from a bean one.
Go through and work out whether it's a loop property, a primitive or a standard.
The class property is ignored. |
protected NameMapper createNameMapper() {
return new DefaultNameMapper();
} Deprecated! 0.6 - this method has been moved into IntrospectionConfiguration.
Those who need to vary this should subclass that class instead
A Factory method to lazily create a strategy
used to convert bean type names into element names. |
protected PluralStemmer createPluralStemmer() {
return new DefaultPluralStemmer();
} Deprecated! 0.6 - this method has been moved into IntrospectionConfiguration.
Those who need to vary this should subclass that class instead
A Factory method to lazily create a new strategy
to detect matching singular and plural properties. |
protected XMLBeanInfo createXMLBeanInfo(DynaClass dynaClass) {
// XXX is the chosen class right?
XMLBeanInfo beanInfo = new XMLBeanInfo(dynaClass.getClass());
return beanInfo;
}
Creates XMLBeanInfo for the given DynaClass. |
protected XMLBeanInfo createXMLBeanInfo(BeanInfo beanInfo) {
XMLBeanInfo xmlBeanInfo = new XMLBeanInfo( beanInfo.getBeanDescriptor().getBeanClass() );
return xmlBeanInfo;
}
Factory method to create XMLBeanInfo instances |
public Descriptor createXMLDescriptor(BeanProperty beanProperty) {
return beanProperty.createXMLDescriptor( configuration );
}
Create a XML descriptor from a bean one.
Go through and work out whether it's a loop property, a primitive or a standard.
The class property is ignored. |
public void defaultAddMethods(ElementDescriptor rootDescriptor,
Class beanClass) {
defaultAddMethods(rootDescriptor, beanClass, false);
}
Add any addPropety(PropertyType) methods as Updaters
which are often used for 1-N relationships in beans.
This method does not preserve null property names.
The tricky part here is finding which ElementDescriptor corresponds
to the method. e.g. a property 'items' might have an Element descriptor
which the method addItem() should match to.
So the algorithm we'll use
by default is to take the decapitalized name of the property being added
and find the first ElementDescriptor that matches the property starting with
the string. This should work for most use cases.
e.g. addChild() would match the children property.
TODO this probably needs refactoring. It probably belongs in the bean wrapper
(so that it'll work properly with dyna-beans) and so that the operations can
be optimized by caching. Multiple hash maps are created and getMethods is
called multiple times. This is relatively expensive and so it'd be better
to push into a proper class and cache.
|
public void defaultAddMethods(ElementDescriptor rootDescriptor,
Class beanClass,
boolean preservePropertyName) {
// TODO: this probably does work properly with DynaBeans: need to push
// implementation into an class and expose it on BeanType.
// lets iterate over all methods looking for one of the form
// add*(PropertyType)
if ( beanClass != null ) {
ArrayList singleParameterAdders = new ArrayList();
ArrayList twinParameterAdders = new ArrayList();
Method[] methods = beanClass.getMethods();
for ( int i = 0, size = methods.length; i < size; i++ ) {
Method method = methods[i];
String name = method.getName();
if ( name.startsWith( "add" )) {
// TODO: should we filter out non-void returning methods?
// some beans will return something as a helper
Class[] types = method.getParameterTypes();
if ( types != null) {
if ( getLog().isTraceEnabled() ) {
getLog().trace("Searching for match for " + method);
}
switch (types.length)
{
case 1:
singleParameterAdders.add(method);
break;
case 2:
twinParameterAdders.add(method);
break;
default:
// ignore
break;
}
}
}
}
Map elementsByPropertyName = makeElementDescriptorMap( rootDescriptor );
for (Iterator it=singleParameterAdders.iterator();it.hasNext();) {
Method singleParameterAdder = (Method) it.next();
setIteratorAdder(elementsByPropertyName, singleParameterAdder, preservePropertyName);
}
for (Iterator it=twinParameterAdders.iterator();it.hasNext();) {
Method twinParameterAdder = (Method) it.next();
setMapAdder(elementsByPropertyName, twinParameterAdder);
}
// need to call this once all the defaults have been added
// so that all the singular types have been set correctly
configureMappingDerivation( rootDescriptor );
}
}
Add any addPropety(PropertyType) methods as Updaters
which are often used for 1-N relationships in beans.
The tricky part here is finding which ElementDescriptor corresponds
to the method. e.g. a property 'items' might have an Element descriptor
which the method addItem() should match to.
So the algorithm we'll use
by default is to take the decapitalized name of the property being added
and find the first ElementDescriptor that matches the property starting with
the string. This should work for most use cases.
e.g. addChild() would match the children property.
TODO this probably needs refactoring. It probably belongs in the bean wrapper
(so that it'll work properly with dyna-beans) and so that the operations can
be optimized by caching. Multiple hash maps are created and getMethods is
called multiple times. This is relatively expensive and so it'd be better
to push into a proper class and cache.
|
protected synchronized XMLBeanInfo findByXMLDescriptor(Class aClass) {
// trim the package name
String name = aClass.getName();
int idx = name.lastIndexOf( '." );
if ( idx >= 0 ) {
name = name.substring( idx + 1 );
}
name += ".betwixt";
URL url = aClass.getResource( name );
if ( url != null ) {
try {
String urlText = url.toString();
if ( getLog().isDebugEnabled( )) {
getLog().debug( "Parsing Betwixt XML descriptor: " + urlText );
}
// synchronized method so this digester is only used by
// one thread at once
configureDigester(aClass);
return (XMLBeanInfo) digester.parse( urlText );
} catch (Exception e) {
getLog().warn( "Caught exception trying to parse: " + name, e );
}
}
if ( getLog().isTraceEnabled() ) {
getLog().trace( "Could not find betwixt file " + name );
}
return null;
}
Attempt to lookup the XML descriptor for the given class using the
classname + ".betwixt" using the same ClassLoader used to load the class
or return null if it could not be loaded |
public void flushCache() {
} Deprecated! 0.5 - use flushable registry instead
Flush existing cached XMLBeanInfo's. |
public NameMapper getAttributeNameMapper() {
return getConfiguration().getAttributeNameMapper();
} Deprecated! 0.6 - getConfiguration().getAttributeNameMapper
Gets the name mapping strategy used to convert bean names into attributes. |
public ClassNormalizer getClassNormalizer() {
return getConfiguration().getClassNormalizer();
} Deprecated! 0.6 - use getConfiguration().getClassNormalizer
Gets the ClassNormalizer strategy.
This is used to determine the Class to be introspected
(the normalized Class). |
public IntrospectionConfiguration getConfiguration() {
return configuration;
}
Gets the configuration to be used for introspection.
The various introspection-time strategies
and configuration variables have been consolidated as properties
of this bean.
This allows the configuration to be more easily shared. |
public NameMapper getElementNameMapper() {
return getConfiguration().getElementNameMapper();
} Deprecated! 0.6 - use getConfiguration().getElementNameMapper
Gets the name mapping strategy used to convert bean names into elements. |
public Log getLog() {
return getConfiguration().getIntrospectionLog();
}
|
public NameMapper getNameMapper() {
return getElementNameMapper();
} Deprecated! 0.5 - getNameMapper is split up in
#getElementNameMapper() and #getAttributeNameMapper()
Gets the name mapper strategy. |
public PluralStemmer getPluralStemmer() {
return getConfiguration().getPluralStemmer();
} Deprecated! 0.6 - use getConfiguration().getPluralStemmer
Get singular and plural matching strategy. |
public PolymorphicReferenceResolver getPolymorphicReferenceResolver() {
return polymorphicReferenceResolver;
}
|
public XMLBeanInfoRegistry getRegistry() {
return registry;
}
Gets the current registry implementation.
The registry is checked to see if it has an XMLBeanInfo for a class
before introspecting.
After standard introspection is complete, the instance will be passed to the registry.
This allows finely grained control over the caching strategy.
It also allows the standard introspection mechanism
to be overridden on a per class basis.
|
public XMLBeanInfo introspect(Object bean) throws IntrospectionException {
if (getLog().isDebugEnabled()) {
getLog().debug( "Introspecting..." );
getLog().debug(bean);
}
if ( bean instanceof DynaBean ) {
// allow DynaBean implementations to be overridden by .betwixt files
XMLBeanInfo xmlBeanInfo = findByXMLDescriptor( bean.getClass() );
if (xmlBeanInfo != null) {
return xmlBeanInfo;
}
// this is DynaBean use the DynaClass for introspection
return introspect( ((DynaBean) bean).getDynaClass() );
} else {
// normal bean so normal introspection
Class normalClass = getClassNormalizer().getNormalizedClass( bean );
return introspect( normalClass );
}
}
Create a standard XMLBeanInfo by introspection
The actual introspection depends only on the BeanInfo
associated with the bean. |
public XMLBeanInfo introspect(DynaClass dynaClass) {
// for now this method does not do much, since XMLBeanInfoRegistry cannot
// use a DynaClass as a key
// TODO: add caching for DynaClass XMLBeanInfo
// need to work out if this is possible
// this line allows subclasses to change creation strategy
XMLBeanInfo xmlInfo = createXMLBeanInfo( dynaClass );
// populate the created info with
DynaClassBeanType beanClass = new DynaClassBeanType( dynaClass );
populate( xmlInfo, beanClass );
return xmlInfo;
}
Creates XMLBeanInfo by reading the DynaProperties of a DynaBean.
Customizing DynaBeans using betwixt is not supported. |
public XMLBeanInfo introspect(Class aClass) throws IntrospectionException {
// we first reset the beaninfo searchpath.
String[] searchPath = null;
if ( !getConfiguration().useBeanInfoSearchPath() ) {
try {
searchPath = Introspector.getBeanInfoSearchPath();
Introspector.setBeanInfoSearchPath(new String[] { });
} catch (SecurityException e) {
// this call may fail in some environments
getLog().warn("Security manager does not allow bean info search path to be set");
getLog().debug("Security exception whilst setting bean info search page", e);
}
}
XMLBeanInfo xmlInfo = registry.get( aClass );
if ( xmlInfo == null ) {
// lets see if we can find an XML descriptor first
if ( getLog().isDebugEnabled() ) {
getLog().debug( "Attempting to lookup an XML descriptor for class: " + aClass );
}
xmlInfo = findByXMLDescriptor( aClass );
if ( xmlInfo == null ) {
BeanInfo info;
if(getConfiguration().ignoreAllBeanInfo()) {
info = Introspector.getBeanInfo( aClass, Introspector.IGNORE_ALL_BEANINFO );
}
else {
info = Introspector.getBeanInfo( aClass );
}
xmlInfo = introspect( info );
}
if ( xmlInfo != null ) {
registry.put( aClass, xmlInfo );
}
} else {
getLog().trace( "Used cached XMLBeanInfo." );
}
if ( getLog().isTraceEnabled() ) {
getLog().trace( xmlInfo );
}
if ( !getConfiguration().useBeanInfoSearchPath() && searchPath != null) {
try
{
// we restore the beaninfo searchpath.
Introspector.setBeanInfoSearchPath( searchPath );
} catch (SecurityException e) {
// this call may fail in some environments
getLog().warn("Security manager does not allow bean info search path to be set");
getLog().debug("Security exception whilst setting bean info search page", e);
}
}
return xmlInfo;
}
Create a standard XMLBeanInfo by introspection.
The actual introspection depends only on the BeanInfo
associated with the bean. |
public XMLBeanInfo introspect(BeanInfo beanInfo) throws IntrospectionException {
XMLBeanInfo xmlBeanInfo = createXMLBeanInfo( beanInfo );
populate( xmlBeanInfo, new JavaBeanType( beanInfo ) );
return xmlBeanInfo;
}
Create a standard XMLBeanInfo by introspection.
The actual introspection depends only on the BeanInfo
associated with the bean. |
public synchronized XMLBeanInfo introspect(Class aClass,
InputSource source) throws IOException, SAXException {
// need to synchronize since we only use one instance and SAX is essentially one thread only
configureDigester(aClass);
XMLBeanInfo result = (XMLBeanInfo) digester.parse(source);
return result;
}
Introspects the given Class using the dot betwixt
document in the given InputSource.
Note: that the given mapping will not
be registered by this method. Use #register(Class, InputSource)
instead.
|
public boolean isAttributesForPrimitives() {
return getConfiguration().isAttributesForPrimitives();
} Deprecated! 0.6 - use getConfiguration().isAttributesForPrimitives
Should attributes (or elements) be used for primitive types. |
public boolean isCachingEnabled() {
return true;
} Deprecated! 0.5 - replaced by XMlBeanInfoRegistry
Is XMLBeanInfo caching enabled? |
public boolean isLoopType(Class type) {
return getConfiguration().isLoopType(type);
}
|
public boolean isPrimitiveType(Class type) {
// TODO: this method will probably be deprecated when primitive types
// are subsumed into the simple type concept
TypeBindingStrategy.BindingType bindingType
= configuration.getTypeBindingStrategy().bindingType( type ) ;
boolean result = (bindingType.equals(TypeBindingStrategy.BindingType.PRIMITIVE));
return result;
}
Is this class a primitive? |
public boolean isWrapCollectionsInElement() {
return getConfiguration().isWrapCollectionsInElement();
} Deprecated! 0.6 - use getConfiguration().isWrapCollectionsInElement
Should collections be wrapped in an extra element? |
public synchronized Class[] register(InputSource source) throws IntrospectionException, IOException, SAXException {
Map xmlBeanInfoByClass = loadMultiMapping(source);
Set keySet = xmlBeanInfoByClass.keySet();
Class mappedClasses[] = new Class[keySet.size()];
int i=0;
for (Iterator it=keySet.iterator(); it.hasNext(); ) {
Class clazz = (Class) it.next();
mappedClasses[i++] = clazz;
XMLBeanInfo xmlBeanInfo = (XMLBeanInfo) xmlBeanInfoByClass.get(clazz);
if (xmlBeanInfo != null) {
getRegistry().put(clazz, xmlBeanInfo);
}
}
return mappedClasses;
}
Registers the class mappings specified in the multi-class document
given by the InputSource.
Note: that this method will override any existing mapping
for the speficied classes.
|
public void register(Class aClass,
InputSource source) throws IOException, SAXException {
XMLBeanInfo xmlBeanInfo = introspect(aClass, source);
getRegistry().put(aClass, xmlBeanInfo);
}
Registers the class mapping specified in the standard dot-betwixt file.
Subsequent introspections will use this registered mapping for the class.
Note: that this method will override any existing mapping
for this class.
|
public void setAttributeNameMapper(NameMapper nameMapper) {
getConfiguration().setAttributeNameMapper( nameMapper );
} Deprecated! 0.6 - use getConfiguration().setAttributeNameMapper
Sets the strategy used to convert bean type names into attribute names |
public void setAttributesForPrimitives(boolean attributesForPrimitives) {
getConfiguration().setAttributesForPrimitives(attributesForPrimitives);
} Deprecated! 0.6 - use getConfiguration().setAttributesForPrimitives
Set whether attributes (or elements) should be used for primitive types. |
public void setCachingEnabled(boolean cachingEnabled) {
//
} Deprecated! 0.5 - replaced by XMlBeanInfoRegistry
Set whether XMLBeanInfo caching should be enabled. |
public void setClassNormalizer(ClassNormalizer classNormalizer) {
getConfiguration().setClassNormalizer(classNormalizer);
} Deprecated! 0.6 - use getConfiguration().setClassNormalizer
Sets the ClassNormalizer strategy.
This is used to determine the Class to be introspected
(the normalized Class). |
public void setConfiguration(IntrospectionConfiguration configuration) {
this.configuration = configuration;
}
Sets the configuration to be used for introspection.
The various introspection-time strategies
and configuration variables have been consolidated as properties
of this bean.
This allows the configuration to be more easily shared. |
public void setElementNameMapper(NameMapper nameMapper) {
getConfiguration().setElementNameMapper( nameMapper );
} Deprecated! 0.6 - use getConfiguration().setElementNameMapper
Sets the strategy used to convert bean type names into element names |
public void setLog(Log log) {
getConfiguration().setIntrospectionLog(log);
}
|
public void setNameMapper(NameMapper nameMapper) {
setElementNameMapper(nameMapper);
} Deprecated! 0.5 - setNameMapper is split up in
#setElementNameMapper(NameMapper) and #setAttributeNameMapper(NameMapper)
Sets the strategy used to convert bean type names into element names |
public void setPluralStemmer(PluralStemmer pluralStemmer) {
getConfiguration().setPluralStemmer(pluralStemmer);
} Deprecated! 0.6 - use getConfiguration().setPluralStemmer
Sets the strategy used to detect matching singular and plural properties |
public void setPolymorphicReferenceResolver(PolymorphicReferenceResolver polymorphicReferenceResolver) {
this.polymorphicReferenceResolver = polymorphicReferenceResolver;
}
|
public void setRegistry(XMLBeanInfoRegistry registry) {
this.registry = registry;
}
Sets the XMLBeanInfoRegistry implementation.
The registry is checked to see if it has an XMLBeanInfo for a class
before introspecting.
After standard introspection is complete, the instance will be passed to the registry.
This allows finely grained control over the caching strategy.
It also allows the standard introspection mechanism
to be overridden on a per class basis.
Note when using polymophic mapping with a custom
registry, a call to
#setPolymorphicReferenceResolver(PolymorphicReferenceResolver)
may be necessary.
|
public void setUseBeanInfoSearchPath(boolean useBeanInfoSearchPath) {
getConfiguration().setUseBeanInfoSearchPath( useBeanInfoSearchPath );
} Deprecated! 0.6 - use getConfiguration().setUseBeanInfoSearchPath
Specifies if you want to use the beanInfoSearchPath |
public void setWrapCollectionsInElement(boolean wrapCollectionsInElement) {
getConfiguration().setWrapCollectionsInElement(wrapCollectionsInElement);
} Deprecated! 0.6 - use getConfiguration().setWrapCollectionsInElement
Sets whether we should we wrap collections in an extra element. |
public boolean useBeanInfoSearchPath() {
return getConfiguration().useBeanInfoSearchPath();
} Deprecated! 0.6 - use getConfiguration().useBeanInfoSearchPath
Should the original java.reflect.Introspector bean info search path be used?
By default it will be false. |