Submitted by: "Adam Murdoch" <adammurdoch_ml@yahoo.com> git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@270491 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -0,0 +1,35 @@ | |||||
| /* | |||||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
| * | |||||
| * This software is published under the terms of the Apache Software License | |||||
| * version 1.1, a copy of which has been included with this distribution in | |||||
| * the LICENSE.txt file. | |||||
| */ | |||||
| package org.apache.myrmidon.components.configurer; | |||||
| import org.apache.avalon.framework.configuration.ConfigurationException; | |||||
| /** | |||||
| * Used to set an attribute or text content of an object. | |||||
| * | |||||
| * @author <a href="mailto:adammurdoch_ml@yahoo.com">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public interface AttributeSetter | |||||
| { | |||||
| /** | |||||
| * Returns the attribute type. | |||||
| */ | |||||
| Class getType(); | |||||
| /** | |||||
| * Sets the value of the attribute. | |||||
| * | |||||
| * @param object The object to set the attribute of. | |||||
| * @param value The value of the attribute. Must be assignable to the class | |||||
| * returned by {@link #getType}. | |||||
| * @throw ConfigurationException If the value could not be set. | |||||
| */ | |||||
| void setAttribute( Object object, Object value ) | |||||
| throws ConfigurationException; | |||||
| } | |||||
| @@ -0,0 +1,66 @@ | |||||
| /* | |||||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
| * | |||||
| * This software is published under the terms of the Apache Software License | |||||
| * version 1.1, a copy of which has been included with this distribution in | |||||
| * the LICENSE.txt file. | |||||
| */ | |||||
| package org.apache.myrmidon.components.configurer; | |||||
| import java.lang.reflect.InvocationTargetException; | |||||
| import java.lang.reflect.Method; | |||||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
| import org.apache.avalon.excalibur.i18n.Resources; | |||||
| import org.apache.avalon.framework.configuration.ConfigurationException; | |||||
| /** | |||||
| * A default attribute setter implementation, which uses reflection to | |||||
| * set the attribute value. | |||||
| * | |||||
| * @author <a href="mailto:adammurdoch_ml@yahoo.com">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| class DefaultAttributeSetter | |||||
| implements AttributeSetter | |||||
| { | |||||
| private final Method m_method; | |||||
| private final Class m_type; | |||||
| private static final Resources REZ = | |||||
| ResourceManager.getPackageResources( DefaultAttributeSetter.class ); | |||||
| public DefaultAttributeSetter( final Method method ) | |||||
| { | |||||
| m_method = method; | |||||
| m_type = method.getParameterTypes()[ 0 ]; | |||||
| } | |||||
| /** | |||||
| * Returns the attribute type. | |||||
| */ | |||||
| public Class getType() | |||||
| { | |||||
| return m_type; | |||||
| } | |||||
| /** | |||||
| * Sets the value of the attribute. | |||||
| */ | |||||
| public void setAttribute( final Object object, final Object value ) | |||||
| throws ConfigurationException | |||||
| { | |||||
| try | |||||
| { | |||||
| m_method.invoke( object, new Object[]{value} ); | |||||
| } | |||||
| catch( final InvocationTargetException ite ) | |||||
| { | |||||
| final Throwable cause = ite.getTargetException(); | |||||
| throw new ConfigurationException( cause.getMessage(), cause ); | |||||
| } | |||||
| catch( final Exception e ) | |||||
| { | |||||
| throw new ConfigurationException( e.getMessage(), e ); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -7,12 +7,10 @@ | |||||
| */ | */ | ||||
| package org.apache.myrmidon.components.configurer; | package org.apache.myrmidon.components.configurer; | ||||
| import java.lang.reflect.InvocationTargetException; | |||||
| import java.lang.reflect.Method; | |||||
| import java.util.ArrayList; | |||||
| import java.util.HashMap; | |||||
| import java.util.Map; | |||||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | import org.apache.avalon.excalibur.i18n.ResourceManager; | ||||
| import org.apache.avalon.excalibur.i18n.Resources; | import org.apache.avalon.excalibur.i18n.Resources; | ||||
| import org.apache.avalon.excalibur.property.PropertyException; | |||||
| import org.apache.avalon.excalibur.property.PropertyUtil; | import org.apache.avalon.excalibur.property.PropertyUtil; | ||||
| import org.apache.avalon.framework.component.ComponentException; | import org.apache.avalon.framework.component.ComponentException; | ||||
| import org.apache.avalon.framework.component.ComponentManager; | import org.apache.avalon.framework.component.ComponentManager; | ||||
| @@ -23,7 +21,6 @@ import org.apache.avalon.framework.configuration.ConfigurationException; | |||||
| import org.apache.avalon.framework.context.Context; | import org.apache.avalon.framework.context.Context; | ||||
| import org.apache.avalon.framework.logger.AbstractLogEnabled; | import org.apache.avalon.framework.logger.AbstractLogEnabled; | ||||
| import org.apache.avalon.framework.logger.LogEnabled; | import org.apache.avalon.framework.logger.LogEnabled; | ||||
| import org.apache.myrmidon.converter.ConverterException; | |||||
| import org.apache.myrmidon.interfaces.configurer.Configurer; | import org.apache.myrmidon.interfaces.configurer.Configurer; | ||||
| import org.apache.myrmidon.interfaces.converter.MasterConverter; | import org.apache.myrmidon.interfaces.converter.MasterConverter; | ||||
| @@ -42,18 +39,13 @@ public class DefaultConfigurer | |||||
| ///Compile time constant to turn on extreme debugging | ///Compile time constant to turn on extreme debugging | ||||
| private final static boolean DEBUG = false; | private final static boolean DEBUG = false; | ||||
| /* | |||||
| * TODO: Should reserved names be "configurable" ? | |||||
| */ | |||||
| ///Element names that are reserved | |||||
| private final static String[] RESERVED_ELEMENTS = | |||||
| { | |||||
| "content" | |||||
| }; | |||||
| ///Converter to use for converting between values | ///Converter to use for converting between values | ||||
| private MasterConverter m_converter; | private MasterConverter m_converter; | ||||
| ///Cached object configurers. This is a map from Class to the | |||||
| ///ObjectConfigurer for that class. | |||||
| private Map m_configurerCache = new HashMap(); | |||||
| public void compose( final ComponentManager componentManager ) | public void compose( final ComponentManager componentManager ) | ||||
| throws ComponentException | throws ComponentException | ||||
| { | { | ||||
| @@ -81,7 +73,7 @@ public class DefaultConfigurer | |||||
| if( DEBUG ) | if( DEBUG ) | ||||
| { | { | ||||
| final String message = REZ.getString( "configuring-object.notice", object ); | final String message = REZ.getString( "configuring-object.notice", object ); | ||||
| getLogger().debug( "Configuring " + object ); | |||||
| getLogger().debug( message ); | |||||
| } | } | ||||
| if( object instanceof Configurable ) | if( object instanceof Configurable ) | ||||
| @@ -89,9 +81,10 @@ public class DefaultConfigurer | |||||
| if( DEBUG ) | if( DEBUG ) | ||||
| { | { | ||||
| final String message = REZ.getString( "configurable.notice" ); | final String message = REZ.getString( "configurable.notice" ); | ||||
| getLogger().debug( "Configuring object via Configurable interface" ); | |||||
| getLogger().debug( message ); | |||||
| } | } | ||||
| // Let the object configure itself | |||||
| ( (Configurable)object ).configure( configuration ); | ( (Configurable)object ).configure( configuration ); | ||||
| } | } | ||||
| else | else | ||||
| @@ -102,408 +95,257 @@ public class DefaultConfigurer | |||||
| getLogger().debug( message ); | getLogger().debug( message ); | ||||
| } | } | ||||
| // Locate the configurer for this object | |||||
| final ObjectConfigurer configurer = getConfigurer( object.getClass() ); | |||||
| // Set each of the attributes | |||||
| final String[] attributes = configuration.getAttributeNames(); | final String[] attributes = configuration.getAttributeNames(); | ||||
| for( int i = 0; i < attributes.length; i++ ) | for( int i = 0; i < attributes.length; i++ ) | ||||
| { | { | ||||
| final String name = attributes[ i ]; | final String name = attributes[ i ]; | ||||
| final String value = configuration.getAttribute( name ); | final String value = configuration.getAttribute( name ); | ||||
| if( DEBUG ) | |||||
| { | |||||
| final String message = REZ.getString( "configure-attribute.notice", name, value ); | |||||
| getLogger().debug( message ); | |||||
| } | |||||
| configureAttribute( object, name, value, context ); | |||||
| // Set the attribute | |||||
| setAttribute( configurer, object, name, value, context ); | |||||
| } | } | ||||
| final Configuration[] children = configuration.getChildren(); | |||||
| for( int i = 0; i < children.length; i++ ) | |||||
| // Set the text content | |||||
| final String content = configuration.getValue( null ); | |||||
| if( null != content && content.length() > 0 ) | |||||
| { | { | ||||
| final Configuration child = children[ i ]; | |||||
| if( DEBUG ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "configure-subelement.notice", child.getName() ); | |||||
| getLogger().debug( message ); | |||||
| } | |||||
| configureElement( object, child, context ); | |||||
| setContent( configurer, object, content, context ); | |||||
| } | } | ||||
| final String content = configuration.getValue( null ); | |||||
| if( null != content ) | |||||
| // Create and configure each of the child elements | |||||
| final Configuration[] children = configuration.getChildren(); | |||||
| for( int i = 0; i < children.length; i++ ) | |||||
| { | { | ||||
| if( !content.trim().equals( "" ) ) | |||||
| { | |||||
| if( DEBUG ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "configure-content.notice", content ); | |||||
| getLogger().debug( message ); | |||||
| } | |||||
| configureContent( object, content, context ); | |||||
| } | |||||
| final Configuration childConfig = children[ i ]; | |||||
| configureElement( configurer, object, childConfig, context ); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /** | /** | ||||
| * Configure named attribute of object in a particular context. | |||||
| * This configuring can be done in different ways for different | |||||
| * configurers. | |||||
| * | |||||
| * @param object the object | |||||
| * @param name the attribute name | |||||
| * @param value the attribute value | |||||
| * @param context the Context | |||||
| * @exception ConfigurationException if an error occurs | |||||
| * Sets the text content of an object. | |||||
| */ | */ | ||||
| public void configure( final Object object, | |||||
| final String name, | |||||
| final String value, | |||||
| final Context context ) | |||||
| private void setContent( final ObjectConfigurer configurer, | |||||
| final Object object, | |||||
| final String content, | |||||
| final Context context ) | |||||
| throws ConfigurationException | throws ConfigurationException | ||||
| { | { | ||||
| configureAttribute( object, name, value, context ); | |||||
| if( DEBUG ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "configure-content.notice", content ); | |||||
| getLogger().debug( message ); | |||||
| } | |||||
| // Set the content | |||||
| final AttributeSetter setter = configurer.getContentSetter(); | |||||
| if( null == setter ) | |||||
| { | |||||
| final String message = REZ.getString( "content-not-supported.error" ); | |||||
| throw new ConfigurationException( message ); | |||||
| } | |||||
| try | |||||
| { | |||||
| setValue( setter, object, content, context ); | |||||
| } | |||||
| catch( final Exception e ) | |||||
| { | |||||
| final String message = REZ.getString( "bad-set-content.error" ); | |||||
| throw new ConfigurationException( message, e ); | |||||
| } | |||||
| } | } | ||||
| /** | /** | ||||
| * Try to configure content of an object. | |||||
| * | |||||
| * @param object the object | |||||
| * @param content the content value to be set | |||||
| * @param context the Context | |||||
| * @exception ConfigurationException if an error occurs | |||||
| * Creates and configures a nested element | |||||
| */ | */ | ||||
| private void configureContent( final Object object, | |||||
| final String content, | |||||
| private void configureElement( final ObjectConfigurer configurer, | |||||
| final Object object, | |||||
| final Configuration childConfig, | |||||
| final Context context ) | final Context context ) | ||||
| throws ConfigurationException | throws ConfigurationException | ||||
| { | { | ||||
| setValue( object, "addContent", content, context ); | |||||
| } | |||||
| final String childName = childConfig.getName(); | |||||
| private void configureAttribute( final Object object, | |||||
| final String name, | |||||
| final String value, | |||||
| final Context context ) | |||||
| throws ConfigurationException | |||||
| { | |||||
| final String methodName = getMethodNameFor( name ); | |||||
| setValue( object, methodName, value, context ); | |||||
| } | |||||
| private void setValue( final Object object, | |||||
| final String methodName, | |||||
| final String value, | |||||
| final Context context ) | |||||
| throws ConfigurationException | |||||
| { | |||||
| // OMFG the rest of this is soooooooooooooooooooooooooooooooo | |||||
| // slow. Need to cache results per class etc. | |||||
| final Class clazz = object.getClass(); | |||||
| final Method[] methods = getMethodsFor( clazz, methodName ); | |||||
| if( 0 == methods.length ) | |||||
| if( DEBUG ) | |||||
| { | { | ||||
| final String message = | final String message = | ||||
| REZ.getString( "no-attribute-method.error", methodName ); | |||||
| throw new ConfigurationException( message ); | |||||
| REZ.getString( "configure-subelement.notice", childName ); | |||||
| getLogger().debug( message ); | |||||
| } | } | ||||
| setValue( object, value, context, methods ); | |||||
| } | |||||
| // Locate the configurer for the child element | |||||
| final ElementConfigurer childConfigurer = configurer.getElement( childName ); | |||||
| if( null == childConfigurer ) | |||||
| { | |||||
| final String message = REZ.getString( "unknown-subelement.error", childName ); | |||||
| throw new ConfigurationException( message ); | |||||
| } | |||||
| private void setValue( final Object object, | |||||
| final String value, | |||||
| final Context context, | |||||
| final Method methods[] ) | |||||
| throws ConfigurationException | |||||
| { | |||||
| try | try | ||||
| { | { | ||||
| final Object objectValue = | |||||
| PropertyUtil.resolveProperty( value, context, false ); | |||||
| // Create the child element | |||||
| final Object child = childConfigurer.createElement( object ); | |||||
| setValue( object, objectValue, methods, context ); | |||||
| // Configure the child element | |||||
| configure( child, childConfig, context ); | |||||
| // Set the child element | |||||
| childConfigurer.addElement( object, child ); | |||||
| } | } | ||||
| catch( final PropertyException pe ) | |||||
| catch( final ConfigurationException ce ) | |||||
| { | { | ||||
| final String message = | final String message = | ||||
| REZ.getString( "bad-property-resolve.error", value ); | |||||
| throw new ConfigurationException( message, pe ); | |||||
| REZ.getString( "bad-configure-subelement.error", childName ); | |||||
| throw new ConfigurationException( message, ce ); | |||||
| } | } | ||||
| } | } | ||||
| private void setValue( final Object object, | |||||
| Object value, | |||||
| final Method methods[], | |||||
| /** | |||||
| * Configure named attribute of object in a particular context. | |||||
| * This configuring can be done in different ways for different | |||||
| * configurers. | |||||
| * | |||||
| * @param object the object | |||||
| * @param name the attribute name | |||||
| * @param value the attribute value | |||||
| * @param context the Context | |||||
| * @exception ConfigurationException if an error occurs | |||||
| */ | |||||
| public void configure( final Object object, | |||||
| final String name, | |||||
| final String value, | |||||
| final Context context ) | final Context context ) | ||||
| throws ConfigurationException | throws ConfigurationException | ||||
| { | { | ||||
| final Class sourceClass = value.getClass(); | |||||
| final String source = sourceClass.getName(); | |||||
| // Locate the configurer for this object | |||||
| final ObjectConfigurer configurer = getConfigurer( object.getClass() ); | |||||
| for( int i = 0; i < methods.length; i++ ) | |||||
| { | |||||
| if( setValue( object, value, methods[ i ], sourceClass, source, context ) ) | |||||
| { | |||||
| return; | |||||
| } | |||||
| } | |||||
| final String message = | |||||
| REZ.getString( "no-can-convert.error", methods[ 0 ].getName(), source ); | |||||
| throw new ConfigurationException( message ); | |||||
| // Set the attribute value | |||||
| setAttribute( configurer, object, name, value, context ); | |||||
| } | } | ||||
| private boolean setValue( final Object object, | |||||
| Object value, | |||||
| final Method method, | |||||
| final Class sourceClass, | |||||
| final String source, | |||||
| final Context context ) | |||||
| /** | |||||
| * Sets an attribute value. | |||||
| */ | |||||
| private void setAttribute( final ObjectConfigurer configurer, | |||||
| final Object object, | |||||
| final String name, | |||||
| final String value, | |||||
| final Context context ) | |||||
| throws ConfigurationException | throws ConfigurationException | ||||
| { | { | ||||
| Class parameterType = method.getParameterTypes()[ 0 ]; | |||||
| if( parameterType.isPrimitive() ) | |||||
| { | |||||
| parameterType = getComplexTypeFor( parameterType ); | |||||
| } | |||||
| try | |||||
| if( DEBUG ) | |||||
| { | { | ||||
| value = m_converter.convert( parameterType, value, context ); | |||||
| final String message = REZ.getString( "configure-attribute.notice", | |||||
| name, | |||||
| value ); | |||||
| getLogger().debug( message ); | |||||
| } | } | ||||
| catch( final ConverterException ce ) | |||||
| { | |||||
| if( DEBUG ) | |||||
| { | |||||
| final String message = REZ.getString( "no-converter.error" ); | |||||
| getLogger().debug( message, ce ); | |||||
| } | |||||
| throw new ConfigurationException( ce.getMessage(), ce ); | |||||
| } | |||||
| catch( final Exception e ) | |||||
| // Locate the setter for this attribute | |||||
| final AttributeSetter setter = configurer.getAttributeSetter( name ); | |||||
| if( null == setter ) | |||||
| { | { | ||||
| final String message = | |||||
| REZ.getString( "bad-convert-for-attribute.error", method.getName() ); | |||||
| throw new ConfigurationException( message, e ); | |||||
| } | |||||
| if( null == value ) | |||||
| { | |||||
| return false; | |||||
| final String message = REZ.getString( "unknown-attribute.error", name ); | |||||
| throw new ConfigurationException( message ); | |||||
| } | } | ||||
| // Set the value | |||||
| try | try | ||||
| { | { | ||||
| method.invoke( object, new Object[]{value} ); | |||||
| } | |||||
| catch( final IllegalAccessException iae ) | |||||
| { | |||||
| //should never happen .... | |||||
| final String message = REZ.getString( "illegal-access.error" ); | |||||
| throw new ConfigurationException( message, iae ); | |||||
| } | |||||
| catch( final InvocationTargetException ite ) | |||||
| { | |||||
| final String message = REZ.getString( "invoke-target.error", method.getName() ); | |||||
| throw new ConfigurationException( message, ite ); | |||||
| setValue( setter, object, value, context ); | |||||
| } | } | ||||
| return true; | |||||
| } | |||||
| private Class getComplexTypeFor( final Class clazz ) | |||||
| { | |||||
| if( String.class == clazz ) | |||||
| return String.class; | |||||
| else if( Integer.TYPE.equals( clazz ) ) | |||||
| return Integer.class; | |||||
| else if( Long.TYPE.equals( clazz ) ) | |||||
| return Long.class; | |||||
| else if( Short.TYPE.equals( clazz ) ) | |||||
| return Short.class; | |||||
| else if( Byte.TYPE.equals( clazz ) ) | |||||
| return Byte.class; | |||||
| else if( Boolean.TYPE.equals( clazz ) ) | |||||
| return Boolean.class; | |||||
| else if( Float.TYPE.equals( clazz ) ) | |||||
| return Float.class; | |||||
| else if( Double.TYPE.equals( clazz ) ) | |||||
| return Double.class; | |||||
| else | |||||
| catch( final Exception e ) | |||||
| { | { | ||||
| final String message = REZ.getString( "no-complex-type.error", clazz.getName() ); | |||||
| throw new IllegalArgumentException( message ); | |||||
| final String message = REZ.getString( "bad-set-attribute.error", name ); | |||||
| throw new ConfigurationException( message, e ); | |||||
| } | } | ||||
| } | } | ||||
| private Method[] getMethodsFor( final Class clazz, final String methodName ) | |||||
| /** | |||||
| * Sets an attribute value, or an element's text content. | |||||
| */ | |||||
| private void setValue( final AttributeSetter setter, | |||||
| final Object object, | |||||
| final String value, | |||||
| final Context context ) | |||||
| throws Exception | |||||
| { | { | ||||
| final Method methods[] = clazz.getMethods(); | |||||
| final ArrayList matches = new ArrayList(); | |||||
| // Resolve property references in the attribute value | |||||
| Object objValue = PropertyUtil.resolveProperty( value, context, false ); | |||||
| for( int i = 0; i < methods.length; i++ ) | |||||
| // Convert the value to the appropriate type | |||||
| Class clazz = setter.getType(); | |||||
| if( clazz.isPrimitive() ) | |||||
| { | { | ||||
| final Method method = methods[ i ]; | |||||
| if( methodName.equals( method.getName() ) && | |||||
| Method.PUBLIC == ( method.getModifiers() & Method.PUBLIC ) ) | |||||
| { | |||||
| if( method.getReturnType().equals( Void.TYPE ) ) | |||||
| { | |||||
| final Class parameters[] = method.getParameterTypes(); | |||||
| if( 1 == parameters.length ) | |||||
| { | |||||
| matches.add( method ); | |||||
| } | |||||
| } | |||||
| } | |||||
| clazz = getComplexTypeFor( clazz ); | |||||
| } | } | ||||
| return (Method[])matches.toArray( new Method[ 0 ] ); | |||||
| objValue = m_converter.convert( clazz, objValue, context ); | |||||
| // Set the value | |||||
| setter.setAttribute( object, objValue ); | |||||
| } | } | ||||
| private Method[] getCreateMethodsFor( final Class clazz, final String methodName ) | |||||
| /** | |||||
| * Locates the configurer for a particular class. | |||||
| */ | |||||
| private ObjectConfigurer getConfigurer( final Class clazz ) | |||||
| throws ConfigurationException | |||||
| { | { | ||||
| final Method methods[] = clazz.getMethods(); | |||||
| final ArrayList matches = new ArrayList(); | |||||
| for( int i = 0; i < methods.length; i++ ) | |||||
| ObjectConfigurer configurer = | |||||
| (ObjectConfigurer)m_configurerCache.get( clazz ); | |||||
| if( null == configurer ) | |||||
| { | { | ||||
| final Method method = methods[ i ]; | |||||
| if( methodName.equals( method.getName() ) && | |||||
| Method.PUBLIC == ( method.getModifiers() & Method.PUBLIC ) ) | |||||
| { | |||||
| final Class returnType = method.getReturnType(); | |||||
| if( !returnType.equals( Void.TYPE ) && | |||||
| !returnType.isPrimitive() ) | |||||
| { | |||||
| final Class parameters[] = method.getParameterTypes(); | |||||
| if( 0 == parameters.length ) | |||||
| { | |||||
| matches.add( method ); | |||||
| } | |||||
| } | |||||
| } | |||||
| configurer = DefaultObjectConfigurer.getConfigurer( clazz ); | |||||
| m_configurerCache.put( clazz, configurer ); | |||||
| } | } | ||||
| return (Method[])matches.toArray( new Method[ 0 ] ); | |||||
| } | |||||
| private String getMethodNameFor( final String attribute ) | |||||
| { | |||||
| return "set" + getJavaNameFor( attribute.toLowerCase() ); | |||||
| return configurer; | |||||
| } | } | ||||
| private String getJavaNameFor( final String name ) | |||||
| private Class getComplexTypeFor( final Class clazz ) | |||||
| { | { | ||||
| final StringBuffer sb = new StringBuffer(); | |||||
| int index = name.indexOf( '-' ); | |||||
| int last = 0; | |||||
| while( -1 != index ) | |||||
| if( String.class == clazz ) | |||||
| { | { | ||||
| final String word = name.substring( last, index ).toLowerCase(); | |||||
| sb.append( Character.toUpperCase( word.charAt( 0 ) ) ); | |||||
| sb.append( word.substring( 1, word.length() ) ); | |||||
| last = index + 1; | |||||
| index = name.indexOf( '-', last ); | |||||
| return String.class; | |||||
| } | } | ||||
| index = name.length(); | |||||
| final String word = name.substring( last, index ).toLowerCase(); | |||||
| sb.append( Character.toUpperCase( word.charAt( 0 ) ) ); | |||||
| sb.append( word.substring( 1, word.length() ) ); | |||||
| return sb.toString(); | |||||
| } | |||||
| private void configureElement( final Object object, | |||||
| final Configuration configuration, | |||||
| final Context context ) | |||||
| throws ConfigurationException | |||||
| { | |||||
| final String name = configuration.getName(); | |||||
| final String javaName = getJavaNameFor( name ); | |||||
| // OMFG the rest of this is soooooooooooooooooooooooooooooooo | |||||
| // slow. Need to cache results per class etc. | |||||
| final Class clazz = object.getClass(); | |||||
| Method methods[] = getMethodsFor( clazz, "add" + javaName ); | |||||
| if( 0 != methods.length ) | |||||
| else if( Integer.TYPE.equals( clazz ) ) | |||||
| { | { | ||||
| //guess it is first method ???? | |||||
| addElement( object, methods[ 0 ], configuration, context ); | |||||
| return Integer.class; | |||||
| } | } | ||||
| else | |||||
| else if( Long.TYPE.equals( clazz ) ) | |||||
| { | { | ||||
| methods = getCreateMethodsFor( clazz, "create" + javaName ); | |||||
| if( 0 == methods.length ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "no-element-method.error", javaName ); | |||||
| throw new ConfigurationException( message ); | |||||
| } | |||||
| //guess it is first method ???? | |||||
| createElement( object, methods[ 0 ], configuration, context ); | |||||
| return Long.class; | |||||
| } | } | ||||
| } | |||||
| private void createElement( final Object object, | |||||
| final Method method, | |||||
| final Configuration configuration, | |||||
| final Context context ) | |||||
| throws ConfigurationException | |||||
| { | |||||
| try | |||||
| else if( Short.TYPE.equals( clazz ) ) | |||||
| { | { | ||||
| final Object created = method.invoke( object, new Object[ 0 ] ); | |||||
| configure( created, configuration, context ); | |||||
| return Short.class; | |||||
| } | } | ||||
| catch( final ConfigurationException ce ) | |||||
| else if( Byte.TYPE.equals( clazz ) ) | |||||
| { | { | ||||
| throw ce; | |||||
| return Byte.class; | |||||
| } | } | ||||
| catch( final Exception e ) | |||||
| else if( Boolean.TYPE.equals( clazz ) ) | |||||
| { | { | ||||
| final String message = REZ.getString( "subelement-create.error" ); | |||||
| throw new ConfigurationException( message, e ); | |||||
| return Boolean.class; | |||||
| } | } | ||||
| } | |||||
| private void addElement( final Object object, | |||||
| final Method method, | |||||
| final Configuration configuration, | |||||
| final Context context ) | |||||
| throws ConfigurationException | |||||
| { | |||||
| try | |||||
| else if( Float.TYPE.equals( clazz ) ) | |||||
| { | { | ||||
| final Class clazz = method.getParameterTypes()[ 0 ]; | |||||
| final Object created = clazz.newInstance(); | |||||
| configure( created, configuration, context ); | |||||
| method.invoke( object, new Object[]{created} ); | |||||
| return Float.class; | |||||
| } | } | ||||
| catch( final ConfigurationException ce ) | |||||
| else if( Double.TYPE.equals( clazz ) ) | |||||
| { | { | ||||
| throw ce; | |||||
| return Double.class; | |||||
| } | } | ||||
| catch( final Exception e ) | |||||
| else | |||||
| { | { | ||||
| final String message = REZ.getString( "subelement-create.error" ); | |||||
| throw new ConfigurationException( message, e ); | |||||
| final String message = REZ.getString( "no-complex-type.error", clazz.getName() ); | |||||
| throw new IllegalArgumentException( message ); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -0,0 +1,101 @@ | |||||
| /* | |||||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
| * | |||||
| * This software is published under the terms of the Apache Software License | |||||
| * version 1.1, a copy of which has been included with this distribution in | |||||
| * the LICENSE.txt file. | |||||
| */ | |||||
| package org.apache.myrmidon.components.configurer; | |||||
| import java.lang.reflect.InvocationTargetException; | |||||
| import java.lang.reflect.Method; | |||||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
| import org.apache.avalon.excalibur.i18n.Resources; | |||||
| import org.apache.avalon.framework.configuration.ConfigurationException; | |||||
| /** | |||||
| * The default element configurer implementation, which uses reflection to | |||||
| * create and/or add nested elements. | |||||
| * | |||||
| * @author <a href="mailto:adammurdoch_ml@yahoo.com">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| class DefaultElementConfigurer | |||||
| implements ElementConfigurer | |||||
| { | |||||
| private static final Resources REZ = | |||||
| ResourceManager.getPackageResources( DefaultElementConfigurer.class ); | |||||
| private final Class m_type; | |||||
| private final Method m_createMethod; | |||||
| private final Method m_addMethod; | |||||
| public DefaultElementConfigurer( final Class type, | |||||
| final Method createMethod, | |||||
| final Method addMethod ) | |||||
| { | |||||
| m_type = type; | |||||
| m_createMethod = createMethod; | |||||
| m_addMethod = addMethod; | |||||
| } | |||||
| /** | |||||
| * Returns the type of the element. | |||||
| */ | |||||
| public Class getType() | |||||
| { | |||||
| return m_type; | |||||
| } | |||||
| /** | |||||
| * Creates a nested element. | |||||
| */ | |||||
| public Object createElement( final Object parent ) | |||||
| throws ConfigurationException | |||||
| { | |||||
| try | |||||
| { | |||||
| if( null != m_createMethod ) | |||||
| { | |||||
| return m_createMethod.invoke( parent, null ); | |||||
| } | |||||
| else | |||||
| { | |||||
| return m_type.newInstance(); | |||||
| } | |||||
| } | |||||
| catch( final InvocationTargetException ite ) | |||||
| { | |||||
| final Throwable cause = ite.getTargetException(); | |||||
| throw new ConfigurationException( cause.getMessage(), cause ); | |||||
| } | |||||
| catch( final Exception e ) | |||||
| { | |||||
| throw new ConfigurationException( e.getMessage(), e ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Sets the nested element, after it has been configured. | |||||
| */ | |||||
| public void addElement( final Object parent, final Object child ) | |||||
| throws ConfigurationException | |||||
| { | |||||
| try | |||||
| { | |||||
| if( null != m_addMethod ) | |||||
| { | |||||
| m_addMethod.invoke( parent, new Object[]{child} ); | |||||
| } | |||||
| } | |||||
| catch( final InvocationTargetException ite ) | |||||
| { | |||||
| final Throwable cause = ite.getTargetException(); | |||||
| throw new ConfigurationException( cause.getMessage(), cause ); | |||||
| } | |||||
| catch( final Exception e ) | |||||
| { | |||||
| throw new ConfigurationException( e.getMessage(), e ); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,380 @@ | |||||
| /* | |||||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
| * | |||||
| * This software is published under the terms of the Apache Software License | |||||
| * version 1.1, a copy of which has been included with this distribution in | |||||
| * the LICENSE.txt file. | |||||
| */ | |||||
| package org.apache.myrmidon.components.configurer; | |||||
| import java.lang.reflect.Method; | |||||
| import java.lang.reflect.Modifier; | |||||
| import java.util.ArrayList; | |||||
| import java.util.Collection; | |||||
| import java.util.HashMap; | |||||
| import java.util.HashSet; | |||||
| import java.util.Iterator; | |||||
| import java.util.List; | |||||
| import java.util.Map; | |||||
| import java.util.Set; | |||||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
| import org.apache.avalon.excalibur.i18n.Resources; | |||||
| import org.apache.avalon.framework.configuration.ConfigurationException; | |||||
| /** | |||||
| * An object configurer which uses reflection to determine the attributes | |||||
| * and elements of a class. | |||||
| * | |||||
| * @author <a href="mailto:adammurdoch_ml@yahoo.com">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public class DefaultObjectConfigurer | |||||
| implements ObjectConfigurer | |||||
| { | |||||
| private static final Resources REZ = | |||||
| ResourceManager.getPackageResources( DefaultObjectConfigurer.class ); | |||||
| private final Class m_class; | |||||
| /** | |||||
| * Map from lowercase attribute name -> AttributeSetter. | |||||
| */ | |||||
| private final Map m_attrs = new HashMap(); | |||||
| /** | |||||
| * Map from lowercase element name -> ElementSetter. | |||||
| */ | |||||
| private final Map m_elements = new HashMap(); | |||||
| /** | |||||
| * Content setter. | |||||
| */ | |||||
| private AttributeSetter m_contentSetter; | |||||
| /** | |||||
| * Creates an object configurer for a particular class. The newly | |||||
| * created configurer will not handle any attributes, elements, or content. | |||||
| * Use the various <code>enable</code> methods to enable handling of these. | |||||
| */ | |||||
| public DefaultObjectConfigurer( final Class classInfo ) | |||||
| { | |||||
| m_class = classInfo; | |||||
| } | |||||
| /** | |||||
| * Enables all attributes, elements and content handling. | |||||
| */ | |||||
| public void enableAll() | |||||
| throws ConfigurationException | |||||
| { | |||||
| enableAttributes(); | |||||
| enableElements(); | |||||
| enableContent(); | |||||
| } | |||||
| /** | |||||
| * Enables all attributes. | |||||
| */ | |||||
| public void enableAttributes() | |||||
| throws ConfigurationException | |||||
| { | |||||
| // Find all 'set' methods which take a single parameter, and return void. | |||||
| final List methods = new ArrayList(); | |||||
| findMethodsWithPrefix( "set", methods ); | |||||
| final Iterator iterator = methods.iterator(); | |||||
| while( iterator.hasNext() ) | |||||
| { | |||||
| final Method method = (Method)iterator.next(); | |||||
| if( method.getReturnType() != Void.TYPE || | |||||
| method.getParameterTypes().length != 1 ) | |||||
| { | |||||
| continue; | |||||
| } | |||||
| // Extract the attribute name | |||||
| final String attrName = extractName( "set", method.getName() ); | |||||
| // Enable the attribute | |||||
| enableAttribute( attrName, method ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Enables all elements. | |||||
| */ | |||||
| public void enableElements() | |||||
| throws ConfigurationException | |||||
| { | |||||
| final Map creators = findCreators(); | |||||
| final Map adders = findAdders(); | |||||
| // Add the elements | |||||
| final Set elemNames = new HashSet(); | |||||
| elemNames.addAll( creators.keySet() ); | |||||
| elemNames.addAll( adders.keySet() ); | |||||
| final Iterator iterator = elemNames.iterator(); | |||||
| while( iterator.hasNext() ) | |||||
| { | |||||
| final String elemName = (String)iterator.next(); | |||||
| final Method createMethod = (Method)creators.get( elemName ); | |||||
| final Method addMethod = (Method)adders.get( elemName ); | |||||
| // Determine and check the return type | |||||
| Class type; | |||||
| if( createMethod != null && addMethod != null ) | |||||
| { | |||||
| // Make sure the add method is more general than the create | |||||
| // method | |||||
| type = createMethod.getReturnType(); | |||||
| final Class addType = addMethod.getParameterTypes()[ 0 ]; | |||||
| if( !addType.isAssignableFrom( type ) ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "incompatible-element-types.error", | |||||
| elemName, | |||||
| m_class.getName() ); | |||||
| throw new ConfigurationException( message ); | |||||
| } | |||||
| } | |||||
| else if( createMethod != null ) | |||||
| { | |||||
| type = createMethod.getReturnType(); | |||||
| } | |||||
| else | |||||
| { | |||||
| type = addMethod.getParameterTypes()[ 0 ]; | |||||
| } | |||||
| final DefaultElementConfigurer configurer = | |||||
| new DefaultElementConfigurer( type, createMethod, addMethod ); | |||||
| m_elements.put( elemName, configurer ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Locate all 'add' methods which return void, and take a non-primitive type | |||||
| */ | |||||
| private Map findAdders() | |||||
| throws ConfigurationException | |||||
| { | |||||
| final Map adders = new HashMap(); | |||||
| final List methodSet = new ArrayList(); | |||||
| findMethodsWithPrefix( "add", methodSet ); | |||||
| final Iterator iterator = methodSet.iterator(); | |||||
| while( iterator.hasNext() ) | |||||
| { | |||||
| final Method method = (Method)iterator.next(); | |||||
| final String methodName = method.getName(); | |||||
| if( method.getReturnType() != Void.TYPE || | |||||
| method.getParameterTypes().length != 1 || | |||||
| method.getParameterTypes()[ 0 ].isPrimitive() ) | |||||
| { | |||||
| continue; | |||||
| } | |||||
| // TODO - un-hard-code this | |||||
| if( methodName.equals( "addContent" ) ) | |||||
| { | |||||
| continue; | |||||
| } | |||||
| // Extract element name | |||||
| final String elemName = extractName( "add", methodName ); | |||||
| // Add to the adders map | |||||
| if( adders.containsKey( elemName ) ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "multiple-adder-methods-for-element.error", | |||||
| m_class.getName(), | |||||
| elemName ); | |||||
| throw new ConfigurationException( message ); | |||||
| } | |||||
| adders.put( elemName, method ); | |||||
| } | |||||
| return adders; | |||||
| } | |||||
| /** | |||||
| * Find all 'create' methods, which return a non-primitive type, | |||||
| * and take no parameters. | |||||
| */ | |||||
| private Map findCreators() | |||||
| throws ConfigurationException | |||||
| { | |||||
| final Map creators = new HashMap(); | |||||
| final List methodSet = new ArrayList(); | |||||
| findMethodsWithPrefix( "create", methodSet ); | |||||
| final Iterator iterator = methodSet.iterator(); | |||||
| while( iterator.hasNext() ) | |||||
| { | |||||
| final Method method = (Method)iterator.next(); | |||||
| final String methodName = method.getName(); | |||||
| if( method.getReturnType().isPrimitive() || | |||||
| method.getParameterTypes().length != 0 ) | |||||
| { | |||||
| continue; | |||||
| } | |||||
| // Extract element name | |||||
| final String elemName = extractName( "create", methodName ); | |||||
| // Add to the creators map | |||||
| if( creators.containsKey( elemName ) ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "multiple-creator-methods-for-element.error", | |||||
| m_class.getName(), | |||||
| elemName ); | |||||
| throw new ConfigurationException( message ); | |||||
| } | |||||
| creators.put( elemName, method ); | |||||
| } | |||||
| return creators; | |||||
| } | |||||
| /** | |||||
| * Enables content. | |||||
| */ | |||||
| public void enableContent() | |||||
| throws ConfigurationException | |||||
| { | |||||
| // Locate any 'addContent' methods, which return void, and take | |||||
| // a single parameter. | |||||
| final Method[] methods = m_class.getMethods(); | |||||
| for( int i = 0; i < methods.length; i++ ) | |||||
| { | |||||
| final Method method = methods[ i ]; | |||||
| final String methodName = method.getName(); | |||||
| if( Modifier.isStatic( method.getModifiers() ) || | |||||
| !methodName.equals( "addContent" ) || | |||||
| method.getReturnType() != Void.TYPE || | |||||
| method.getParameterTypes().length != 1 ) | |||||
| { | |||||
| continue; | |||||
| } | |||||
| if( null != m_contentSetter ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "multiple-content-setter-methods.error", m_class.getName() ); | |||||
| throw new ConfigurationException( message ); | |||||
| } | |||||
| m_contentSetter = new DefaultAttributeSetter( method ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Locates the configurer for a particular class. | |||||
| */ | |||||
| public static ObjectConfigurer getConfigurer( final Class classInfo ) | |||||
| throws ConfigurationException | |||||
| { | |||||
| final DefaultObjectConfigurer configurer = new DefaultObjectConfigurer( classInfo ); | |||||
| configurer.enableAll(); | |||||
| return configurer; | |||||
| } | |||||
| /** | |||||
| * Returns the class. | |||||
| */ | |||||
| public Class getType() | |||||
| { | |||||
| return m_class; | |||||
| } | |||||
| /** | |||||
| * Returns a configurer for an attribute of this class. | |||||
| */ | |||||
| public AttributeSetter getAttributeSetter( final String name ) | |||||
| { | |||||
| return (AttributeSetter)m_attrs.get( name ); | |||||
| } | |||||
| /** | |||||
| * Returns a configurer for an element of this class. | |||||
| */ | |||||
| public ElementConfigurer getElement( final String name ) | |||||
| { | |||||
| return (ElementConfigurer)m_elements.get( name ); | |||||
| } | |||||
| /** | |||||
| * Returns a configurer for the content of this class. | |||||
| */ | |||||
| public AttributeSetter getContentSetter() | |||||
| { | |||||
| return m_contentSetter; | |||||
| } | |||||
| /** | |||||
| * Enables an attribute. | |||||
| */ | |||||
| private void enableAttribute( final String attrName, | |||||
| final Method method ) | |||||
| throws ConfigurationException | |||||
| { | |||||
| if( m_attrs.containsKey( attrName ) ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "multiple-setter-methods-for-attribute.error", | |||||
| m_class.getName(), | |||||
| attrName ); | |||||
| throw new ConfigurationException( message ); | |||||
| } | |||||
| final DefaultAttributeSetter setter = new DefaultAttributeSetter( method ); | |||||
| m_attrs.put( attrName, setter ); | |||||
| } | |||||
| /** | |||||
| * Extracts an attribute/element name from a Java method name. | |||||
| * Removes the prefix, inserts '-' before each uppercase character | |||||
| * (except the first), then converts all to lowercase. | |||||
| */ | |||||
| private String extractName( final String prefix, final String methodName ) | |||||
| { | |||||
| final StringBuffer sb = new StringBuffer( methodName ); | |||||
| sb.delete( 0, prefix.length() ); | |||||
| for( int i = 0; i < sb.length(); i++ ) | |||||
| { | |||||
| char ch = sb.charAt( i ); | |||||
| if( Character.isUpperCase( ch ) ) | |||||
| { | |||||
| if( i > 0 ) | |||||
| { | |||||
| sb.insert( i, '-' ); | |||||
| i++; | |||||
| } | |||||
| sb.setCharAt( i, Character.toLowerCase( ch ) ); | |||||
| } | |||||
| } | |||||
| return sb.toString(); | |||||
| } | |||||
| /** | |||||
| * Locates all non-static methods whose name starts with a particular | |||||
| * prefix. | |||||
| */ | |||||
| private void findMethodsWithPrefix( final String prefix, final Collection matches ) | |||||
| { | |||||
| final int prefixLen = prefix.length(); | |||||
| final Method[] methods = m_class.getMethods(); | |||||
| for( int i = 0; i < methods.length; i++ ) | |||||
| { | |||||
| final Method method = methods[ i ]; | |||||
| final String methodName = method.getName(); | |||||
| if( Modifier.isStatic( method.getModifiers() ) || | |||||
| methodName.length() <= prefixLen || | |||||
| !methodName.startsWith( prefix ) ) | |||||
| { | |||||
| continue; | |||||
| } | |||||
| matches.add( method ); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,47 @@ | |||||
| /* | |||||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
| * | |||||
| * This software is published under the terms of the Apache Software License | |||||
| * version 1.1, a copy of which has been included with this distribution in | |||||
| * the LICENSE.txt file. | |||||
| */ | |||||
| package org.apache.myrmidon.components.configurer; | |||||
| import org.apache.avalon.framework.configuration.ConfigurationException; | |||||
| /** | |||||
| * Configures an element of an object. | |||||
| * | |||||
| * @author <a href="mailto:adammurdoch_ml@yahoo.com">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public interface ElementConfigurer | |||||
| { | |||||
| /** | |||||
| * Returns the type of the element. | |||||
| */ | |||||
| Class getType(); | |||||
| /** | |||||
| * Creates an object for an element. | |||||
| * | |||||
| * @param parent The parent object. | |||||
| * @return An object which is assignable to the type returned by | |||||
| * {@link #getType}. | |||||
| * @throws ConfigurationException If the object cannot be created. | |||||
| */ | |||||
| Object createElement( Object parent ) | |||||
| throws ConfigurationException; | |||||
| /** | |||||
| * Attaches an element object to its parent, after it has been configured. | |||||
| * | |||||
| * @param parent The parent object. | |||||
| * | |||||
| * @param child The element object. This must be assignable to the type | |||||
| * returned by {@link #getType}. | |||||
| * @throws ConfigurationException If the object cannot be attached. | |||||
| */ | |||||
| void addElement( Object parent, Object child ) | |||||
| throws ConfigurationException; | |||||
| } | |||||
| @@ -0,0 +1,48 @@ | |||||
| /* | |||||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
| * | |||||
| * This software is published under the terms of the Apache Software License | |||||
| * version 1.1, a copy of which has been included with this distribution in | |||||
| * the LICENSE.txt file. | |||||
| */ | |||||
| package org.apache.myrmidon.components.configurer; | |||||
| /** | |||||
| * Configures objects of a particular class. | |||||
| * | |||||
| * @author <a href="mailto:adammurdoch_ml@yahoo.com">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public interface ObjectConfigurer | |||||
| { | |||||
| /** | |||||
| * Returns the class. | |||||
| */ | |||||
| Class getType(); | |||||
| /** | |||||
| * Returns a configurer for an attribute of this class. | |||||
| * | |||||
| * @param name The attribute name. | |||||
| * @return A configurer for the attribute. Returns null if the attribute | |||||
| * is not valid for this class. | |||||
| */ | |||||
| AttributeSetter getAttributeSetter( String name ); | |||||
| /** | |||||
| * Returns a configurer for an element of this class. | |||||
| * | |||||
| * @param name The element name. | |||||
| * @return A configurer for the element. Returns null if the element | |||||
| * is not valid for this class. | |||||
| */ | |||||
| ElementConfigurer getElement( String name ); | |||||
| /** | |||||
| * Returns a configurer for the content of this class. | |||||
| * | |||||
| * @return A configurer for the content. Returns null if the class does | |||||
| * not allow text content. | |||||
| */ | |||||
| AttributeSetter getContentSetter(); | |||||
| } | |||||
| @@ -1,18 +1,20 @@ | |||||
| configuring-object.notice=Configuring {0}. | configuring-object.notice=Configuring {0}. | ||||
| configurable.notice=Configuring object via Configurable interface. | configurable.notice=Configuring object via Configurable interface. | ||||
| reflection.notice=Configuring object via Configurable reflection. | |||||
| configure-attribute.notice=Configuring attribute name={0} value={1}. | |||||
| configure-subelement.notice=Configuring subelement name={0}. | |||||
| configure-content.notice=Configuring content {0}. | |||||
| reflection.notice=Configuring object via ObjectConfigurer. | |||||
| configure-content.notice=Configuring content with "{0}". | |||||
| configure-subelement.notice=Configuring subelement "{0}". | |||||
| configure-attribute.notice=Configuring attribute name="{0}" value="{1}". | |||||
| reserved-attribute.error=Can not specify reserved attribute {0}. | |||||
| no-attribute-method.error=Unable to set attribute via {0} due to not finding any appropriate mutator method. | |||||
| bad-property-resolve.error=Error resolving property {0}. | |||||
| no-can-convert.error=Unable to set attribute via {0} as could not convert {1} to a matching type. | |||||
| no-converter.error=Failed to find converter. | |||||
| bad-convert-for-attribute.error=Error converting attribute for {0}. | |||||
| no-element-method.error=Unable to set element {0} due to not finding any appropriate mutator method. | |||||
| illegal-access.error=Error retrieving methods with correct access specifiers. | |||||
| invoke-target.error=Error calling method attribute {0}. | |||||
| content-not-supported.error=Text content is not supported for this element. | |||||
| bad-set-content.error=Could not set text content. | |||||
| unknown-subelement.error=Unknown element "{0}". | |||||
| bad-configure-subelement.error=Could not configure element "{0}". | |||||
| unknown-attribute.error=Unknown attribute "{0}". | |||||
| bad-set-attribute.error=Could not set attribute "{0}". | |||||
| no-complex-type.error=Can not get complex type for non-primitive type {0}. | no-complex-type.error=Can not get complex type for non-primitive type {0}. | ||||
| subelement-create.error=Error creating sub-element. | |||||
| multiple-creator-methods-for-element.error=Multiple creator methods found in class {0} for element "{0}". | |||||
| multiple-adder-methods-for-element.error=Multiple adder methods found in class {0} for element "{0}". | |||||
| incompatible-element-types.error=Incompatible creator and adder types for element "{0}" of class {1}. | |||||
| multiple-content-setter-methods.error=Multiple content setter methods found in class {0}. | |||||
| multiple-setter-methods-for-attribute.error=Multiple setter methods found in class {0} for attribute "{1}". | |||||