protected override FragmentEventType DoResolveFragmentType(String property) { if ((!ConfigurationEventTypeXMLDOM.IsAutoFragment) || (ConfigurationEventTypeXMLDOM.IsXPathPropertyExpr)) { return(null); } Property prop = PropertyParser.ParseAndWalkLaxToSimple(property); SchemaItem item = prop.GetPropertyTypeSchema(_schemaModelRoot, EventAdapterService); if ((item == null) || (!CanFragment(item))) { return(null); } var complex = (SchemaElementComplex)item; // build name of event type String[] atomicProps = prop.ToPropertyArray(); String delimiterDot = "."; var eventTypeNameBuilder = new StringBuilder(Name); foreach (String atomic in atomicProps) { eventTypeNameBuilder.Append(delimiterDot); eventTypeNameBuilder.Append(atomic); } String eventTypeName = eventTypeNameBuilder.ToString(); // check if the type exists, use the existing type if found EventType existingType = EventAdapterService.GetEventTypeByName(eventTypeName); if (existingType != null) { return(new FragmentEventType(existingType, complex.IsArray, false)); } // add a new type var xmlDom = new ConfigurationEventTypeXMLDOM(); xmlDom.RootElementName = "//" + complex.Name; // such the reload of the type can resolve it xmlDom.RootElementNamespace = complex.Namespace; xmlDom.IsAutoFragment = ConfigurationEventTypeXMLDOM.IsAutoFragment; xmlDom.IsEventSenderValidatesRoot = ConfigurationEventTypeXMLDOM.IsEventSenderValidatesRoot; xmlDom.IsXPathPropertyExpr = ConfigurationEventTypeXMLDOM.IsXPathPropertyExpr; xmlDom.IsXPathResolvePropertiesAbsolute = ConfigurationEventTypeXMLDOM.IsXPathResolvePropertiesAbsolute; xmlDom.SchemaResource = ConfigurationEventTypeXMLDOM.SchemaResource; xmlDom.SchemaText = ConfigurationEventTypeXMLDOM.SchemaText; xmlDom.XPathFunctionResolver = ConfigurationEventTypeXMLDOM.XPathFunctionResolver; xmlDom.XPathVariableResolver = ConfigurationEventTypeXMLDOM.XPathVariableResolver; xmlDom.DefaultNamespace = ConfigurationEventTypeXMLDOM.DefaultNamespace; xmlDom.AddNamespacePrefixes(ConfigurationEventTypeXMLDOM.NamespacePrefixes); EventType newType; try { newType = EventAdapterService.AddXMLDOMType(eventTypeName, xmlDom, _schemaModel, true); } catch (Exception ex) { Log.Error( "Failed to add dynamic event type for fragment of XML schema for property '" + property + "' :" + ex.Message, ex); return(null); } return(new FragmentEventType(newType, complex.IsArray, false)); }
/// <summary> /// Return the xPath corresponding to the given property. The PropertyName String /// may be simple, nested, indexed or mapped. /// </summary> /// <param name="propertyName">is the event property name</param> /// <param name="namespace">is the default namespace</param> /// <param name="schemaModel">is the schema model</param> /// <param name="xPathContext">is the xpath factory instance to use</param> /// <param name="rootElementName">is the name of the root element</param> /// <param name="eventAdapterService">for type lookup and creation</param> /// <param name="xmlEventType">the resolving type</param> /// <param name="isAllowFragment">whether fragmenting is allowed</param> /// <param name="defaultNamespace">default namespace</param> /// <returns> /// xpath expression /// </returns> /// <throws>EPException is there are XPath errors</throws> public static EventPropertyGetterSPI GetXPathResolution( String propertyName, XPathNamespaceContext xPathContext, String rootElementName, String @namespace, SchemaModel schemaModel, EventAdapterService eventAdapterService, BaseXMLEventType xmlEventType, bool isAllowFragment, String defaultNamespace) { if (Log.IsDebugEnabled) { Log.Debug("Determining XPath expression for property '" + propertyName + "'"); } var ctx = new XPathNamespaceContext(); var namespaces = schemaModel.Namespaces; string defaultNamespacePrefix = null; for (int i = 0; i < namespaces.Count; i++) { var namespacePrefix = "n" + i; ctx.AddNamespace(namespacePrefix, namespaces[i]); if ((defaultNamespace != null) && (defaultNamespace == namespaces[i])) { defaultNamespacePrefix = namespacePrefix; } } var property = PropertyParser.ParseAndWalkLaxToSimple(propertyName); var isDynamic = property.IsDynamic; var rootComplexElement = SchemaUtil.FindRootElement(schemaModel, @namespace, rootElementName); string prefix = ctx.LookupPrefix(rootComplexElement.Namespace); if (prefix == null) { prefix = ""; } else { prefix += ':'; } var xPathBuf = new StringBuilder(); xPathBuf.Append('/'); xPathBuf.Append(prefix); if (rootElementName.StartsWith("//")) { xPathBuf.Append(rootElementName.Substring(2)); } else { xPathBuf.Append(rootElementName); } var parentComplexElement = rootComplexElement; Pair <String, XPathResultType> pair = null; if (!(property is NestedProperty)) { pair = MakeProperty(rootComplexElement, property, ctx, true, isDynamic, defaultNamespacePrefix); if (pair == null) { throw new PropertyAccessException("Failed to locate property '" + propertyName + "' in schema"); } xPathBuf.Append(pair.First); } else { NestedProperty nestedProperty = (NestedProperty)property; int indexLast = nestedProperty.Properties.Count - 1; for (int i = 0; i < indexLast + 1; i++) { var isLast = i == indexLast; var propertyNested = nestedProperty.Properties[i]; pair = MakeProperty(parentComplexElement, propertyNested, ctx, isLast, isDynamic, defaultNamespacePrefix); if (pair == null) { throw new PropertyAccessException("Failed to locate property '" + propertyName + "' nested property part '" + property.PropertyNameAtomic + "' in schema"); } var text = propertyNested.PropertyNameAtomic; var obj = SchemaUtil.FindPropertyMapping(parentComplexElement, text); if (obj is SchemaElementComplex) { parentComplexElement = (SchemaElementComplex)obj; } xPathBuf.Append(pair.First); } } var xPath = xPathBuf.ToString(); if ((ExecutionPathDebugLog.IsEnabled) && (Log.IsDebugEnabled)) { Log.Debug(".parse XPath for property '" + propertyName + "' is expression=" + xPath); } // Compile assembled XPath expression if (Log.IsDebugEnabled) { Log.Debug("Compiling XPath expression '" + xPath + "' for property '" + propertyName + "' using namespace context :" + ctx); } XPathExpression expr; try { expr = XPathExpression.Compile(xPath, ctx); } catch (XPathException e) { String detail = "Error constructing XPath expression from property expression '" + propertyName + "' expression '" + xPath + "'"; if (e.Message != null) { throw new EPException(detail + " :" + e.Message, e); } throw new EPException(detail, e); } // get type var item = property.GetPropertyTypeSchema(rootComplexElement, eventAdapterService); if ((item == null) && (!isDynamic)) { return(null); } var resultType = isDynamic ? typeof(XmlNode) : SchemaUtil.ToReturnType(item); FragmentFactory fragmentFactory = null; if (isAllowFragment) { fragmentFactory = new FragmentFactoryDOMGetter(eventAdapterService, xmlEventType, propertyName); } return(new XPathPropertyGetter(propertyName, xPath, expr, pair.Second, resultType, fragmentFactory)); }
public FragmentEventType GetFragmentType(string propertyName) { var item = _propertyItems.Get(propertyName); if (item != null) { // may contain null values return item.FragmentEventType; } // see if this is a nested property var index = StringValue.UnescapedIndexOfDot(propertyName); if (index == -1) { // dynamic simple property if (propertyName.EndsWith("?")) { return null; } // parse, can be an indexed property var property = PropertyParser.ParseAndWalkLaxToSimple(propertyName); if (property is IndexedProperty indexedProp) { var type = _nestableTypes.Get(indexedProp.PropertyNameAtomic); if (type == null) { return null; } if (type is EventType[] eventTypesArray) { var eventType = eventTypesArray[0]; return new FragmentEventType(eventType, false, false); } if (type is TypeBeanOrUnderlying[] beanOrUnderlyings) { var innerType = beanOrUnderlyings[0].EventType; if (!(innerType is BaseNestableEventType)) { return null; } return new FragmentEventType(innerType, false, false); // false since an index is present } if (!(type is Type)) { return null; } if (!((Type) type).IsArray) { return null; } // its an array return EventBeanUtility.CreateNativeFragmentType( ((Type) type).GetElementType(), null, _beanEventTypeFactory, _publicFields); } if (property is MappedProperty) { // No type information available for the inner event return null; } return null; } // Map event types allow 2 types of properties inside: // - a property that is a object is interrogated via bean property getters and BeanEventType // - a property that is a Map itself is interrogated via map property getters // The property getters therefore act on // Take apart the nested property into a map key and a nested value class property name var propertyMap = StringValue.UnescapeDot(propertyName.Substring(0, index)); var propertyNested = propertyName.Substring(index + 1); // If the property is dynamic, it cannot be a fragment if (propertyMap.EndsWith("?")) { return null; } var nestedType = _nestableTypes.Get(propertyMap); if (nestedType == null) { // parse, can be an indexed property var property = PropertyParser.ParseAndWalkLaxToSimple(propertyMap); if (property is IndexedProperty indexedProp) { var type = _nestableTypes.Get(indexedProp.PropertyNameAtomic); if (type == null) { return null; } // handle map-in-map case if (type is TypeBeanOrUnderlying[] beanOrUnderlyings) { var innerType = beanOrUnderlyings[0].EventType; if (!(innerType is BaseNestableEventType)) { return null; } return innerType.GetFragmentType(propertyNested); } if (type is EventType[] innerEventTypeArray) { // handle EventType[] in map var innerType = innerEventTypeArray[0]; return innerType.GetFragmentType(propertyNested); } // handle array class in map case if (!(type is Type)) { return null; } if (!((Type) type).IsArray) { return null; } var fragmentParent = EventBeanUtility.CreateNativeFragmentType( (Type) type, null, _beanEventTypeFactory, _publicFields); return fragmentParent?.FragmentType.GetFragmentType(propertyNested); } if (property is MappedProperty) { // No type information available for the property's map value return null; } return null; } // If there is a map value in the map, return the Object value if this is a dynamic property if (ReferenceEquals(nestedType, typeof(IDictionary<string, object>))) { return null; } if (nestedType is IDictionary<string, object>) { return null; } if (nestedType is Type simpleClass) { if (!simpleClass.IsFragmentableType()) { return null; } EventType nestedEventType = _beanEventTypeFactory.GetCreateBeanType(simpleClass, _publicFields); return nestedEventType.GetFragmentType(propertyNested); } if (nestedType is EventType innerEventType) { return innerEventType.GetFragmentType(propertyNested); } if (nestedType is EventType[] eventTypeArray) { return eventTypeArray[0].GetFragmentType(propertyNested); } if (nestedType is TypeBeanOrUnderlying typeBeanOrUnderlying) { var innerType = typeBeanOrUnderlying.EventType; if (!(innerType is BaseNestableEventType)) { return null; } return innerType.GetFragmentType(propertyNested); } if (nestedType is TypeBeanOrUnderlying[] typeBeanOrUnderlyings) { var innerType = typeBeanOrUnderlyings[0].EventType; if (!(innerType is BaseNestableEventType)) { return null; } return innerType.GetFragmentType(propertyNested); } var message = "Nestable map type configuration encountered an unexpected value type of '" + nestedType.GetType() + " for property '" + propertyName + "', expected Class, Map.class or Map<String, Object> as value type"; throw new PropertyAccessException(message); }
private EventPropertyGetterSPI DoResolvePropertyGetter( string propertyExpression, bool allowSimpleProperties) { var getter = propertyGetterCache.Get(propertyExpression); if (getter != null) { return getter; } if (!allowSimpleProperties) { // see if this is an indexed property var index = StringValue.UnescapedIndexOfDot(propertyExpression); if (index == -1) { // parse, can be an indexed property var property = PropertyParser.ParseAndWalkLaxToSimple(propertyExpression); if (!property.IsDynamic) { if (!(property is IndexedProperty)) { return null; } var indexedProp = (IndexedProperty) property; getter = propertyGetters.Get(indexedProp.PropertyNameAtomic); if (null == getter) { return null; } var descriptor = PropertyDescriptorMap.Get(indexedProp.PropertyNameAtomic); if (descriptor == null) { return null; } if (!descriptor.IsIndexed) { return null; } if (descriptor.PropertyType == typeof(XmlNodeList)) { FragmentFactorySPI fragmentFactory = new FragmentFactoryDOMGetter( EventBeanTypedEventFactory, this, indexedProp.PropertyNameAtomic); return new XPathPropertyArrayItemGetter(getter, indexedProp.Index, fragmentFactory); } else if (descriptor.PropertyType == typeof(string)) { FragmentFactorySPI fragmentFactory = new FragmentFactoryDOMGetter( EventBeanTypedEventFactory, this, indexedProp.PropertyNameAtomic); return new XPathPropertyArrayItemGetter(getter, indexedProp.Index, fragmentFactory); } } } } if (!isPropertyExpressionXPath) { var prop = PropertyParser.ParseAndWalkLaxToSimple(propertyExpression); var isDynamic = prop.IsDynamic; if (!isDynamic) { var item = prop.GetPropertyTypeSchema(schemaModelRoot); if (item == null) { return null; } getter = prop.GetGetterDOM(schemaModelRoot, EventBeanTypedEventFactory, this, propertyExpression); if (getter == null) { return null; } var returnType = SchemaUtil.ToReturnType(item); if (returnType != typeof(XmlNode) && returnType != typeof(XmlNodeList)) { if (!returnType.IsArray) { getter = new DOMConvertingGetter((DOMPropertyGetter) getter, returnType); } else { getter = new DOMConvertingArrayGetter( (DOMPropertyGetter) getter, returnType.GetElementType()); } } } else { return prop.GetterDOM; } } else { var allowFragments = !ConfigurationEventTypeXMLDOM.IsXPathPropertyExpr; getter = SchemaXMLPropertyParser.GetXPathResolution( propertyExpression, NamespaceContext, RootElementName, rootElementNamespace, SchemaModel, EventBeanTypedEventFactory, this, allowFragments, ConfigurationEventTypeXMLDOM.DefaultNamespace); } propertyGetterCache.Put(propertyExpression, getter); return getter; }
public EventPropertyWriter GetWriter(string propertyName) { if (_writeablePropertyDescriptors == null) { InitializeWriters(); } var pair = _writerMap.Get(propertyName); if (pair != null) { return pair.Second; } var property = PropertyParser.ParseAndWalkLaxToSimple(propertyName); if (property is MappedProperty) { var mapProp = (MappedProperty)property; var methodName = PropertyHelper.GetSetterMethodName(mapProp.PropertyNameAtomic); MethodInfo setterMethod; try { setterMethod = MethodResolver.ResolveMethod( _clazz, methodName, new Type[] { typeof(string), typeof(object) }, true, new bool[2], new bool[2]); } catch (EngineNoSuchMethodException) { Log.Info( "Failed to find mapped property setter method '" + methodName + "' for writing to property '" + propertyName + "' taking {string, Object} as parameters"); return null; } if (setterMethod == null) { return null; } var fastMethod = _fastClass.GetMethod(setterMethod); return new BeanEventPropertyWriterMapProp(_clazz, fastMethod, mapProp.Key); } if (property is IndexedProperty) { var indexedProp = (IndexedProperty)property; var methodName = PropertyHelper.GetSetterMethodName(indexedProp.PropertyNameAtomic); MethodInfo setterMethod; try { // setterMethod = UnderlyingType.GetMethod( // methodName, BindingFlags.Public | BindingFlags.Instance, null, // new Type[] { typeof(int), typeof(object) }, null); setterMethod = MethodResolver.ResolveMethod( _clazz, methodName, new Type[] { typeof(int), typeof(object) }, true, new bool[2], new bool[2]); } catch (EngineNoSuchMethodException) { Log.Info( "Failed to find indexed property setter method '" + methodName + "' for writing to property '" + propertyName + "' taking {int, Object} as parameters"); return null; } if (setterMethod == null) { return null; } var fastMethod = _fastClass.GetMethod(setterMethod); return new BeanEventPropertyWriterIndexedProp(_clazz, fastMethod, indexedProp.Index); } return null; }
public FragmentEventType GetFragmentType(String propertyName) { var item = _propertyItems.Get(propertyName); if (item != null) // may contain null values { return(item.FragmentEventType); } // see if this is a nested property var index = ASTUtil.UnescapedIndexOfDot(propertyName); if (index == -1) { // dynamic simple property if (propertyName.EndsWith("?")) { return(null); } // parse, can be an indexed property var property = PropertyParser.ParseAndWalkLaxToSimple(propertyName); if (property is IndexedProperty) { var indexedProp = (IndexedProperty)property; var type = NestableTypes.Get(indexedProp.PropertyNameAtomic); if (type == null) { return(null); } else if (type is EventType[]) { var eventType = ((EventType[])type)[0]; return(new FragmentEventType(eventType, false, false)); } else if (type is String) { var propTypeName = type.ToString(); var isArray = EventTypeUtility.IsPropertyArray(propTypeName); if (!isArray) { return(null); } propTypeName = EventTypeUtility.GetPropertyRemoveArray(propTypeName); EventType innerType = _eventAdapterService.GetEventTypeByName(propTypeName); if (!(innerType is BaseNestableEventType)) { return(null); } return(new FragmentEventType(innerType, false, false)); // false since an index is present } if (!(type is Type)) { return(null); } if (!((Type)type).IsArray) { return(null); } // its an array return(EventBeanUtility.CreateNativeFragmentType(((Type)type).GetElementType(), null, _eventAdapterService)); } else if (property is MappedProperty) { // No type information available for the inner event return(null); } else { return(null); } } // Map event types allow 2 types of properties inside: // - a property that is a object is interrogated via bean property getters and BeanEventType // - a property that is a Map itself is interrogated via map property getters // The property getters therefore act on // Take apart the nested property into a map key and a nested value class property name var propertyMap = ASTUtil.UnescapeDot(propertyName.Substring(0, index)); var propertyNested = propertyName.Substring(index + 1); // If the property is dynamic, it cannot be a fragment if (propertyMap.EndsWith("?")) { return(null); } var nestedType = NestableTypes.Get(propertyMap); if (nestedType == null) { // parse, can be an indexed property var property = PropertyParser.ParseAndWalkLaxToSimple(propertyMap); if (property is IndexedProperty) { var indexedProp = (IndexedProperty)property; var type = NestableTypes.Get(indexedProp.PropertyNameAtomic); if (type == null) { return(null); } // handle map-in-map case if (type is String) { var propTypeName = type.ToString(); var isArray = EventTypeUtility.IsPropertyArray(propTypeName); if (isArray) { propTypeName = EventTypeUtility.GetPropertyRemoveArray(propTypeName); } EventType innerType = _eventAdapterService.GetEventTypeByName(propTypeName); if (!(innerType is BaseNestableEventType)) { return(null); } return(innerType.GetFragmentType(propertyNested)); } // handle eventtype[] in map else if (type is EventType[]) { var innerType = ((EventType[])type)[0]; return(innerType.GetFragmentType(propertyNested)); } // handle array class in map case else { if (!(type is Type)) { return(null); } if (!((Type)type).IsArray) { return(null); } var fragmentParent = EventBeanUtility.CreateNativeFragmentType( (Type)type, null, _eventAdapterService); if (fragmentParent == null) { return(null); } return(fragmentParent.FragmentType.GetFragmentType(propertyNested)); } } else if (property is MappedProperty) { // No type information available for the property's map value return(null); } else { return(null); } } // If there is a map value in the map, return the Object value if this is a dynamic property if (ReferenceEquals(nestedType, typeof(IDictionary <string, object>))) { return(null); } else if (nestedType is IDictionary <string, object> ) { return(null); } else if (nestedType is Type) { var simpleClass = (Type)nestedType; if (!TypeHelper.IsFragmentableType(simpleClass)) { return(null); } EventType nestedEventType = _eventAdapterService.BeanEventTypeFactory.CreateBeanTypeDefaultName(simpleClass); return(nestedEventType.GetFragmentType(propertyNested)); } else if (nestedType is EventType) { var innerType = (EventType)nestedType; return(innerType.GetFragmentType(propertyNested)); } else if (nestedType is EventType[]) { var innerType = (EventType[])nestedType; return(innerType[0].GetFragmentType(propertyNested)); } else if (nestedType is String) { var nestedName = nestedType.ToString(); var isArray = EventTypeUtility.IsPropertyArray(nestedName); if (isArray) { nestedName = EventTypeUtility.GetPropertyRemoveArray(nestedName); } var innerType = _eventAdapterService.GetEventTypeByName(nestedName); if (!(innerType is BaseNestableEventType)) { return(null); } return(innerType.GetFragmentType(propertyNested)); } else { var message = "Nestable map type configuration encountered an unexpected value type of '" + nestedType.GetType() + " for property '" + propertyName + "', expected Class, typeof(Map) or IDictionary<String, Object> as value type"; throw new PropertyAccessException(message); } }
public static EventPropertyGetter GetGetter( Schema avroSchema, Dictionary <string, EventPropertyGetter> propertyGetterCache, IDictionary <string, PropertySetDescriptorItem> propertyDescriptors, string propertyName, bool addToCache, EventAdapterService eventAdapterService) { var getter = propertyGetterCache.Get(propertyName); if (getter != null) { return(getter); } var unescapePropName = ASTUtil.UnescapeDot(propertyName); var item = propertyDescriptors.Get(unescapePropName); if (item != null) { getter = item.PropertyGetter; MayAddToGetterCache(propertyName, propertyGetterCache, getter, true); return(getter); } // see if this is a nested property var index = ASTUtil.UnescapedIndexOfDot(propertyName); if (index == -1) { var prop = PropertyParser.ParseAndWalkLaxToSimple(propertyName); if (prop is IndexedProperty) { var indexedProp = (IndexedProperty)prop; Field field = avroSchema.GetField(prop.PropertyNameAtomic); if (field == null) { return(null); } switch (field.Schema.Tag) { case Schema.Type.Array: var fragmentEventType = AvroFragmentTypeUtil.GetFragmentEventTypeForField( field.Schema, eventAdapterService); getter = new AvroEventBeanGetterIndexed( field, indexedProp.Index, fragmentEventType == null ? null : fragmentEventType.FragmentType, eventAdapterService); MayAddToGetterCache(propertyName, propertyGetterCache, getter, addToCache); return(getter); case Schema.Type.String: getter = new AvroEventBeanGetterStringIndexed(field, indexedProp.Index); MayAddToGetterCache(propertyName, propertyGetterCache, getter, addToCache); return(getter); default: return(null); } } else if (prop is MappedProperty) { var mappedProp = (MappedProperty)prop; Field field = avroSchema.GetField(prop.PropertyNameAtomic); if (field == null || field.Schema.Tag != Schema.Type.Map) { return(null); } getter = new AvroEventBeanGetterMapped(field, mappedProp.Key); MayAddToGetterCache(propertyName, propertyGetterCache, getter, addToCache); return(getter); } if (prop is DynamicIndexedProperty) { var dynamicIndexedProp = (DynamicIndexedProperty)prop; getter = new AvroEventBeanGetterIndexedDynamic(prop.PropertyNameAtomic, dynamicIndexedProp.Index); MayAddToGetterCache(propertyName, propertyGetterCache, getter, addToCache); return(getter); } if (prop is DynamicMappedProperty) { var dynamicMappedProp = (DynamicMappedProperty)prop; getter = new AvroEventBeanGetterMappedDynamic(prop.PropertyNameAtomic, dynamicMappedProp.Key); MayAddToGetterCache(propertyName, propertyGetterCache, getter, addToCache); return(getter); } else if (prop is DynamicSimpleProperty) { getter = new AvroEventBeanGetterSimpleDynamic(prop.PropertyNameAtomic); MayAddToGetterCache(propertyName, propertyGetterCache, getter, addToCache); return(getter); } return(null); // simple property already cached } // Take apart the nested property into a map key and a nested value class property name var propertyTop = ASTUtil.UnescapeDot(propertyName.Substring(0, index)); var propertyNested = propertyName.Substring(index + 1); var isRootedDynamic = false; // If the property is dynamic, remove the ? since the property type is defined without if (propertyTop.EndsWith("?")) { propertyTop = propertyTop.Substring(0, propertyTop.Length - 1); isRootedDynamic = true; } var propTop = PropertyParser.ParseAndWalkLaxToSimple(propertyTop); Field fieldTop = avroSchema.GetField(propTop.PropertyNameAtomic); // field is known and is a record if (fieldTop != null && fieldTop.Schema.Tag == Schema.Type.Record && propTop is SimpleProperty) { var factory = new GetterNestedFactoryRootedSimple(eventAdapterService, fieldTop); var property = PropertyParser.ParseAndWalk(propertyNested, isRootedDynamic); getter = PropertyGetterNested(factory, fieldTop.Schema, property, eventAdapterService); MayAddToGetterCache(propertyName, propertyGetterCache, getter, addToCache); return(getter); } // field is known and is a record if (fieldTop != null && fieldTop.Schema.Tag == Schema.Type.Array && propTop is IndexedProperty) { var factory = new GetterNestedFactoryRootedIndexed( eventAdapterService, fieldTop, ((IndexedProperty)propTop).Index); var property = PropertyParser.ParseAndWalk(propertyNested, isRootedDynamic); getter = PropertyGetterNested(factory, fieldTop.Schema.GetElementType(), property, eventAdapterService); MayAddToGetterCache(propertyName, propertyGetterCache, getter, addToCache); return(getter); } // field is not known or is not a record if (!isRootedDynamic) { return(null); } var propertyX = PropertyParser.ParseAndWalk(propertyNested, true); var innerGetter = GetDynamicGetter(propertyX); getter = new AvroEventBeanGetterNestedDynamicPoly(propertyTop, innerGetter); MayAddToGetterCache(propertyName, propertyGetterCache, getter, addToCache); return(getter); }
public static EventPropertyGetterSPI GetGetter( Schema avroSchema, string moduleName, Dictionary<string, EventPropertyGetterSPI> propertyGetterCache, IDictionary<string, PropertySetDescriptorItem> propertyDescriptors, string propertyName, bool addToCache, EventBeanTypedEventFactory eventAdapterService, EventTypeAvroHandler eventTypeAvroHandler, AvroEventTypeFragmentTypeCache fragmentTypeCache) { var getter = propertyGetterCache.Get(propertyName); if (getter != null) { return getter; } var unescapePropName = StringValue.UnescapeDot(propertyName); var item = propertyDescriptors.Get(unescapePropName); if (item != null) { getter = item.PropertyGetter; MayAddToGetterCache(propertyName, propertyGetterCache, getter, true); return getter; } // see if this is a nested property var index = StringValue.UnescapedIndexOfDot(propertyName); if (index == -1) { var prop = PropertyParser.ParseAndWalkLaxToSimple(propertyName); if (prop is IndexedProperty indexedProp) { var field = avroSchema.GetField(indexedProp.PropertyNameAtomic); if (field == null) { return null; } if ((field.Schema.Tag != Schema.Type.Array) && (field.Schema.Tag != Schema.Type.String)) { return null; } var fragmentEventType = AvroFragmentTypeUtil.GetFragmentEventTypeForField( field.Schema, moduleName, eventAdapterService, eventTypeAvroHandler, fragmentTypeCache); getter = new AvroEventBeanGetterIndexed( field, indexedProp.Index, fragmentEventType?.FragmentType, eventAdapterService); MayAddToGetterCache(propertyName, propertyGetterCache, getter, addToCache); return getter; } if (prop is MappedProperty mappedProp) { Field field = avroSchema.GetField(mappedProp.PropertyNameAtomic); if (field == null || field.Schema.Tag != Schema.Type.Map) { return null; } getter = new AvroEventBeanGetterMapped(field, mappedProp.Key); MayAddToGetterCache(propertyName, propertyGetterCache, getter, addToCache); return getter; } if (prop is DynamicIndexedProperty dynamicIndexedProp) { getter = new AvroEventBeanGetterIndexedDynamic( dynamicIndexedProp.PropertyNameAtomic, dynamicIndexedProp.Index); MayAddToGetterCache(propertyName, propertyGetterCache, getter, addToCache); return getter; } if (prop is DynamicMappedProperty dynamicMappedProp) { getter = new AvroEventBeanGetterMappedDynamic( dynamicMappedProp.PropertyNameAtomic, dynamicMappedProp.Key); MayAddToGetterCache(propertyName, propertyGetterCache, getter, addToCache); return getter; } if (prop is DynamicSimpleProperty) { getter = new AvroEventBeanGetterSimpleDynamic(prop.PropertyNameAtomic); MayAddToGetterCache(propertyName, propertyGetterCache, getter, addToCache); return getter; } return null; // simple property already cached } // Take apart the nested property into a map key and a nested value class property name var propertyTop = StringValue.UnescapeDot(propertyName.Substring(0, index)); var propertyNested = propertyName.Substring(index + 1); var isRootedDynamic = false; // If the property is dynamic, remove the ? since the property type is defined without if (propertyTop.EndsWith("?")) { propertyTop = propertyTop.Substring(0, propertyTop.Length - 1); isRootedDynamic = true; } var propTop = PropertyParser.ParseAndWalkLaxToSimple(propertyTop); Field fieldTop = avroSchema.GetField(propTop.PropertyNameAtomic); // field is known and is a record if (fieldTop != null && fieldTop.Schema.Tag == Schema.Type.Record && propTop is SimpleProperty) { var factory = new GetterNestedFactoryRootedSimple(eventAdapterService, fieldTop); var property = PropertyParser.ParseAndWalk(propertyNested, isRootedDynamic); getter = PropertyGetterNested( factory, fieldTop.Schema, property, moduleName, eventAdapterService, eventTypeAvroHandler, fragmentTypeCache); MayAddToGetterCache(propertyName, propertyGetterCache, getter, addToCache); return getter; } // field is known and is a record if (fieldTop != null && propTop is IndexedProperty indexedProperty) { if ((fieldTop.Schema.Tag == Schema.Type.Array) || (fieldTop.Schema.Tag == Schema.Type.String)) { var factory = new GetterNestedFactoryRootedIndexed( eventAdapterService, fieldTop, indexedProperty.Index); var property = PropertyParser.ParseAndWalk(propertyNested, isRootedDynamic); getter = PropertyGetterNested( factory, fieldTop.Schema.AsArraySchema().ItemSchema, property, moduleName, eventAdapterService, eventTypeAvroHandler, fragmentTypeCache); MayAddToGetterCache(propertyName, propertyGetterCache, getter, addToCache); return getter; } } // field is not known or is not a record if (!isRootedDynamic) { return null; } var propertyX = PropertyParser.ParseAndWalk(propertyNested, true); var innerGetter = GetDynamicGetter(propertyX); getter = new AvroEventBeanGetterNestedDynamicPoly(propertyTop, innerGetter); MayAddToGetterCache(propertyName, propertyGetterCache, getter, addToCache); return getter; }
public static object CoerceProperty( string propertyName, Type containingType, object value, Type type, ExprNodeOrigin exprNodeOrigin, ExprValidationContext exprValidationContext, bool forceNumeric, bool includeClassNameInEx) { // handle system-property exception if (value is ExprNode) { if (value is ExprIdentNode) { var identNode = (ExprIdentNode) value; Property prop; try { prop = PropertyParser.ParseAndWalkLaxToSimple(identNode.FullUnresolvedName); } catch (Exception) { throw new ExprValidationException( "Failed to parse property '" + identNode.FullUnresolvedName + "'"); } if (!(prop is MappedProperty)) { throw new ExprValidationException( "Unrecognized property '" + identNode.FullUnresolvedName + "'"); } var mappedProperty = (MappedProperty) prop; if (string.Equals( mappedProperty.PropertyNameAtomic, ExprEvalSystemProperty.SYSTEM_PROPETIES_NAME, StringComparison.InvariantCultureIgnoreCase)) { if (type == typeof(ExprNode)) { return new ExprEvalSystemProperty(mappedProperty.Key); } return Environment.GetEnvironmentVariable(mappedProperty.Key); } } else { var exprNode = (ExprNode) value; if (type == typeof(ExprNode)) { return exprNode; } if (!exprNode.Forge.ForgeConstantType.IsCompileTimeConstant) { throw new ExprValidationException( "Failed to determine parameter for property '" + propertyName + "' as the parameter is not a compile-time constant expression"); } value = exprNode.Forge.ExprEvaluator.Evaluate(null, true, null); } } if (value == null) { return null; } var valueType = value.GetType(); if (valueType == type) { return value; } var typeUnboxed = type.GetUnboxedType(); if (valueType.GetUnboxedType().IsAssignmentCompatible(typeUnboxed)) { if (forceNumeric && value.GetType().GetBoxedType() != type.GetBoxedType() && type.IsNumeric() && value.GetType().IsNumeric()) { value = TypeHelper.CoerceBoxed(value, type.GetBoxedType()); } return value; } if (TypeHelper.IsSubclassOrImplementsInterface(value.GetType(), type)) { return value; } if (type.IsArray) { if (!value.GetType().IsGenericCollection()) { var detail = "expects an array but receives a value of type " + value.GetType().Name; throw new ExprValidationException( GetExceptionText(propertyName, containingType, includeClassNameInEx, detail)); } var items = value.UnwrapIntoArray<object>(); var coercedArray = Array.CreateInstance(type.GetElementType(), items.Length); for (var i = 0; i < items.Length; i++) { var coercedValue = CoerceProperty( propertyName + " (array element)", type, items[i], type.GetElementType(), exprNodeOrigin, exprValidationContext, false, includeClassNameInEx); coercedArray.SetValue(coercedValue, i); } return coercedArray; } if (!(value is IDictionary<string, object>)) { var detail = "expects an " + type.CleanName() + " but receives a value of type " + value.GetType().CleanName(); throw new ExprValidationException( GetExceptionText(propertyName, containingType, includeClassNameInEx, detail)); } var props = (IDictionary<string, object>) value; return InstantiatePopulateObject(props, type, exprNodeOrigin, exprValidationContext); }
public static Object CoerceProperty( string propertyName, Type containingType, Object value, Type type, ExprNodeOrigin exprNodeOrigin, ExprValidationContext exprValidationContext, bool forceNumeric, bool includeClassNameInEx) { if (value is ExprNode && type != typeof(ExprNode)) { if (value is ExprIdentNode) { var identNode = (ExprIdentNode)value; Property prop; try { prop = PropertyParser.ParseAndWalkLaxToSimple(identNode.FullUnresolvedName); } catch (Exception) { throw new ExprValidationException( "Failed to parse property '" + identNode.FullUnresolvedName + "'"); } if (!(prop is MappedProperty)) { throw new ExprValidationException( "Unrecognized property '" + identNode.FullUnresolvedName + "'"); } var mappedProperty = (MappedProperty)prop; if (string.Equals( mappedProperty.PropertyNameAtomic, SYSTEM_PROPETIES_NAME, StringComparison.InvariantCultureIgnoreCase)) { return(Environment.GetEnvironmentVariable(mappedProperty.Key)); } } else { var exprNode = (ExprNode)value; var validated = ExprNodeUtility.GetValidatedSubtree( exprNodeOrigin, exprNode, exprValidationContext); exprValidationContext.VariableService.SetLocalVersion(); var evaluator = validated.ExprEvaluator; if (evaluator == null) { throw new ExprValidationException( "Failed to evaluate expression '" + ExprNodeUtility.ToExpressionStringMinPrecedenceSafe(exprNode) + "'"); } value = evaluator.Evaluate(EvaluateParams.EmptyTrue); } } if (value == null) { return(null); } var valueType = value.GetType(); if (valueType == type) { return(value); } if (valueType.IsAssignmentCompatible(type)) { if (forceNumeric && (valueType.GetBoxedType() != type.GetBoxedType()) && type.IsNumeric() && valueType.IsNumeric()) { value = CoercerFactory.CoerceBoxed(value, type.GetBoxedType()); } return(value); } #if false // numerical coercion between non-boxed types and incompatible boxed types if ((valueType.IsNumeric()) && (valueType.IsNullable() == false) && (type.IsNumeric()) && (type.IsNullable())) { var typeNonGeneric = Nullable.GetUnderlyingType(type); if (valueType.IsAssignmentCompatible(typeNonGeneric)) { value = CoercerFactory.CoerceBoxed(value, type); } return(value); } #endif if (TypeHelper.IsSubclassOrImplementsInterface(valueType, type)) { return(value); } if (type.IsArray) { if (!(valueType.IsGenericCollection())) { var detail = "expects an array but receives a value of type " + valueType.GetCleanName(); throw new ExprValidationException( GetExceptionText(propertyName, containingType, includeClassNameInEx, detail)); } var items = value.UnwrapIntoArray <object>(); var coercedArray = Array.CreateInstance(type.GetElementType(), items.Length); for (var i = 0; i < items.Length; i++) { var coercedValue = CoerceProperty( propertyName + " (array element)", type, items[i], type.GetElementType(), exprNodeOrigin, exprValidationContext, false, includeClassNameInEx); coercedArray.SetValue(coercedValue, i); } return(coercedArray); } if (type.IsNullable() && !valueType.IsNullable()) { var typeNonGeneric = Nullable.GetUnderlyingType(type); if (valueType.IsAssignmentCompatible(typeNonGeneric)) { return(CoercerFactory.CoerceBoxed(value, type)); } } if (!(value is IDictionary <String, Object>)) { var detail = "expects an " + type.GetCleanName() + " but receives a value of type " + valueType.GetCleanName(); throw new ExprValidationException( GetExceptionText(propertyName, containingType, includeClassNameInEx, detail)); } var props = (IDictionary <string, Object>)value; return(InstantiatePopulateObject(props, type, exprNodeOrigin, exprValidationContext)); }