// Private
private Object startElement(Object parent, QName elementName, ParticleBinding particle)
{
TermBinding term = particle.getTerm();
if(term.isSkip())
{
return parent;
}
boolean trace = log.isTraceEnabled();
if(trace)
{
log.trace("startElement " + elementName + " parent=" + parent + " term=" + term);
}
ClassMetaData classMetaData = term.getClassMetaData();
MapEntryMetaData mapEntryMetaData = term.getMapEntryMetaData();
if(!term.isModelGroup())
{
TypeBinding type = ((ElementBinding)term).getType();
if(type.isSimple() ||
classMetaData == null && mapEntryMetaData == null &&
(!type.isStartElementCreatesObject() ||
Constants.QNAME_ANYTYPE.equals(type.getQName())))
{
if(trace)
{
log.trace("startElement " + elementName + " does not create an object");
}
return null;
}
}
// if addMethod is specified, it's probably some collection field
// but should not be set as a property. Instead, items are added to it using the addMethod
ElementBinding arrayItem = null;
if(!term.isModelGroup())
{
TypeBinding type = ((ElementBinding)term).getType();
if(type.getAttributes().isEmpty())
{
ParticleBinding typeParticle = type.getParticle();
ModelGroupBinding modelGroup = (ModelGroupBinding)(typeParticle == null ? null : typeParticle.getTerm());
arrayItem = modelGroup == null ? null : modelGroup.getArrayItem();
// todo refactor later (move it to modelGroup.getArrayItem()?)
if(arrayItem != null &&
(arrayItem.isSkip() ||
arrayItem.getMapEntryMetaData() != null ||
arrayItem.getPutMethodMetaData() != null ||
arrayItem.getAddMethodMetaData() != null
))
{
arrayItem = null;
}
}
}
if(arrayItem != null)
{
Class wrapperType = null;
if(classMetaData != null)
{
wrapperType = loadClassForTerm(classMetaData.getImpl(),
term.getSchema().isIgnoreUnresolvedFieldOrClass(),
elementName
);
if(GenericValueContainer.class.isAssignableFrom(wrapperType) ||
Collection.class.isAssignableFrom(wrapperType) ||
Map.class.isAssignableFrom(wrapperType))
{
return newInstance(wrapperType, elementName, term.getSchema().isUseNoArgCtorIfFound());
}
}
if(wrapperType == null && parent == null)
{
Class itemType = classForElement(arrayItem, null);
if(itemType != null)
{
if(trace)
{
log.trace("startElement " + elementName + " new array " + itemType.getName());
}
return GenericValueContainer.FACTORY.array(itemType);
}
}
else
{
PropertyMetaData propertyMetaData = wrapperType == null ?
term.getPropertyMetaData() : arrayItem.getPropertyMetaData();
String propName;
if(propertyMetaData == null)
{
propName = Util.xmlNameToFieldName(
wrapperType == null ? elementName.getLocalPart() : arrayItem.getQName().getLocalPart(),
term.getSchema().isIgnoreLowLine()
);
}
else
{
propName = propertyMetaData.getName();
}
if(trace)
{
log.trace("startElement " + elementName + " property=" + propName);
}
Class parentClass = wrapperType;
if(wrapperType == null)
{
if(parent instanceof GenericValueContainer)
{
parentClass = ((GenericValueContainer)parent).getTargetClass();
}
else if(parent instanceof ValueList)
{
parentClass = ((ValueList)parent).getTargetClass();
}
else
{
parentClass = parent.getClass();
}
}
Class fieldType = null;
if(parentClass.isArray())
{
fieldType = parentClass.getComponentType();
}
else
{
//fieldType = FieldInfo.getFieldInfo(parentClass, propName, true).getType();
// this was changed to false because allow overriding of handler.setParent()
// with an interceptor.add(). See CollectionOverridePropertyUnitTestCase
// In other words, don't treat it as an array wrapper.
FieldInfo fieldInfo = FieldInfo.getFieldInfo(parentClass, propName, false);
if(fieldInfo != null)
{
fieldType = fieldInfo.getType();
if (particle.isRepeatable() && fieldType.isArray())
{
fieldType = fieldType.getComponentType();
}
}
else if(arrayItem.getInterceptors().isEmpty())
{
QName typeName = ((ElementBinding)term).getType().getQName();
throw new JBossXBRuntimeException(
"Couldn't apply 'array wrapper' pattern for element " +
elementName + " of type " +
(typeName == null ? "anonymous" : typeName.toString()) +
": failed to resolve property " + propName +
" and no interceptors applied to override handler.setParent(...)");
}
}
if(fieldType.isArray())
{
return GenericValueContainer.FACTORY.array(wrapperType, propName, fieldType.getComponentType());
}
else if(Collection.class.isAssignableFrom(fieldType))
{
if (wrapperType == null)
{
return new ValueListInitializer().newValueList(ValueListHandler.FACTORY.child(), Collection.class);
//o = ArrayList();
}
}
else
{
return GenericValueContainer.FACTORY.array(wrapperType, propName, fieldType);
}
}
}
Object o = null;
if(mapEntryMetaData != null)
{
if(mapEntryMetaData.getImpl() != null)
{
Class cls = loadClassForTerm(mapEntryMetaData.getImpl(),
term.getSchema().isIgnoreUnresolvedFieldOrClass(),
elementName
);
if(trace)
{
log.trace("startElement " + elementName + " new map entry " + cls.getName());
}
o = newInstance(cls, elementName, term.getSchema().isUseNoArgCtorIfFound());
}
else
{
o = new MapEntry();
if(trace)
{
log.trace("startElement " + elementName + " new map entry");
}
}
if(mapEntryMetaData.isNonNullValue() && mapEntryMetaData.getValueType() != null)
{
Class mapValueType;
try
{
mapValueType =
Thread.currentThread().getContextClassLoader().loadClass(mapEntryMetaData.getValueType());
}
catch(ClassNotFoundException e)
{
throw new JBossXBRuntimeException("startElement failed for " +
elementName +
": failed to load class " +
mapEntryMetaData.getValueType() +
" for map entry value."
);
}
Object value;
try
{
if(trace)
{
log.trace("startElement " + elementName + " map value type " + mapEntryMetaData.getValueType());
}
value = mapValueType.newInstance();
}
catch(Exception e)
{
throw new JBossXBRuntimeException("startElement failed for " +
elementName +
": failed to create an instance of " +
mapValueType +
" for map entry value."
);
}
if(o instanceof MapEntry)
{
((MapEntry)o).setValue(value);
}
else
{
String getValueMethodName = mapEntryMetaData.getGetValueMethod();
if(getValueMethodName == null)
{
getValueMethodName = "getValue";
}
String setValueMethodName = mapEntryMetaData.getSetValueMethod();
if(setValueMethodName == null)
{
setValueMethodName = "setValue";
}
Method getValueMethod;
try
{
getValueMethod = o.getClass().getMethod(getValueMethodName, null);
}
catch(NoSuchMethodException e)
{
throw new JBossXBRuntimeException("getValueMethod=" +
getValueMethodName +
" is not found in map entry " + o.getClass()
);
}
Method setValueMethod;
try
{
setValueMethod =
o.getClass().getMethod(setValueMethodName, new Class[]{getValueMethod.getReturnType()});
}
catch(NoSuchMethodException e)
{
throw new JBossXBRuntimeException("setValueMethod=" +
setValueMethodName +
"(" +
getValueMethod.getReturnType().getName() +
" value) is not found in map entry " + o.getClass()
);
}
try
{
setValueMethod.invoke(o, new Object[]{value});
}
catch(Exception e)
{
throw new JBossXBRuntimeException("setValueMethod=" +
setValueMethodName +
" failed: owner=" +
o +
", value=" + value + ", msg=" + e.getMessage(), e
);
}
}
}
}
else
{
// todo: for now we require metadata for model groups to be bound
// todo 2: parent.getClass() is not going to work for containers
Class parentClass = null;
if(parent != null)
{
if(parent instanceof GenericValueContainer)
{
parentClass = ((GenericValueContainer)parent).getTargetClass();
}
else if(parent instanceof ValueList)
{
parentClass = ((ValueList)parent).getTargetClass();
}
else
{
parentClass = parent.getClass();
}
}
Class cls;
if(term.isModelGroup())
{
if(classMetaData == null)
{
throw new JBossXBRuntimeException(
"Model groups should be annotated with 'class' annotation to be bound."
);
}
cls = loadClassForTerm(classMetaData.getImpl(),
term.getSchema().isIgnoreUnresolvedFieldOrClass(),
elementName
);
}
else
{
ElementBinding element = (ElementBinding)term;
cls = classForNonArrayItem(element, parentClass);
if(cls != null)
{
// todo: before that, the type should be checked for required attributes and elements
TypeBinding simpleType = element.getType().getSimpleType();
if(simpleType != null)
{
Class simpleCls = classForSimpleType(simpleType, element.isNillable());
if(cls.equals(simpleCls) ||
cls.isPrimitive() && Classes.getPrimitiveWrapper(cls) == simpleCls ||
simpleCls.isPrimitive() && Classes.getPrimitiveWrapper(simpleCls) == cls)
{
cls = null;
}
}
}
}
if(cls != null)
{
boolean noArgCtor;
if(classMetaData == null)
{
noArgCtor = term.getSchema().isUseNoArgCtorIfFound();
}
else
{
Boolean termUsesNoArgCtor = classMetaData.isUseNoArgCtor();
noArgCtor = termUsesNoArgCtor == null ?
term.getSchema().isUseNoArgCtorIfFound() : termUsesNoArgCtor.booleanValue(); }
if(trace)
{
log.trace("startElement " + elementName + " new " + cls.getName() + ", noArgCtor=" + noArgCtor);
}