FieldDescriptor fieldDesc;
FieldMappingCollectionType colType = fieldMap.getCollection();
String xmlName = null;
NodeType nodeType = null;
String match = null;
XMLFieldDescriptorImpl xmlDesc;
boolean isReference = false;
boolean isXMLTransient = false;
//-- handle special case for HashMap/Hashtable
if ((fieldMap.getType() == null) && (colType != null)) {
if ((colType == FieldMappingCollectionType.HASHTABLE) ||
(colType == FieldMappingCollectionType.MAP) ||
(colType == FieldMappingCollectionType.SORTEDMAP))
{
fieldMap.setType(MapItem.class.getName());
}
}
// Create an XML field descriptor
fieldDesc = super.createFieldDesc( javaClass, fieldMap );
BindXml xml = fieldMap.getBindXml();
boolean deriveNameByClass = false;
if (xml != null) {
//-- xml name
xmlName = xml.getName();
//-- node type
if ( xml.getNode() != null )
nodeType = NodeType.getNodeType( xml.getNode().toString() );
//-- matches
match = xml.getMatches();
//-- reference
isReference = xml.getReference();
//-- XML transient
isXMLTransient = xml.getTransient();
//-- autonaming
BindXmlAutoNamingType autoName = xml.getAutoNaming();
if (autoName != null) {
deriveNameByClass = (autoName == BindXmlAutoNamingType.DERIVEBYCLASS);
}
}
//-- transient
//-- XXXX -> if it's transient we probably shouldn't do all
//-- XXXX -> the unecessary work
isXMLTransient = isXMLTransient || fieldDesc.isTransient();
//--
//-- handle QName for xmlName
String namespace = null;
if ((xmlName != null) && (xmlName.length() > 0)){
if (xmlName.charAt(0) == '{') {
int idx = xmlName.indexOf('}');
if (idx < 0) {
throw new MappingException("Invalid QName: " + xmlName);
}
namespace = xmlName.substring(1, idx);
xmlName = xmlName.substring(idx+1);
}
else if (xmlName.startsWith(XML_PREFIX)) {
namespace = Namespaces.XML_NAMESPACE;
xmlName = xmlName.substring(4);
}
}
if (nodeType == null) {
if (isPrimitive(javaClass))
nodeType = getInternalContext().getPrimitiveNodeType();
else
nodeType = NodeType.Element;
}
//-- Create XML name if necessary. Note if name is to be derived
//-- by class..we just make sure we set the name to null...
//-- the Marshaller does this during runtime. This allows
//-- Collections to be handled properly.
if ((!deriveNameByClass) && ((xmlName == null) && (match == null)))
{
xmlName = getInternalContext().getXMLNaming().toXMLName( fieldDesc.getFieldName() );
match = xmlName + ' ' + fieldDesc.getFieldName();
}
xmlDesc = new XMLFieldDescriptorImpl( fieldDesc, xmlName, nodeType, getInternalContext().getPrimitiveNodeType() );
if (xmlDesc.getHandler() != null && xmlDesc.getHandler() instanceof AbstractFieldHandler) {
AbstractFieldHandler handler = (AbstractFieldHandler) xmlDesc.getHandler();
handler.setFieldDescriptor(xmlDesc);
}
//-- transient?
xmlDesc.setTransient(isXMLTransient);
//--set a default fieldValidator
xmlDesc.setValidator(new FieldValidator());
//-- enable use parent namespace if explicit one doesn't exist
xmlDesc.setUseParentsNamespace(true);
//-- If deriveNameByClass we need to reset the name to
//-- null because XMLFieldDescriptorImpl tries to be smart
//-- and automatically creates the name.
if (deriveNameByClass) {
xmlDesc.setXMLName(null);
}
//-- namespace
if (namespace != null) {
xmlDesc.setNameSpaceURI(namespace);
}
//-- matches
if (match != null) {
xmlDesc.setMatches(match);
//-- special fix for xml-name since XMLFieldDescriptorImpl
//-- will create a default name based off the field name
if (xmlName == null) xmlDesc.setXMLName(null);
}
//-- reference
xmlDesc.setReference(isReference);
if (isReference) {
if (colType == null) {
FieldValidator fieldValidator = new FieldValidator();
fieldValidator.setValidator(new IdRefValidator());
xmlDesc.setValidator(fieldValidator);
} else {
// TODO handle other cases
}
}
xmlDesc.setContainer(fieldMap.getContainer());
xmlDesc.setNillable(fieldMap.isNillable());
if (xml != null) {
//-- has class descriptor for type specified
if (xml.getClassMapping() != null) {
ClassDescriptor cd = createClassDescriptor(xml.getClassMapping());
xmlDesc.setClassDescriptor(cd);
}
//-- has location path?
if (xml.getLocation() != null) {
xmlDesc.setLocationPath(xml.getLocation());
}
//is the value type needs specific handling
//such as QName or NCName support?
String xmlType = xml.getType();
xmlDesc.setSchemaType(xmlType);
xmlDesc.setQNamePrefix(xml.getQNamePrefix());
TypeValidator validator = null;
if (NCNAME.equals(xmlType)) {
validator = new NameValidator(XMLConstants.NAME_TYPE_NCNAME);
xmlDesc.setValidator(new FieldValidator(validator));
}
//-- special properties?
Property[] props = xml.getProperty();
if ((props != null) && (props.length > 0)) {
for (int pIdx = 0; pIdx < props.length; pIdx++) {
Property prop = props[pIdx];
xmlDesc.setXMLProperty(prop.getName(), prop.getValue());
}
}
}
//-- Get collection type
if (colType == null) {
//-- just in case user forgot to use collection="..."
//-- in the mapping file
Class type = fieldDesc.getFieldType();
if (type != null && CollectionHandlers.hasHandler(type)) {
String typeName = CollectionHandlers.getCollectionName(type);
colType = FieldMappingCollectionType.valueOf(typeName);
}
}
//-- isMapped item
if (colType != null) {
if ((colType == FieldMappingCollectionType.HASHTABLE) ||
(colType == FieldMappingCollectionType.MAP) ||
(colType == FieldMappingCollectionType.SORTEDMAP))
{
//-- Make sure user is not using an addMethod
//-- before setting the mapped field to true.
String methodName = fieldMap.getSetMethod();
if (methodName != null) {
if (!methodName.startsWith("add")) {
xmlDesc.setMapped(true);
}
}
else xmlDesc.setMapped(true);
}
//-- special NodeType.Namespace handling
//-- prevent FieldHandlerImpl from using CollectionHandler
//-- during calls to #getValue
if ((nodeType == NodeType.Namespace) || (xmlDesc.isMapped())) {
Object handler = xmlDesc.getHandler();
if (handler instanceof FieldHandlerImpl) {
FieldHandlerImpl handlerImpl = (FieldHandlerImpl)handler;
handlerImpl.setConvertFrom(new IdentityConvertor());
}
}
//-- wrap collection in element?
if (nodeType == NodeType.Element) {
if (fieldMap.hasContainer() && (!fieldMap.getContainer())) {
xmlDesc = wrapCollection(xmlDesc);
}
}
}
//-- is Type-Safe Enumeration?
//-- This is not very clean, we should have a way
//-- to specify something is a type-safe enumeration
//-- without having to guess.
else if ((!isReference) && (!isXMLTransient)) {
Class fieldType = xmlDesc.getFieldType();
if (!isPrimitive(fieldType)) {
//-- make sure no default constructor
Constructor cons = null;
try {
cons = fieldType.getConstructor(EMPTY_ARGS);
if (!Modifier.isPublic(cons.getModifiers())) {
cons = null;
}
}
catch(NoSuchMethodException nsmx) {
//-- Do nothing
}
try {
if (cons == null) {
//-- make sure a valueOf factory method
//-- exists and no user specified handler exists
Method method = fieldType.getMethod(VALUE_OF, STRING_ARG);
Class returnType = method.getReturnType();
if ((returnType != null) && fieldType.isAssignableFrom(returnType)) {
if (fieldMap.getHandler() == null) {
//-- Use EnumFieldHandler
//-- mapping loader now supports a basic EnumFieldHandler
//-- for xml we simply need to make sure the toString()
//-- method is called during getValue()
//FieldHandler handler = xmlDesc.getHandler();
//handler = new EnumFieldHandler(fieldType, handler);
FieldHandler handler = new ToStringFieldHandler(fieldType, xmlDesc.getHandler());
xmlDesc.setHandler(handler);
xmlDesc.setImmutable(true);
}
}
}
}
catch(NoSuchMethodException nsmx) {
//-- Do nothing
}
}
}
//-- constructor argument?
String setter = fieldMap.getSetMethod();
if (setter != null) {
if (setter.startsWith("%")) {
int index = 0;
setter = setter.substring(1);
index = Integer.parseInt(setter);
if ((index < 1) || (index > 9)) {
throw new MappingException("mapper.invalidParameterIndex", setter);
}
//-- adjust index to base zero
--index;
xmlDesc.setConstructorArgumentIndex(index);
}
}
return xmlDesc;
}