in commons-digester3-core/src/main/java/org/apache/commons/digester3/SetPropertiesRule.java [157:238]
public void begin( final String namespace, final String name, final Attributes attributes )
throws Exception
{
// Build a set of attribute names and corresponding values
final Map<String, String> values = new HashMap<>();
for ( int i = 0; i < attributes.getLength(); i++ )
{
String attributeName = attributes.getLocalName( i );
if ( "".equals( attributeName ) )
{
attributeName = attributes.getQName( i );
}
final String value = attributes.getValue( i );
// alias lookup has complexity O(1)
if ( aliases.containsKey( attributeName ) )
{
attributeName = aliases.get( attributeName );
}
if ( getDigester().getLogger().isDebugEnabled() )
{
getDigester().getLogger().debug( format( "[SetPropertiesRule]{%s} Setting property '%s' to '%s'",
getDigester().getMatch(),
attributeName,
attributeName ) );
}
if ( !ignoreMissingProperty && attributeName != null )
{
// The BeanUtils.populate method silently ignores items in
// the map (ie XML entities) which have no corresponding
// setter method, so here we check whether each XML attribute
// does have a corresponding property before calling the
// BeanUtils.populate method.
//
// Yes having the test and set as separate steps is ugly and
// inefficient. But BeanUtils.populate doesn't provide the
// functionality we need here, and changing the algorithm which
// determines the appropriate setter method to invoke is
// considered too risky.
//
// Using two different classes (PropertyUtils vs BeanUtils) to
// do the test and the set is also ugly; the code paths
// are different which could potentially lead to trouble.
// However the BeanUtils/PropertyUtils code has been carefully
// compared and the PropertyUtils functionality does appear
// compatible so we'll accept the risk here.
final Object top = getDigester().peek();
final boolean test = isWriteable( top, attributeName );
if ( !test )
{
throw new NoSuchMethodException( "Property " + attributeName + " can't be set" );
}
}
if ( attributeName != null )
{
values.put( attributeName, value );
}
}
// Populate the corresponding properties of the top object
final Object top = getDigester().peek();
if ( getDigester().getLogger().isDebugEnabled() )
{
if ( top != null )
{
getDigester().getLogger().debug( format( "[SetPropertiesRule]{%s} Set '%s' properties",
getDigester().getMatch(),
top.getClass().getName() ) );
}
else
{
getDigester().getLogger().debug( format( "[SetPropertiesRule]{%s} Set NULL properties",
getDigester().getMatch() ) );
}
}
populate( top, values );
}