// 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 + " wrapper=" + wrapperType);
}
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(((ElementBinding)term).getType().getInterceptors(arrayItem.getQName()).isEmpty() &&
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 != null)
{
// TODO: review the logic for cases when wrapperType == null
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 = new 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);