org.exolab.castor.mapping.loader.FieldHandlerImpl Maven / Gradle / Ivy
/**
* Redistribution and use of this software and associated documentation ("Software"), with or
* without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain copyright statements and notices. Redistributions
* must also contain a copy of this document.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials provided with
* the distribution.
*
* 3. The name "Exolab" must not be used to endorse or promote products derived from this Software
* without prior written permission of Intalio, Inc. For written permission, please contact
* [email protected].
*
* 4. Products derived from this Software may not be called "Exolab" nor may "Exolab" appear in
* their names without prior written permission of Intalio, Inc. Exolab is a registered trademark of
* Intalio, Inc.
*
* 5. Due credit should be given to the Exolab Project (http://www.exolab.org/).
*
* THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTALIO, INC. OR ITS
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Copyright 1999-2003 (C) Intalio, Inc. All Rights Reserved.
*
* $Id$
*/
package org.exolab.castor.mapping.loader;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.InvocationTargetException;
import java.util.Enumeration;
import java.util.Iterator;
import org.castor.core.util.Messages;
import org.exolab.castor.core.exceptions.CastorIllegalStateException;
import org.exolab.castor.mapping.AbstractFieldHandler;
import org.exolab.castor.mapping.ExtendedFieldHandler;
import org.exolab.castor.mapping.FieldDescriptor;
import org.exolab.castor.mapping.FieldHandler;
import org.exolab.castor.mapping.GeneralizedFieldHandler;
import org.exolab.castor.mapping.TypeConvertor;
import org.exolab.castor.mapping.CollectionHandler;
import org.exolab.castor.mapping.MappingException;
import org.exolab.castor.mapping.MappingRuntimeException;
import org.exolab.castor.util.IteratorEnumeration;
/**
* A field handler that knows how to get/set the values of a field directly or through the get/set
* methods. Uses reflection.
*
* Note: the field Java type is obtained from {@link TypeInfo#getFieldType()}, but if the field is a
* collection, the actual field/accessor type is obtained from {@link TypeInfo#getCollectionHandler}
* and the object to create (with {@link #newInstance(Object)}) is the former field type.
*
* @author Assaf Arkin
* @version $Revision$ $Date: 2006-04-25 15:08:23 -0600 (Tue, 25 Apr 2006) $
*/
public final class FieldHandlerImpl extends AbstractFieldHandler {
/**
* The prefix for an "add" method
**/
private static final String ADD_PREFIX = "add";
/**
* The prefix for an "enum" method
*/
private static final String ENUM_PREFIX = "enum";
/**
* The prefix for an "iter" method
*/
private static final String ITER_PREFIX = "iter";
/**
* The underlying field handler used by this handler.
*/
private final FieldHandler _handler;
/**
* The Java field described and accessed through this descriptor.
*/
private final Field _field;
/**
* The sequence of methods used to obtain the nested field. May be null.
*/
private Method[] _getSequence;
/**
* The sequence of methods used to create the nested object. May be null.
*/
private Method[] _setSequence;
/**
* The method used to "incrementally" set the value of this field. This is only used if the field
* is a collection
*/
private Method _addMethod;
/**
* The method used to enumerate entries of a container.
*/
private Method _enumMethod;
/**
* The method used to iterate over a container.
*/
private Method _iterMethod;
/**
* The method used to obtain the value of this field. May be null.
*/
private Method _getMethod;
/**
* The method used to set the value of this field. May be null.
*/
private Method _setMethod;
/**
* The method used to check if the value of this field exists. May be null.
*/
private Method _hasMethod;
/**
* The method used to delete the value of this field. May be null.
*/
private Method _deleteMethod;
/**
* The method used to create a new instance of the field.
*/
private Method _createMethod;
/**
* The Java field name.
*/
private final String _fieldName;
/**
* The Java field type.
*/
private final Class _fieldType;
/**
* True if this field is an immutable type.
*/
private final boolean _immutable;
/**
* The default value for primitive fields. Will be set if the field is null.
*/
private final Object _default;
/**
* Convertor to apply when setting the value of the field. Converts from the value to the field
* type. Null if no convertor is required.
*/
private TypeConvertor _convertTo = null;
/**
* Convertor to apply when reading the value of the field. Converts from the field type to the
* return value. Null if no convertor is required.
*/
private TypeConvertor _convertFrom = null;
/**
* The collection handler for multi valued fields.
*/
private final CollectionHandler _colHandler;
/**
* Construct a new field handler for the specified field. The field must be public, and may not be
* static or transient. The field name is determined from the Java field, the type from the type
* information.
*
* @param handler
* @param typeInfo Type information
*/
public FieldHandlerImpl(FieldHandler handler, TypeInfo typeInfo) {
_handler = handler;
_field = null;
_fieldName = handler.toString();
_fieldType = Types.typeFromPrimitive(typeInfo.getFieldType());
_immutable = typeInfo.isImmutable();
_default = typeInfo.getDefaultValue();
_convertTo = typeInfo.getConvertorTo();
_convertFrom = typeInfo.getConvertorFrom();
_colHandler = typeInfo.getCollectionHandler();
}
/**
* Construct a new field handler for the specified field. The field must be public, and may not be
* static or transient. The field name is determined from the Java field, the type from the type
* information.
*
* @param field The field being described
* @param typeInfo Type information
* @throws MappingException If the field is not public, is static or transient
*/
public FieldHandlerImpl(Field field, TypeInfo typeInfo) throws MappingException {
if (field.getModifiers() != Modifier.PUBLIC
&& field.getModifiers() != (Modifier.PUBLIC | Modifier.VOLATILE))
throw new MappingException("mapping.fieldNotAccessible", field.getName(),
field.getDeclaringClass().getName());
_handler = null;
_field = field;
_fieldType = Types.typeFromPrimitive(typeInfo.getFieldType());
_fieldName = field.getName() + "(" + field.getType().getName() + ")";
_immutable = typeInfo.isImmutable();
// If the field is of a primitive type or if it is required
// we use the default value
if (_field.getType().isPrimitive())
_default = typeInfo.getDefaultValue();
else
_default = null;
_convertTo = typeInfo.getConvertorTo();
_convertFrom = typeInfo.getConvertorFrom();
_colHandler = typeInfo.getCollectionHandler();
}
/**
* Construct a new field handler for the specified field that is accessed through the accessor
* methods (get/set). The accessor methods must be public and not static. The field name is
* required for descriptive purposes. The field type must match the return value of the get method
* and the single parameter of the set method. Either get or set methods are optional.
*
* @param fieldName The field being described
* @param getMethod The method used to retrieve the field value, must accept no parameters and
* have a return type castable to the field type
* @param setMethod The method used to set the field value, must accept a single parameter that is
* castable to the field type
* @param typeInfo Type information
* @throws MappingException If the get or set method are not public, are static, or do not specify
* the proper types
*
*/
public FieldHandlerImpl(String fieldName, Method[] getSequence, Method[] setSequence,
Method getMethod, Method setMethod, TypeInfo typeInfo) throws MappingException {
_handler = null;
_field = null;
if (fieldName == null)
throw new IllegalArgumentException("Argument 'fieldName' is null");
// Originally commented out by Oleg....not sure why?
// if ( getMethod == null && setMethod == null )
// throw new IllegalArgumentException(
// "Both arguments 'getMethod' and 'setMethod' are null" );
_getSequence = getSequence;
_setSequence = setSequence;
if (setMethod != null) {
// -- might be an "add" method
if (setMethod.getName().startsWith(ADD_PREFIX)) {
Class pType = setMethod.getParameterTypes()[0];
if (pType != typeInfo.getFieldType())
setAddMethod(setMethod);
else
setWriteMethod(setMethod);
}
// for(Iterator iter = setMethods.iterator(); iter.hasNext(); ) {
// Method method = (Method) iter.next();
//
// if (method.getName().startsWith(ADD_PREFIX)) {
// Class paraType = method.getParameterTypes()[0];
//
// if (paraType != typeInfo.getFieldType()) {
// addMethods.add(method);
// iter.remove();
// }
// }
// }
else
setWriteMethod(setMethod);
}
if (getMethod != null) {
// getMethod might be an enumeration or iteration.
if (getMethod.getName().startsWith(ENUM_PREFIX)) {
Class rType = getMethod.getReturnType();
// Check if getMethod really returns an enumeration.
if (Enumeration.class.isAssignableFrom(rType))
setEnumMethod(getMethod);
else
// If getMethod does not return an enumeration, treat it as a
// normal getMethod.
setReadMethod(getMethod);
} else if (getMethod.getName().startsWith(ITER_PREFIX)) {
Class rType = getMethod.getReturnType();
// Check if getMethod really returns an iterator.
if (Iterator.class.isAssignableFrom(rType))
setIterMethod(getMethod);
else
// If getMethod does not return an iterator, treat it as a normal
// getMethod.
setReadMethod(getMethod);
} else
setReadMethod(getMethod);
}
_fieldType = Types.typeFromPrimitive(typeInfo.getFieldType());
_fieldName = fieldName + "(" + _fieldType.getName() + ")";
_immutable = typeInfo.isImmutable();
// If the field is of a primitive type or if it is required
// we use the default value
if (setMethod != null && setMethod.getParameterTypes()[0].isPrimitive())
_default = typeInfo.getDefaultValue();
else
_default = null;
_convertTo = typeInfo.getConvertorTo();
_convertFrom = typeInfo.getConvertorFrom();
_colHandler = typeInfo.getCollectionHandler();
}
public TypeConvertor getConvertFrom() {
return _convertFrom;
}
public TypeConvertor getConvertTo() {
return _convertTo;
}
/**
* {@inheritDoc}
*
* @see org.exolab.castor.mapping.AbstractFieldHandler#getValue(java.lang.Object)
*/
@SuppressWarnings("unchecked")
public T getValue(Object object) {
T value;
try {
// If field is accessed directly, get its value. If not, we need to
// call
// its get method. It's possible to not have a way to access the field.
if (_handler != null) {
value = _handler.getValue(object);
} else if (_field != null) {
value = (T) _field.get(object);
} else if (_enumMethod != null) {
// If there is an enumeration method supplied, return the
// enumeration.
value = (T) _enumMethod.invoke(object, (Object[]) null);
} else if (_iterMethod != null) {
// If there is an iterator method supplied, wrap it in an
// enumeration.
value =
(T) new IteratorEnumeration((Iterator) _iterMethod.invoke(object, (Object[]) null));
} else if (_getMethod != null) {
if (_getSequence != null) {
for (int i = 0; i < _getSequence.length; i++) {
object = _getSequence[i].invoke(object, (Object[]) null);
if (object == null) {
break;
}
}
}
// Some of the objects in the sequence might be null, then the value
// is null.
// If field has 'has' method, false means field is null and do not
// attempt to
// call getValue. Otherwise, ????
if (object == null || (_hasMethod != null
&& !((Boolean) _hasMethod.invoke(object, (Object[]) null)).booleanValue())) {
value = null;
} else {
value = (T) _getMethod.invoke(object, (Object[]) null);
}
} else {
value = null;
}
} catch (IllegalAccessException except) {
throw new CastorIllegalStateException(
Messages.format("mapping.schemaChangeNoAccess", toString()), except);
} catch (InvocationTargetException except) {
throw new CastorIllegalStateException(
Messages.format("mapping.schemaChangeInvocation", toString(), except), except);
}
// -- If a collection, return an enumeration of it's values.
// -- Only use collection handler, if there is no convertor or enum
// method.
if (_colHandler != null && _enumMethod == null && _iterMethod == null && _convertFrom == null) {
if (value == null) {
return (T) new CollectionHandlers.EmptyEnumerator();
}
return (T) _colHandler.elements(value);
}
// If there is a convertor, apply it
if (_convertFrom == null || value == null) {
return value;
}
try {
return (T) _convertFrom.convert(value);
} catch (ClassCastException except) {
String errorMessage = Messages.format("mapping.wrongConvertor", value.getClass().getName());
throw new IllegalArgumentException(errorMessage, except);
}
}
/**
* {@inheritDoc}
*
* @see org.exolab.castor.mapping.AbstractFieldHandler#setValue(java.lang.Object,
* java.lang.Object)
*/
@SuppressWarnings("unchecked")
public void setValue(Object object, T value) {
if (_colHandler == null || _addMethod != null) {
// If there is a convertor, apply conversion here.
if (value != null && _convertTo != null) {
try {
value = (T) _convertTo.convert(value);
} catch (ClassCastException except) {
String errorMessage =
Messages.format("mapping.wrongConvertor", value.getClass().getName());
throw new IllegalArgumentException(errorMessage, except);
}
} else {
// -- unwrap MapItem if necessary
// if (_colHandler != null) {
// if ((value instanceof MapItem) && (_fieldType != MapItem.class))
// {
// value = ((MapItem)value).getValue();
// }
// }
}
try {
if (_handler != null) {
_handler.setValue(object, value);
} else if (_field != null) {
_field.set(object, value == null ? _default : value);
} else {
// -- either add or set
Method setter = selectWriteMethod(value);
if (setter != null) {
if (_getSequence != null) {
for (int i = 0; i < _getSequence.length; i++) {
Object last;
last = object;
object = _getSequence[i].invoke(object, (Object[]) null);
if (object == null) {
// if the value is not null, we must instantiate
// the object in the sequence
if (value == null || _setSequence[i] == null) {
break;
}
object = Types.newInstance(_getSequence[i].getReturnType());
_setSequence[i].invoke(last, new Object[] {object});
}
}
}
if (object != null) {
if (value == null && _deleteMethod != null) {
_deleteMethod.invoke(object, (Object[]) null);
} else {
setter.invoke(object, new Object[] {value == null ? _default : value});
}
}
}
}
// If the field has no set method, ignore it.
// If this is a problem, identity it someplace else.
} catch (IllegalArgumentException except) {
// Graceful way of dealing with unwrapping exception
if (value == null) {
String errorMessage = Messages.format("mapping.typeConversionNull", toString());
throw new IllegalArgumentException(errorMessage);
}
String errorMessage =
Messages.format("mapping.typeConversion", toString(), value.getClass().getName());
throw new IllegalArgumentException(errorMessage, except);
} catch (IllegalAccessException except) {
// This should never happen
String errorMessage = Messages.format("mapping.schemaChangeNoAccess", toString());
throw new CastorIllegalStateException(errorMessage, except);
} catch (InvocationTargetException except) {
// This should never happen
throw new MappingRuntimeException(except.getTargetException());
}
} else if (value != null) {
Object collect;
try {
// Get the field value (the collection), add the value to it,
// possibly yielding a new collection (in the case of an array),
// and set that collection back into the field.
if (_handler != null) {
collect = _handler.getValue(object);
collect = _colHandler.add(collect, value);
if (collect != null)
_handler.setValue(object, (T) collect);
} else if (_field != null) {
collect = _field.get(object);
if (collect == null) {
// The type of the collection.
Class type = _field.getType();
// -- Handle Arrays, we need to declare the array with
// -- the correct type. The other cases are handled in
// -- the J1CollectionHandler during the
// -- add(collect,value) call
if (type.isArray()) {
Class componentType = type.getComponentType();
Class valueType = value.getClass();
if (componentType.isPrimitive()
|| ((!valueType.isArray()) && (valueType != componentType))) {
try {
collect = Array.newInstance(componentType, 0);
} catch (Exception e) {
String err = "Unable to instantiate an array of '" + componentType + "' : " + e;
throw new CastorIllegalStateException(err, e);
}
}
}
}
collect = _colHandler.add(collect, value);
if (collect != null)
_field.set(object, collect);
} else if (_getMethod != null) {
if (_getSequence != null)
for (int i = 0; i < _getSequence.length; i++)
object = _getSequence[i].invoke(object, (Object[]) null);
collect = _getMethod.invoke(object, (Object[]) null);
// If we deal with a collection who is an array of primitive
// and that has not been instantiated, we have to handle the
// instantiation here rather than in J1CollectionHandler,
// because we have acces to the Field object here.
boolean setCollection = false;
if (collect == null) {
// The return type of the get method should be the type of the
// collection.
Class type = _getMethod.getReturnType();
// -- Handle Arrays, we need to declare the array with
// -- the correct type. The other cases are handled in
// -- the J1CollectionHandler during the
// -- add(collect,value) call
if (type.isArray()) {
Class componentType = type.getComponentType();
Class valueType = value.getClass();
if (componentType.isPrimitive()
|| ((!valueType.isArray()) && (valueType != componentType))) {
try {
collect = Array.newInstance(componentType, 0);
} catch (Exception e) {
String err = "Unable to instantiate an array of '" + componentType + "' : " + e;
throw new CastorIllegalStateException(err, e);
}
}
}
setCollection = true;
} else {
setCollection = collect.getClass().isArray();
}
Object tmp = _colHandler.add(collect, value);
// -- make sure we do not overwrite collect unless
// -- the new collection is not null
if (tmp != null)
collect = tmp;
if (setCollection && (_setMethod != null))
_setMethod.invoke(object, new Object[] {collect});
}
} catch (IllegalAccessException except) {
// This should never happen
throw new IllegalStateException(
Messages.format("mapping.schemaChangeNoAccess", toString()));
} catch (InvocationTargetException except) {
// This should never happen
throw new MappingRuntimeException(except.getTargetException());
}
}
}
public void resetValue(Object object) {
if (_colHandler == null) {
try {
if (_handler != null)
_handler.resetValue(object);
else if (_field != null)
_field.set(object, _default);
else if (_setMethod != null) {
if (_getSequence != null)
for (int i = 0; i < _getSequence.length; i++) {
object = _getSequence[i].invoke(object, (Object[]) null);
if (object == null)
break;
}
if (object != null) {
if (_deleteMethod != null)
_deleteMethod.invoke(object, (Object[]) null);
else
_setMethod.invoke(object, new Object[] {_default});
}
}
// If the field has no set method, ignore it.
// If this is a problem, identity it someplace else.
} catch (IllegalArgumentException except) {
// Graceful way of dealing with unwrapping exception
throw new IllegalArgumentException(
Messages.format("mapping.typeConversionNull", toString()));
} catch (IllegalAccessException except) {
// This should never happen
throw new IllegalStateException(
Messages.format("mapping.schemaChangeNoAccess", toString()));
} catch (InvocationTargetException except) {
// This should never happen
throw new MappingRuntimeException(except.getTargetException());
}
} else {
Object collect;
try {
// Get the field value (the collection), add the value to it,
// possibly yielding a new collection (in the case of an array),
// and set that collection back into the field.
if (_handler != null) {
_handler.resetValue(object);
} else if (_field != null) {
collect = _field.get(object);
collect = _colHandler.clear(collect);
if (collect != null)
_field.set(object, collect);
} else if (_getMethod != null) {
if (_getSequence != null)
for (int i = 0; i < _getSequence.length; i++)
object = _getSequence[i].invoke(object, (Object[]) null);
collect = _getMethod.invoke(object, (Object[]) null);
collect = _colHandler.clear(collect);
if (collect != null && _setMethod != null)
_setMethod.invoke(object, new Object[] {collect});
}
} catch (IllegalAccessException except) {
// This should never happen
throw new IllegalStateException(
Messages.format("mapping.schemaChangeNoAccess", toString()));
} catch (InvocationTargetException except) {
// This should never happen
throw new MappingRuntimeException(except.getTargetException());
}
}
}
/**
* Creates a new instance of the object described by this field.
*
* @param parent The object for which the field is created
* @return A new instance of the field's value
* @throws IllegalStateException This field is a simple type and cannot be instantiated
*/
public T newInstance(Object parent) throws IllegalStateException {
return newInstance(parent, null);
}
/**
* Creates a new instance of the object described by this field.
*
* @param parent The object for which the field is created
* @param args the set of constructor arguments
* @return A new instance of the field's value
* @throws IllegalStateException This field is a simple type and cannot be instantiated
*/
@SuppressWarnings("unchecked")
public T newInstance(Object parent, Object[] args) throws IllegalStateException {
if (_fieldType.isInterface() && _createMethod == null)
return null;
if ((_immutable) && ((args == null) || (args.length == 0)))
throw new IllegalStateException(Messages.format("mapping.classNotConstructable", _fieldType));
if (_handler != null) {
if (_handler instanceof ExtendedFieldHandler)
return (T) ((ExtendedFieldHandler) _handler).newInstance(parent, args);
return _handler.newInstance(parent);
}
// If we have a create method and parent object, call the create method.
if (_createMethod != null && parent != null) {
try {
return (T) _createMethod.invoke(parent, args);
} catch (IllegalAccessException except) {
// This should never happen
throw new IllegalStateException(
Messages.format("mapping.schemaChangeNoAccess", toString()));
} catch (InvocationTargetException except) {
// This should never happen
throw new MappingRuntimeException(except.getTargetException());
}
}
return (T) Types.newInstance(_fieldType, args);
} // -- newInstance
/**
* Mutator method used by {@link AbstractMappingLoader}.
*/
void setRequired(final boolean required) {}
/**
* Sets the TypeConvertor used during calls to getValue
*
* @param convertor the TypeConvertor to use during calls to getValue
**/
public void setConvertFrom(TypeConvertor convertor) {
_convertFrom = convertor;
} // -- setConvertFrom
/**
* Sets the TypeConvertor used during calls to setValue
*
* @param convertor the TypeConvertor to use during calls to setValue
**/
public void setConvertTo(TypeConvertor convertor) {
_convertTo = convertor;
} // -- setConvertTo
/**
* Mutator method used by {@link AbstractMappingLoader} and
* {@link org.exolab.castor.xml.Introspector}. Please understand how this method is used before
* you start playing with it! :-)
*/
public void setCreateMethod(Method method) throws MappingException {
if ((method.getModifiers() & Modifier.PUBLIC) == 0
|| (method.getModifiers() & Modifier.STATIC) != 0)
throw new MappingException("mapping.accessorNotAccessible", method,
method.getDeclaringClass().getName());
if (method.getParameterTypes().length != 0)
throw new MappingException("mapping.createMethodNoParam", method,
method.getDeclaringClass().getName());
_createMethod = method;
}
/**
* Mutator method used by {@link AbstractMappingLoader} and
* {@link org.exolab.castor.xml.Introspector}. Please understand how this method is used before
* you start playing with it! :-)
*/
public void setHasDeleteMethod(Method hasMethod, Method deleteMethod) throws MappingException {
if (hasMethod != null) {
if ((hasMethod.getModifiers() & Modifier.PUBLIC) == 0
|| (hasMethod.getModifiers() & Modifier.STATIC) != 0)
throw new MappingException("mapping.accessorNotAccessible", hasMethod,
hasMethod.getDeclaringClass().getName());
if (hasMethod.getParameterTypes().length != 0)
throw new MappingException("mapping.createMethodNoParam", hasMethod,
hasMethod.getDeclaringClass().getName());
_hasMethod = hasMethod;
}
if (deleteMethod != null) {
if ((deleteMethod.getModifiers() & Modifier.PUBLIC) == 0
|| (deleteMethod.getModifiers() & Modifier.STATIC) != 0)
throw new MappingException("mapping.accessorNotAccessible", deleteMethod,
deleteMethod.getDeclaringClass().getName());
if (deleteMethod.getParameterTypes().length != 0)
throw new MappingException("mapping.createMethodNoParam", deleteMethod,
deleteMethod.getDeclaringClass().getName());
_deleteMethod = deleteMethod;
}
}
/**
* Mutator method used by {@link org.exolab.castor.xml.Introspector}. Please understand how this
* method is used before you start playing with it! :-)
*/
public void setReadMethod(Method method) throws MappingException {
if ((method.getModifiers() & Modifier.PUBLIC) == 0
|| (method.getModifiers() & Modifier.STATIC) != 0)
throw new MappingException("mapping.accessorNotAccessible", method,
method.getDeclaringClass().getName());
if (method.getParameterTypes().length != 0)
throw new MappingException("mapping.readMethodHasParam", method,
method.getDeclaringClass().getName());
_getMethod = method;
}
/**
* Mutator method used by {@link org.exolab.castor.xml.Introspector}. Please understand how this
* method is used before you start playing with it! :-)
*/
public void setWriteMethod(Method method) throws MappingException {
if ((method.getModifiers() & Modifier.PUBLIC) == 0
|| (method.getModifiers() & Modifier.STATIC) != 0)
throw new MappingException("mapping.accessorNotAccessible", method,
method.getDeclaringClass().getName());
if (method.getParameterTypes().length != 1)
throw new MappingException("mapping.writeMethodNoParam", method,
method.getDeclaringClass().getName());
_setMethod = method;
}
/**
* Mutator method used by {@link org.exolab.castor.xml.Introspector}. Please understand how this
* method is used before you start playing with it! :-)
*/
public void setAddMethod(Method method) throws MappingException {
if ((method.getModifiers() & Modifier.PUBLIC) == 0
|| (method.getModifiers() & Modifier.STATIC) != 0)
throw new MappingException("mapping.accessorNotAccessible", method,
method.getDeclaringClass().getName());
if (method.getParameterTypes().length != 1)
throw new MappingException("mapping.writeMethodNoParam", method,
method.getDeclaringClass().getName());
_addMethod = method;
// -- make sure add method is not the same as the set method
if (_addMethod == _setMethod)
_setMethod = null;
} // -- setAddMethod
/**
* Sets the enumeration method.
*/
public void setEnumMethod(Method method) throws MappingException {
if ((method.getModifiers() & Modifier.PUBLIC) == 0
|| (method.getModifiers() & Modifier.STATIC) != 0)
throw new MappingException("mapping.accessorNotAccessible", method,
method.getDeclaringClass().getName());
if (method.getParameterTypes().length != 0)
throw new MappingException("mapping.readMethodHasParam", method,
method.getDeclaringClass().getName());
_enumMethod = method;
}
/**
* Sets the iteration method.
*/
public void setIterMethod(Method method) throws MappingException {
if ((method.getModifiers() & Modifier.PUBLIC) == 0
|| (method.getModifiers() & Modifier.STATIC) != 0)
throw new MappingException("mapping.accessorNotAccessible", method,
method.getDeclaringClass().getName());
if (method.getParameterTypes().length != 0)
throw new MappingException("mapping.readMethodHasParam", method,
method.getDeclaringClass().getName());
_iterMethod = method;
}
/**
* Selects the appropriate "write" method based on the value. This is used when there is an "add"
* method and a "set" method.
*
* @return the selected write method
**/
private Method selectWriteMethod(Object value) {
if (_setMethod != null) {
if (_addMethod == null)
return _setMethod;
if (value == null) {
if (_default != null)
value = _default;
else
return _setMethod;
}
// -- check value's class type
Class paramType = _setMethod.getParameterTypes()[0];
if (paramType.isAssignableFrom(value.getClass()))
return _setMethod;
}
return _addMethod;
} // -- selectWriteMethod
/**
* Return true if the field is a collection.
*/
public boolean isCollection() {
return (_colHandler != null);
}
public String toString() {
return _fieldName;
}
/**
* Sets the FieldDescriptor that this FieldHander is responsibile for. By setting the
* FieldDescriptor, it allows the implementation of the FieldHandler methods to obtain information
* about the field itself. This allows a particular implementation to become more generic and
* reusable.
*
* @param fieldDesc the FieldDescriptor to set
*/
public void setFieldDescriptor(FieldDescriptor fieldDesc) {
super.setFieldDescriptor(fieldDesc);
if (_handler != null) {
if (_handler instanceof GeneralizedFieldHandler) {
((GeneralizedFieldHandler) _handler).setFieldDescriptor(fieldDesc);
}
}
}
}