if (xmlTransient != null && propertyOrder != null)
throw new RuntimeException("Property " + property.getName() + " in property order "
+ Arrays.asList(propertyOrder) + " is marked @XmlTransient");
// The current model
ModelGroupBinding localModel = model;
// Setup any new model
if (propertyType.isArray())
{
if (trace)
log.trace("Property " + property.getName() + " is an array");
localModel = createArray(localModel);
}
else if (propertyType.isCollection())
{
if (trace)
log.trace("Property " + property.getName() + " is a collection");
localModel = createCollection(localModel);
JBossXmlCollection xmlCol = property.getUnderlyingAnnotation(JBossXmlCollection.class);
if (xmlCol != null)
{
// this is the type that should be analyzed
propertyType = propertyType.getTypeInfoFactory().getTypeInfo(xmlCol.type());
}
}
// Is this property bound to a model group
else if (!property.getType().isPrimitive())
{
ClassInfo propClassInfo = (ClassInfo) property.getType();
// TODO XmlElement on this property?..
XmlElement propXmlElement = property.getUnderlyingAnnotation(XmlElement.class);
if (propXmlElement != null)
{
propClassInfo = (ClassInfo) propClassInfo.getTypeInfoFactory().getTypeInfo(propXmlElement.type());
}
JBossXmlModelGroup xmlModelGroup = propClassInfo.getUnderlyingAnnotation(JBossXmlModelGroup.class);
if (xmlModelGroup != null && xmlModelGroup.particles().length == 0)
{
if (trace)
log.trace("Property " + property.getName() + " is bound to " + xmlModelGroup.kind());
ModelGroupBinding propertyGroup = null;
QName groupName = null;
if (!JBossXmlConstants.DEFAULT.equals(xmlModelGroup.name()))
groupName = new QName(xmlModelGroup.name());
if (groupName != null)
propertyGroup = schemaBinding.getGroup(groupName);
if (propertyGroup == null)
{
if (xmlModelGroup.kind().equals(JBossXmlConstants.MODEL_GROUP_SEQUENCE))
{
propertyGroup = new SequenceBinding(schemaBinding);
}
else if (xmlModelGroup.kind().equals(JBossXmlConstants.MODEL_GROUP_CHOICE))
{
propertyGroup = new ChoiceBinding(schemaBinding);
}
else if (xmlModelGroup.kind().equals(JBossXmlConstants.MODEL_GROUP_ALL))
{
propertyGroup = new AllBinding(schemaBinding);
}
else
{
throw new IllegalStateException("Unexpected JBossXmlModelGroup.kind=" + xmlModelGroup.kind());
}
if (groupName != null)
{
// TODO what if it doesn't have a name? should an artificial one be created?
propertyGroup.setQName(groupName);
schemaBinding.addGroup(propertyGroup.getQName(), propertyGroup);
}
propertyGroup.setSkip(Boolean.FALSE);
// handler for the model group members
BeanInfo propBeanInfo = JBossXBBuilder.configuration.getBeanInfo(propClassInfo);
BeanAdapterFactory propBeanAdapterFactory = createAdapterFactory(DefaultBeanAdapterBuilder.class, propBeanInfo, null);
BeanHandler propHandler = new BeanHandler(propBeanInfo.getName(), propBeanAdapterFactory);
propertyGroup.setHandler(propHandler);
String[] memberOrder = xmlModelGroup.propOrder();
if (memberOrder.length == 0 || memberOrder[0].length() == 0)
{
List<String> propNames = new ArrayList<String>();
for (PropertyInfo prop : propBeanInfo.getProperties())
{
propNames.add(prop.getName());
}
memberOrder = propNames.toArray(new String[propNames.size()]);
}
if (trace)
log.trace("Property order for " + xmlModelGroup.kind() + " property " + property.getName() + ": "
+ Arrays.asList(memberOrder));
// bind model group members
for (String memberPropName : memberOrder)
{
if ("class".equals(memberPropName))
{
continue;
}
PropertyInfo memberProp = propBeanInfo.getProperty(memberPropName);
TypeInfo memberTypeInfo = memberProp.getType();
String memberNamespace = null;
JBossXmlNsPrefix nsPrefix = memberProp.getUnderlyingAnnotation(JBossXmlNsPrefix.class);
if (nsPrefix != null)
{
memberNamespace = schemaBinding.getNamespace(nsPrefix.prefix());
if (memberNamespace == null && nsPrefix.schemaTargetIfNotMapped())
{
throw new IllegalStateException("Prefix '" + nsPrefix.prefix()
+ "' is not mapped to any namespace!");
}
}
String memberName = null;
XmlElement memberXmlElement = memberProp.getUnderlyingAnnotation(XmlElement.class);
if (memberXmlElement != null)
{
if (!XmlElement.DEFAULT.class.equals(memberXmlElement.type()))
{
memberTypeInfo = memberTypeInfo.getTypeInfoFactory().getTypeInfo(memberXmlElement.type());
}
if (memberNamespace == null)
memberNamespace = memberXmlElement.namespace();
memberName = memberXmlElement.name();
}
if (memberNamespace == null)
{
memberNamespace = defaultNamespace;
}
boolean isCol = false;
AbstractPropertyHandler memberPropertyHandler = null;
if (memberProp.getType().isCollection())
{
memberPropertyHandler = new CollectionPropertyHandler(memberProp, memberProp.getType());
isCol = true;
// if memberXmlElement is present then the collection item type is set explicitly
if (memberXmlElement == null || XmlElement.DEFAULT.class.equals(memberXmlElement.type()))
{
JBossXmlCollection jbossXmlCollection = memberProp
.getUnderlyingAnnotation(JBossXmlCollection.class);
if (jbossXmlCollection != null)
{
memberTypeInfo = memberTypeInfo.getTypeInfoFactory().getTypeInfo(jbossXmlCollection.type());
}
memberTypeInfo = ((ClassInfo) memberTypeInfo).getComponentType();
}
}
// if it is bound with XmlElement.type to a collection
else if (memberTypeInfo.isCollection())
{
memberPropertyHandler = new CollectionPropertyHandler(memberProp, memberTypeInfo);
isCol = true;
memberTypeInfo = ((ClassInfo) memberTypeInfo).getComponentType();
}
else
{
memberPropertyHandler = new PropertyHandler(memberProp, memberTypeInfo);
}
QName memberQName = generateXmlName(memberProp.getName(), elementForm, memberNamespace, memberName);
propBeanAdapterFactory.addProperty(memberQName, memberPropertyHandler);
XBValueAdapter valueAdapter = null;
XmlJavaTypeAdapter xmlTypeAdapter = memberProp.getUnderlyingAnnotation(XmlJavaTypeAdapter.class);
if (xmlTypeAdapter != null)
{
valueAdapter = new XBValueAdapter(xmlTypeAdapter.value(), memberTypeInfo.getTypeInfoFactory());
memberTypeInfo = valueAdapter.getAdaptedTypeInfo();
}
TypeBinding memberTypeBinding = resolveTypeBinding(memberTypeInfo);
ElementBinding memberElement = createElementBinding(memberTypeInfo, memberTypeBinding, memberQName,
false);
memberElement.setNillable(true);
memberElement.setValueAdapter(valueAdapter);
ParticleBinding memberParticle = new ParticleBinding(memberElement, 0, 1, isCol);
propertyGroup.addParticle(memberParticle);
if (trace)
log.trace("added " + memberParticle + " to " + xmlModelGroup.kind() + ", property "
+ property.getName());
}
}
model.addParticle(new ParticleBinding(propertyGroup));
// model group value handler based on the model group name
// TODO what if it doesn't have a name?
AbstractPropertyHandler propertyHandler = null;
if (propertyType.isCollection())
propertyHandler = new CollectionPropertyHandler(property, propClassInfo);
else
{
propertyHandler = new PropertyHandler(property, propClassInfo);
}
beanAdapterFactory.addProperty(propertyGroup.getQName(), propertyHandler);
return;
}
}
// So this is element(s)
XmlElement[] elements = null;
XmlElement xmlElement = property.getUnderlyingAnnotation(XmlElement.class);
if (xmlElement != null)
{
// A single element annotated
elements = new XmlElement[]
{xmlElement};
}
else
{
// Mutlple elements
XmlElements xmlElements = property.getUnderlyingAnnotation(XmlElements.class);
if (xmlElements != null)
elements = xmlElements.value();
}
// A single element not annotated
if (elements == null || elements.length == 0)
elements = new XmlElement[1];
// for now support just one JBossXmlNsPrefix
JBossXmlNsPrefix xmlNsPrefix = property.getUnderlyingAnnotation(JBossXmlNsPrefix.class);
// support for @XmlElementWrapper
// the wrapping element is ignored in this case
XmlElementWrapper xmlWrapper = property.getUnderlyingAnnotation(XmlElementWrapper.class);
if (xmlWrapper != null)
{
String wrapperNamespace = xmlWrapper.namespace();
String wrapperName = xmlWrapper.name();
QName wrapperQName = generateXmlName(property.getName(), elementForm, wrapperNamespace, wrapperName);
localModel = bindXmlElementWrapper(propertyType, localModel, xmlWrapper.nillable(), wrapperQName);
if (trace)
log.trace("Added property " + wrapperQName + " for type=" + property.getBeanInfo().getName() + " property="
+ property.getName() + " as a wrapper element");
}
// Setup a choice
if (elements.length > 1)
{
ChoiceBinding choice = new ChoiceBinding(schemaBinding);
choice.setHandler(BuilderParticleHandler.INSTANCE);
ParticleBinding particleBinding = new ParticleBinding(choice);
particleBinding.setMinOccurs(0);
particleBinding.setMaxOccurs(1);
localModel.addParticle(particleBinding);
localModel = choice;
if (trace)
log.trace("XmlElements seen adding choice for type=" + property.getBeanInfo().getName() + " property="
+ property.getName());
}
for (int i = 0; i < elements.length; ++i)
{
XmlElement element = elements[i];
if (trace)
log.trace("Processing " + element + " for type=" + property.getBeanInfo().getName() + " property="
+ property.getName());
// Determine the parameters
String overrideNamespace = null;
String overrideName = null;
boolean nillable = false;
boolean required = false;
TypeInfo localPropertyType = propertyType;
if (element != null)
{
overrideNamespace = element.namespace();
overrideName = element.name();
nillable = element.nillable();
required = element.required();
Class<?> elementType = element.type();
if (elementType != XmlElement.DEFAULT.class)
localPropertyType = propertyType.getTypeInfoFactory().getTypeInfo(elementType);
}
if (xmlNsPrefix != null)
{
overrideNamespace = schemaBinding.getNamespace(xmlNsPrefix.prefix());
if (overrideNamespace == null)
{
if (xmlNsPrefix.schemaTargetIfNotMapped())
{
overrideNamespace = defaultNamespace;
}
else
{
throw new IllegalStateException("Prefix '" + xmlNsPrefix.prefix()
+ "' is not mapped to any namespace!");
}
}
}
// Determine the name
QName propertyQName = generateXmlName(property.getName(), elementForm, overrideNamespace, overrideName);
// Create the element
JBossXmlGroup jbossXmlGroup = null;
if (!propertyType.isPrimitive())
jbossXmlGroup = ((ClassInfo) propertyType).getUnderlyingAnnotation(JBossXmlGroup.class);
if (element == null && jbossXmlGroup != null)
{
if (trace)
log.trace("Processing group for property " + property.getName() + " in "
+ property.getBeanInfo().getName() + " " + jbossXmlGroup);
JBossXmlChild[] children = jbossXmlGroup.value();
if (children != null && children.length > 0)
{
TypeBinding elementTypeBinding = new TypeBinding();
elementTypeBinding.setSchemaBinding(schemaBinding);
elementTypeBinding.setHandler(BuilderParticleHandler.INSTANCE);
ElementBinding elementBinding = createElementBinding(localPropertyType, elementTypeBinding, propertyQName, false);
// Bind it to the model
ParticleBinding particle = new ParticleBinding(elementBinding, 1, 1, false);
if (required == false)
particle.setMinOccurs(0);
localModel.addParticle(particle);
// Can it take text?
JBossXmlGroupText groupText = ((ClassInfo) propertyType)
.getUnderlyingAnnotation(JBossXmlGroupText.class);
if (groupText != null)
{
CharactersHandler textHandler;
if (groupText.wrapper() != Object.class)
{
BeanInfo wrapperInfo = JBossXBBuilder.configuration.getBeanInfo(groupText.wrapper());
textHandler = new ValueHandler(property, wrapperInfo, groupText.property());
}
else
textHandler = new ValueHandler(property);
elementTypeBinding.setSimpleType(textHandler);
}
// Setup the child model
ChoiceBinding childModel = new ChoiceBinding(schemaBinding);
childModel.setHandler(BuilderParticleHandler.INSTANCE);
ParticleBinding particleBinding = new ParticleBinding(childModel);
particleBinding.setMinOccurs(0);
particleBinding.setMaxOccurs(1);
elementTypeBinding.setParticle(particleBinding);
for (JBossXmlChild child : children)
{
QName childName = generateXmlName(child.name(), elementForm, child.namespace(), child.name());
TypeInfo childType = JBossXBBuilder.configuration.getTypeInfo(child.type());
TypeBinding childTypeBinding = resolveTypeBinding(childType);
ElementBinding childBinding = createElementBinding(childType, childTypeBinding, childName, false);
childBinding.setNillable(nillable);
// Bind it to the model
particle = new ParticleBinding(childBinding, child.minOccurs(), child.maxOccurs(), child.unbounded());
particle.setMinOccurs(0);
childModel.addParticle(particle);
if(childType.isMap())
bindMapProperty(property, (ClassInfo) childType, childName, (ModelGroupBinding) childTypeBinding.getParticle().getTerm());
DefaultElementInterceptor interceptor = new PropertyInterceptor(property, propertyType);
elementTypeBinding.pushInterceptor(childName, interceptor);
if (trace)
log.trace("Added interceptor " + childName + " for type=" + property.getBeanInfo().getName()
+ " property=" + property.getName() + " interceptor=" + interceptor + " " + childType.getName());
beanAdapterFactory.addProperty(propertyQName, new NoopPropertyHandler(property, propertyType));
JBossXmlGroupWildcard groupWildcard = ((ClassInfo) propertyType)
.getUnderlyingAnnotation(JBossXmlGroupWildcard.class);
if (groupWildcard != null)
{
ChildWildcardHandler groupWildcardHandler;
if (groupWildcard.wrapper() != Object.class)
{
BeanInfo wrapperInfo = JBossXBBuilder.configuration.getBeanInfo(groupWildcard.wrapper());
groupWildcardHandler = new ChildWildcardHandler(property, wrapperInfo, groupWildcard.property());
}
else
groupWildcardHandler = new ChildWildcardHandler(property);
WildcardBinding wildcard = new WildcardBinding(schemaBinding);
if (groupWildcard.lax())
wildcard.setProcessContents((short) 3); // Lax
else
wildcard.setProcessContents((short) 1); // Strict
particleBinding = new ParticleBinding(wildcard);
particleBinding.setMinOccurs(0);
particleBinding.setMaxOccurs(1);
childModel.addParticle(particleBinding);
elementTypeBinding.getWildcard().setWildcardHandler(groupWildcardHandler);
}
}
}
}
else
{
XBValueAdapter valueAdapter = null;
XmlJavaTypeAdapter xmlTypeAdapter = property.getUnderlyingAnnotation(XmlJavaTypeAdapter.class);
if (xmlTypeAdapter != null)
{
valueAdapter = new XBValueAdapter(xmlTypeAdapter.value(), propertyType.getTypeInfoFactory());
localPropertyType = valueAdapter.getAdaptedTypeInfo();
}
ModelGroupBinding targetGroup = localModel;
boolean isCol = false;
boolean isMap = false;
AbstractPropertyHandler propertyHandler = null;
// a collection may be bound as a value of a complex type
// and this is checked with the XmlType annotation
if (propertyType.isCollection() && ((ClassInfo) propertyType).getUnderlyingAnnotation(XmlType.class) == null)
{
isCol = true;
propertyHandler = new CollectionPropertyHandler(property, propertyType);
// here we get the comp type based on the non-overriden property type...
// which feels like a weak point
TypeInfo typeArg = ((ClassInfo)property.getType()).getComponentType();
if (typeArg != null && ((ClassInfo)typeArg).getUnderlyingAnnotation(JBossXmlModelGroup.class) == null)
{// it may be a model group in which case we don't want to change the type
// TODO yes, this is another hack with collections
JBossXmlChild xmlChild = ((ClassInfo) propertyType).getUnderlyingAnnotation(JBossXmlChild.class);
if (xmlChild == null && localPropertyType.equals(propertyType))
{ // the localPropertyType was not overriden previously so use the collection parameter type
localPropertyType = typeArg;
}
}
}
// TODO this shouldn't be here (because localPropertyType should specify an item?)
// this is to support the Descriptions.class -> DescriptionsImpl.class
else if (localPropertyType.isCollection()
&& ((ClassInfo) localPropertyType).getUnderlyingAnnotation(XmlType.class) == null)
{
if (valueAdapter != null)
{
propertyHandler = new PropertyHandler(property, localPropertyType);
}
else
{
propertyHandler = new CollectionPropertyHandler(property, localPropertyType);
}
isCol = true;
localPropertyType = ((ClassInfo)localPropertyType).getComponentType();
}
else if (localPropertyType.isMap())
{
TypeBinding wrapperType = null;
if(elements.length > 1)
{
wrapperType = resolveTypeBinding(localPropertyType);
ElementBinding elementBinding = createElementBinding(localPropertyType, wrapperType, propertyQName, false);
elementBinding.setNillable(nillable);
elementBinding.setValueAdapter(valueAdapter);
// Bind it to the model
ParticleBinding particle = new ParticleBinding(elementBinding, 0, 1, isCol);
if (required == false)
particle.setMinOccurs(0);
targetGroup.addParticle(particle);
targetGroup = (ModelGroupBinding) wrapperType.getParticle().getTerm();
}
QName boundQName = bindMapProperty(property, (ClassInfo) localPropertyType, propertyQName, targetGroup);
if(boundQName != null)
{
if(wrapperType != null)
{
BeanAdapterFactory wrapperBeanFactory = ((BeanHandler)wrapperType.getHandler()).getBeanAdapterFactory();
Map<QName, AbstractPropertyHandler> properties = wrapperBeanFactory.getProperties();
if(!properties.containsKey(boundQName))
{
propertyHandler = new MapPropertyHandler(JBossXBBuilder.configuration, property, localPropertyType, true);
wrapperBeanFactory.addProperty(boundQName, propertyHandler);
}
propertyHandler = new PropertyHandler(property, localPropertyType);
}
else
{
propertyQName = boundQName;
propertyHandler = new MapPropertyHandler(JBossXBBuilder.configuration, property, localPropertyType, false);
}
isMap = true;
}
else
propertyHandler = new PropertyHandler(property, localPropertyType);
}
else
{
propertyHandler = new PropertyHandler(property, localPropertyType);
}
ParticleBinding particle;
// DOM elements are going to be treated as unresolved
// however having the property registered
if (!isMap && !Element.class.getName().equals(propertyType.getName()))
{
TypeBinding elementTypeBinding = resolveTypeBinding(localPropertyType);
ElementBinding elementBinding = createElementBinding(localPropertyType, elementTypeBinding, propertyQName, false);
elementBinding.setNillable(nillable);
elementBinding.setValueAdapter(valueAdapter);
// Bind it to the model
particle = new ParticleBinding(elementBinding, 1, 1, isCol);
if (required == false)
particle.setMinOccurs(0);
targetGroup.addParticle(particle);
}
beanAdapterFactory.addProperty(propertyQName, propertyHandler);
if (trace)
log.trace("Added property " + propertyQName + " for type=" + property.getBeanInfo().getName() + " property="