XMLClassDescriptorImpl classDesc
= new IntrospectedXMLClassDescriptor(c);
Method[] methods = c.getMethods();
List dateDescriptors = new List(3);
Hashtable methodSets = new Hashtable();
int methodCount = 0;
Class superClass = c.getSuperclass();
Class[] interfaces = c.getInterfaces();
//-- create method sets
for (int i = 0; i < methods.length; i++) {
Method method = methods[i];
Class owner = method.getDeclaringClass();
//-- ignore methods from super-class, that will be
//-- introspected separately, if necessary
if (owner != c) {
//-- if declaring class is anything but
//-- an interface, than just continue,
//-- the field comes from a super class
//-- (e.g. java.lang.Object)
if (!owner.isInterface()) continue;
//-- owner is an interface, is it an
//-- interface this class implements
//-- or a parent class?
if (interfaces.length > 0) {
boolean found = false;
for (int count = 0; count < interfaces.length; count++) {
if (interfaces[count] == owner) {
found = true;
break;
}
}
if (!found) continue;
}
}
else {
//-- look for overloaded methods
if (superClass != null) {
Class[] args = method.getParameterTypes();
String name = method.getName();
Method tmpMethod = null;
try {
tmpMethod = superClass.getMethod(name, args);
}
catch(NoSuchMethodException nsme) {
//-- do nothing
}
if (tmpMethod != null) continue;
}
}
//-- if method is static...ignore
if ((method.getModifiers() & Modifier.STATIC) != 0) continue;
String methodName = method.getName();
//-- read methods
if (methodName.startsWith(GET)) {
if (method.getParameterTypes().length != 0) continue;
//-- disable direct field access
++methodCount;
//-- make sure return type is "descriptable"
//-- and not null
Class type = method.getReturnType();
if (type == null) continue;
if (!isDescriptable(type)) continue;
//-- caclulate name from Method name
String fieldName = methodName.substring(3);
fieldName = JavaNaming.toJavaMemberName(fieldName);
MethodSet methodSet = (MethodSet)methodSets.get(fieldName);
if (methodSet == null) {
methodSet = new MethodSet(fieldName);
methodSets.put(fieldName, methodSet);
}
methodSet.get = method;
}
else if (methodName.startsWith(IS)) {
if (method.getParameterTypes().length != 0) continue;
//-- make sure type is not null, and a boolean
Class type = method.getReturnType();
if (type == null) continue;
if (type.isPrimitive()) {
if (type != Boolean.TYPE) continue;
}
else {
if (type != Boolean.class) continue;
}
//-- disable direct field access
++methodCount;
//-- caclulate name from Method name
String fieldName = methodName.substring(IS.length());
fieldName = JavaNaming.toJavaMemberName(fieldName);
MethodSet methodSet = (MethodSet)methodSets.get(fieldName);
if (methodSet == null) {
methodSet = new MethodSet(fieldName);
methodSets.put(fieldName, methodSet);
}
methodSet.get = method;
}
//-----------------------------------/
//-- write methods (collection item)
else if (methodName.startsWith(ADD)) {
if (method.getParameterTypes().length != 1) continue;
//-- disable direct field access
++methodCount;
//-- make sure parameter type is "descriptable"
if (!isDescriptable(method.getParameterTypes()[0])) continue;
//-- caclulate name from Method name
String fieldName = methodName.substring(3);
fieldName = JavaNaming.toJavaMemberName(fieldName);
MethodSet methodSet = (MethodSet) methodSets.get(fieldName);
if (methodSet == null) {
methodSet = new MethodSet(fieldName);
methodSets.put(fieldName, methodSet);
}
methodSet.add = method;
}
//-- write method (singleton or collection)
else if (methodName.startsWith(SET)) {
if (method.getParameterTypes().length != 1) continue;
//-- disable direct field access
++methodCount;
//-- make sure parameter type is "descriptable"
if (!isDescriptable(method.getParameterTypes()[0])) continue;
//-- caclulate name from Method name
String fieldName = methodName.substring(3);
fieldName = JavaNaming.toJavaMemberName(fieldName);
MethodSet methodSet = (MethodSet) methodSets.get(fieldName);
if (methodSet == null) {
methodSet = new MethodSet(fieldName);
methodSets.put(fieldName, methodSet);
}
methodSet.set = method;
}
else if (methodName.startsWith(CREATE)) {
if (method.getParameterTypes().length != 0) continue;
Class type = method.getReturnType();
//-- make sure return type is "descriptable"
//-- and not null
if (!isDescriptable(type)) continue;
//-- caclulate name from Method name
String fieldName = methodName.substring(CREATE.length());
fieldName = JavaNaming.toJavaMemberName(fieldName);
MethodSet methodSet = (MethodSet) methodSets.get(fieldName);
if (methodSet == null) {
methodSet = new MethodSet(fieldName);
methodSets.put(fieldName, methodSet);
}
methodSet.create = method;
}
} //-- end create method sets
//-- Loop Through MethodSets and create
//-- descriptors
Enumeration enumeration = methodSets.elements();
while (enumeration.hasMoreElements()) {
MethodSet methodSet = (MethodSet) enumeration.nextElement();
//-- create XMLFieldDescriptor
String xmlName = _naming.toXMLName(methodSet.fieldName);
boolean isCollection = false;
//-- calculate class type
//-- 1st check for add-method, then set or get method
Class type = null;
if (methodSet.add != null) {
type = methodSet.add.getParameterTypes()[0];
isCollection = true;
}
//-- if there was no add method, use get/set methods
//-- to calculate type.
if (type == null) {
if (methodSet.get != null) {
type = methodSet.get.getReturnType();
}
else if (methodSet.set != null) {
type = methodSet.set.getParameterTypes()[0];
}
else {
//-- if we make it here, the only method found
//-- was a create method, which is useless by itself.
continue;
}
}
//-- Handle Collections
isCollection = (isCollection || isCollection(type));
TypeInfo typeInfo = null;
CollectionHandler colHandler = null;
//-- If the type is a collection and there is no add method,
//-- then we obtain a CollectionHandler
if (isCollection && (methodSet.add == null)) {
try {
colHandler = CollectionHandlers.getHandler(type);
}
catch(MappingException mx) {
//-- No collection handler available,
//-- proceed anyway...
}
//-- Find component type
if (type.isArray()) {
//-- Byte arrays are handled as a special case
//-- so don't use CollectionHandler
if (type.getComponentType() == Byte.TYPE) {
colHandler = null;
}
else type = type.getComponentType();
}
}
typeInfo = new TypeInfo(type, null, null, false, null, colHandler);
//-- Create FieldHandler first, before the XMLFieldDescriptor
//-- in case we need to use a custom handler
FieldHandler handler = null;
boolean customHandler = false;
try {
handler = new FieldHandlerImpl(methodSet.fieldName,
null,
null,
methodSet.get,
methodSet.set,
typeInfo);
//-- clean up
if (methodSet.add != null)
((FieldHandlerImpl)handler).setAddMethod(methodSet.add);
if (methodSet.create != null)
((FieldHandlerImpl)handler).setCreateMethod(methodSet.create);
//-- handle Hashtable/Map
if (isCollection && _saveMapKeys && isMapCollection(type)) {
((FieldHandlerImpl)handler).setConvertFrom(new IdentityConvertor());
}
//-- look for GeneralizedFieldHandler
FieldHandlerFactory factory = getHandlerFactory(type);
if (factory != null) {
GeneralizedFieldHandler gfh = factory.createFieldHandler(type);
if (gfh != null) {
gfh.setFieldHandler(handler);
handler = gfh;
customHandler = true;
//-- swap type with the type specified by the
//-- custom field handler
if (gfh.getFieldType() != null) {
type = gfh.getFieldType();
}
}
}
}
catch (MappingException mx) {
throw new MarshalException(mx);
}
XMLFieldDescriptorImpl fieldDesc
= createFieldDescriptor(type, methodSet.fieldName, xmlName);
if (isCollection) {
fieldDesc.setMultivalued(true);
fieldDesc.setNodeType(NodeType.Element);
}
//-- check for instances of java.util.Date
if (java.util.Date.class.isAssignableFrom(type)) {
//handler = new DateFieldHandler(handler);
if (!customHandler) {
dateDescriptors.add(fieldDesc);
}
}
fieldDesc.setHandler(handler);
//-- Wrap collections?
if (isCollection && _wrapCollectionsInContainer) {
String fieldName = COLLECTION_WRAPPER_PREFIX + methodSet.fieldName;
//-- If we have a field 'c' that is a collection and
//-- we want to wrap that field in an element <e>, we
//-- need to create a field descriptor for
//-- an object that represents the element <e> and
//-- acts as a go-between from the parent of 'c'
//-- denoted as P(c) and 'c' itself
//
// object model: P(c) -> c
// xml : <p><e><c></e><p>
//-- Make new class descriptor for the field that
//-- will represent the container element <e>
Class cType = ContainerElement.class;
XMLClassDescriptorImpl containerClassDesc = new XMLClassDescriptorImpl(cType);
//-- add the field descriptor to our new class descriptor
containerClassDesc.addFieldDescriptor(fieldDesc);
//-- nullify xmlName so that auto-naming will be enabled,
//-- we can't do this in the constructor because
//-- XMLFieldDescriptorImpl will create a default one.
fieldDesc.setXMLName(null);
fieldDesc.setMatches("*");
//-- wrap the field handler in a special container field
//-- handler that will actually do the delgation work
FieldHandler cHandler = new ContainerFieldHandler(handler);
fieldDesc.setHandler(cHandler);
fieldDesc = createFieldDescriptor(cType, fieldName, xmlName);
fieldDesc.setClassDescriptor(containerClassDesc);
fieldDesc.setHandler(cHandler);
}
//-- add FieldDescriptor to ClassDescriptor
classDesc.addFieldDescriptor(fieldDesc);
} //-- end of method loop
//-- If we didn't find any methods we can try
//-- direct field access
if (methodCount == 0) {
Field[] fields = c.getFields();
Hashtable descriptors = new Hashtable();
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
Class owner = field.getDeclaringClass();
//-- ignore fields from super-class, that will be
//-- introspected separately, if necessary
if (owner != c) {
//-- if declaring class is anything but
//-- an interface, than just continue,
//-- the field comes from a super class
//-- (e.g. java.lang.Object)
if (!owner.isInterface()) continue;
//-- owner is an interface, is it an
//-- interface this class implements
//-- or a parent class?
if (interfaces.length > 0) {
boolean found = false;
for (int count = 0; count < interfaces.length; count++) {
if (interfaces[count] == owner) {
found = true;
break;
}
}
if (!found) continue;
}
}
//-- make sure field is not transient or static final
int modifiers = field.getModifiers();
if (Modifier.isTransient(modifiers)) continue;
if (Modifier.isFinal(modifiers) &&
Modifier.isStatic(modifiers))
continue;
Class type = field.getType();
if (!isDescriptable(type)) continue;
//-- Built-in support for JDK 1.1 Collections
//-- we need to a pluggable interface for
//-- JDK 1.2+
boolean isCollection = isCollection(type);
TypeInfo typeInfo = null;
CollectionHandler colHandler = null;
//-- If the type is a collection and there is no add method,
//-- then we obtain a CollectionHandler
if (isCollection) {
try {
colHandler = CollectionHandlers.getHandler(type);
}
catch(MappingException mx) {
//-- No CollectionHandler available, continue
//-- without one...
}
//-- Find component type
if (type.isArray()) {
//-- Byte arrays are handled as a special case
//-- so don't use CollectionHandler
if (type.getComponentType() == Byte.TYPE) {
colHandler = null;
}
else type = type.getComponentType();
}
}
String fieldName = field.getName();
String xmlName = _naming.toXMLName(fieldName);
//-- Create FieldHandler first, before the XMLFieldDescriptor
//-- in case we need to use a custom handler
typeInfo = new TypeInfo(type, null, null, false, null, colHandler);
FieldHandler handler = null;
boolean customHandler = false;
try {
handler = new FieldHandlerImpl(field, typeInfo);
//-- handle Hashtable/Map
if (isCollection && _saveMapKeys && isMapCollection(type)) {
((FieldHandlerImpl)handler).setConvertFrom(new IdentityConvertor());
}
//-- look for GeneralizedFieldHandler
FieldHandlerFactory factory = getHandlerFactory(type);
if (factory != null) {
GeneralizedFieldHandler gfh = factory.createFieldHandler(type);
if (gfh != null) {
gfh.setFieldHandler(handler);
handler = gfh;
customHandler = true;
//-- swap type with the type specified by the
//-- custom field handler
if (gfh.getFieldType() != null) {
type = gfh.getFieldType();
}
}
}
}
catch (MappingException mx) {
throw new MarshalException(mx);
}
XMLFieldDescriptorImpl fieldDesc =
createFieldDescriptor(type, fieldName, xmlName);
if (isCollection) {
fieldDesc.setNodeType(NodeType.Element);
fieldDesc.setMultivalued(true);
}
descriptors.put(xmlName, fieldDesc);
classDesc.addFieldDescriptor(fieldDesc);
fieldDesc.setHandler(handler);
//-- check for instances of java.util.Date
if (java.util.Date.class.isAssignableFrom(type)) {
if (!customHandler) {
dateDescriptors.add(fieldDesc);
}
}
}
} //-- end of direct field access
//-- A temporary fix for java.util.Date
if (dateDescriptors != null) {
for (int i = 0; i < dateDescriptors.size(); i++) {
XMLFieldDescriptorImpl fieldDesc =
(XMLFieldDescriptorImpl) dateDescriptors.get(i);
FieldHandler handler = fieldDesc.getHandler();
fieldDesc.setImmutable(true);
DateFieldHandler dfh = new DateFieldHandler(handler);
//-- patch for java.sql.Date