private static PrimitiveMultiValueProperty GetPrimitiveMultiValueProperty(IRandomNumberGenerator random) { var val = random.ChooseFrom(TestValues.CreatePrimitiveCollections(true, true)); var payload = new PrimitiveMultiValueProperty("ArbitraryMultivalue", val); return(payload); }
public PropertyInstance MultiValuePropertyEmptyOrNull(MemberProperty memberProperty, object value) { var bagPropertyType = memberProperty.PropertyType as CollectionDataType; ExceptionUtilities.CheckObjectNotNull(bagPropertyType, "Expected property to be a BagProperty instead its a '{0}'", memberProperty.PropertyType); DataType elementDataType = bagPropertyType.ElementDataType; if (value == null) { return(new NullPropertyInstance(memberProperty.Name, elementDataType.BuildMultiValueTypeName())); } else { ExceptionUtilities.Assert(value == EmptyData.Value, "value MUST be null or EmptyData.Value"); PropertyInstance collectionProperty = null; if (elementDataType is ComplexDataType) { collectionProperty = new ComplexMultiValueProperty(memberProperty.Name, new ComplexMultiValue(elementDataType.BuildMultiValueTypeName(), false)); } else { ExceptionUtilities.Assert(elementDataType is PrimitiveDataType, "DataType is not a PrimitiveDataType '{0}'", elementDataType); collectionProperty = new PrimitiveMultiValueProperty(memberProperty.Name, new PrimitiveMultiValue(elementDataType.BuildMultiValueTypeName(), false)); } // Add an empty one if specified to return(collectionProperty); } }
/// <summary> /// Visits a primitive multivalue property and clears its type name /// Note: this has to be done at the property level rather than just at the multivalue in order to maintain the CLR type stack. /// </summary> /// <param name="payloadElement">The primitive multivalue property</param> public override void Visit(PrimitiveMultiValueProperty payloadElement) { this.VisitProperty( payloadElement, payloadElement.Value, () => { payloadElement.Value.ForEach(v => v.FullTypeName = null); }); }
/// <summary> /// Fix up expected collection parameter payload element for comparison. /// </summary> /// <param name="expectedResultPayloadElement"></param> /// <returns>Modified expected collection payload element</returns> internal static ODataPayloadElement FixupExpectedCollectionParameterPayloadElement(ODataPayloadElement expectedResultPayloadElement) { ComplexInstance expected = expectedResultPayloadElement as ComplexInstance; if (expected != null) { List <ComplexMultiValueProperty> propertiesToReplace = new List <ComplexMultiValueProperty>(); List <PrimitiveMultiValueProperty> replacementProperties = new List <PrimitiveMultiValueProperty>(); foreach (PropertyInstance pi in expected.Properties) { PrimitiveMultiValueProperty primitiveCollectionProperty = pi as PrimitiveMultiValueProperty; ComplexMultiValueProperty complexCollectionProperty = pi as ComplexMultiValueProperty; if (primitiveCollectionProperty != null) { // collection parameter is an array of element without type name or result wrapper if (primitiveCollectionProperty.Value.Annotations.OfType <JsonCollectionResultWrapperAnnotation>().Any(a => !a.Value)) { primitiveCollectionProperty.Value.FullTypeName = null; } } else if (complexCollectionProperty != null) { if (complexCollectionProperty.Value.Annotations.OfType <JsonCollectionResultWrapperAnnotation>().Any(a => !a.Value)) { // collection parameter is an array of element without type name or result wrapper complexCollectionProperty.Value.FullTypeName = null; // replace empty ComplexMultiValueProperty with empty PrimitiveMultiValueProperty for comparison since they have the same payload if (complexCollectionProperty.Value.Count == 0) { PrimitiveMultiValueProperty replacementProperty = new PrimitiveMultiValueProperty(complexCollectionProperty.Name, null); replacementProperty.Value.IsNull = complexCollectionProperty.Value.IsNull; foreach (var annotation in complexCollectionProperty.Annotations) { replacementProperty.Annotations.Add(annotation); } propertiesToReplace.Add(complexCollectionProperty); replacementProperties.Add(replacementProperty); } } } } for (int i = 0; i < propertiesToReplace.Count; i++) { expected.Replace(propertiesToReplace[i], replacementProperties[i]); } return(expected); } return(expectedResultPayloadElement); }
/// <summary> /// Visits a payload element whose root is a PrimitiveCollectionProperty. /// </summary> /// <param name="expected">The root node of payload element being visited.</param> public void Visit(PrimitiveMultiValueProperty expected) { ExceptionUtilities.CheckArgumentNotNull(expected, "expected"); var observed = this.GetNextObservedElement <PrimitiveMultiValueProperty>(); using (this.Assert.WithMessage("Primitive multi-value property '{0}' did not match expectation", expected.Name)) { this.Assert.AreEqual(expected.Name, observed.Name, "Property name did not match expectation"); this.CompareAnnotations(expected.Annotations, observed.Annotations); this.WrapAccept(expected.Value, observed.Value); } }
/// <summary> /// Visits a primitive multivalue property and adds a property to the list of values to be written /// </summary> /// <param name="payloadElement">The property to be added to the list</param> public override void Visit(PrimitiveMultiValueProperty payloadElement) { var items = payloadElement.Value.Select(item => item.ClrValue).ToList(); this.odataProperties.Add(new ODataProperty() { Name = payloadElement.Name, Value = new ODataCollectionValue() { Items = items, TypeName = payloadElement.GetAnnotation<EntityModelTypeAnnotation>().EdmModelType.TestFullName() } }); }
/// <summary> /// Visits a payload element whose root is a PrimitiveCollectionProperty. /// </summary> /// <param name="payloadElement">The root node of payload element being visited.</param> public void Visit(PrimitiveMultiValueProperty payloadElement) { bool needsWrapping = this.isRootElement; if (needsWrapping) { this.isRootElement = false; this.writer.StartObjectScope(); } this.writer.WriteName(payloadElement.Name); // if an annotation is present that specifies not to use the wrapper, don't bool useResultsWrapper = !payloadElement.Value.Annotations.OfType <JsonCollectionResultWrapperAnnotation>().Any(a => !a.Value); if (useResultsWrapper) { this.writer.StartObjectScope(); if (payloadElement.Value.FullTypeName != null) { this.writer.WriteName("__metadata"); this.writer.StartObjectScope(); this.writer.WriteName("type"); this.writer.WriteString(payloadElement.Value.FullTypeName); this.writer.EndScope(); } this.writer.WriteName("results"); } if (payloadElement.Value.IsNull) { this.writer.WriteNull(); } else { this.Recurse(payloadElement.Value); } if (useResultsWrapper) { this.writer.EndScope(); } if (needsWrapping) { this.writer.EndScope(); } }
/// <summary> /// Visits a primitive multivalue property and adds a property to the list of values to be written /// </summary> /// <param name="payloadElement">The property to be added to the list</param> public override void Visit(PrimitiveMultiValueProperty payloadElement) { var items = payloadElement.Value.Select(item => item.ClrValue).ToList(); this.odataProperties.Add(new ODataProperty() { Name = payloadElement.Name, Value = new ODataCollectionValue() { Items = items, TypeName = payloadElement.GetAnnotation <EntityModelTypeAnnotation>().EdmModelType.TestFullName() } }); }
/// <summary> /// Visits the children of the given payload element and replaces it with a copy if any child changes /// </summary> /// <param name="payloadElement">The payload element to potentially replace</param> /// <returns>The original element or a copy to replace it with</returns> public virtual ODataPayloadElement Visit(PrimitiveMultiValueProperty payloadElement) { ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement"); var replacedCollection = this.Recurse(payloadElement.Value) as PrimitiveMultiValue; ExceptionUtilities.CheckObjectNotNull(replacedCollection, "Replaced complex collection was null or wrong type"); if (!this.ShouldReplace(payloadElement.Value, replacedCollection)) { return(payloadElement); } return(payloadElement.ReplaceWith(new PrimitiveMultiValueProperty(payloadElement.Name, replacedCollection))); }
/// <summary> /// Visits a payload element whose root is a PrimitiveMultiValueProperty. /// </summary> /// <param name="payloadElement">The root node of the payload element being visited.</param> public override void Visit(PrimitiveMultiValueProperty payloadElement) { base.Visit(payloadElement); if (this.CurrentElementIsRoot()) { Func <MemberProperty, bool> matchesProperty = (p) => { if (p.Name == payloadElement.Name && p.PropertyType is CollectionDataType) { var primitiveElementType = ((CollectionDataType)p.PropertyType).ElementDataType as PrimitiveDataType; return(primitiveElementType != null && payloadElement.Value.FullTypeName == "Collection(" + primitiveElementType.FullEdmName() + ")"); } return(false); }; Func <IEdmProperty, bool> EdmMatchesProperty = (p) => { if (p.Name == payloadElement.Name && p.DeclaringType as IEdmCollectionType != null) { var complexElementType = ((IEdmCollectionType)p.DeclaringType).ElementType as IEdmPrimitiveType; return(complexElementType != null && payloadElement.Value.FullTypeName == "Collection(" + complexElementType.FullName() + ")"); } return(false); }; var valueTypeAnnotation = payloadElement.Value.Annotations.OfType <EntityModelTypeAnnotation>().SingleOrDefault(); if (valueTypeAnnotation != null) { if (valueTypeAnnotation.EdmModelType != null) { var edmEntityType = valueTypeAnnotation.EdmModelType; this.AddExpectedTypeToProperty(payloadElement, edmEntityType, EdmMatchesProperty); } } else { var edmEntityType = this.ResolvePropertyEdmDataType(payloadElement.Value.FullTypeName); this.AddExpectedTypeToProperty(payloadElement, edmEntityType, EdmMatchesProperty); } } this.AnnotateIfOpenProperty(payloadElement, payloadElement.Value); }
/// <summary> /// Build QueryValue from action response payload /// </summary> /// <param name="payload">response payload element</param> /// <param name="queryType">query type to build</param> /// <returns>query value that represents the payload</returns> private QueryValue BuildQueryValueForActionResponse(ODataPayloadElement payload, QueryType queryType) { EntitySetInstance entitySetInstance = payload as EntitySetInstance; PrimitiveProperty primitiveProperty = payload as PrimitiveProperty; ComplexProperty complexProperty = payload as ComplexProperty; PrimitiveMultiValueProperty primitiveMultiValueProperty = payload as PrimitiveMultiValueProperty; ComplexMultiValueProperty complexMultiValueProperty = payload as ComplexMultiValueProperty; PrimitiveCollection primitiveCollection = payload as PrimitiveCollection; ComplexInstanceCollection complexInstanceCollection = payload as ComplexInstanceCollection; if (entitySetInstance != null) { var xmlBaseAnnotations = payload.Annotations.OfType <XmlBaseAnnotation>(); var collectionType = this.currentExpression.ExpressionType as QueryCollectionType; ExceptionUtilities.CheckObjectNotNull(collectionType, "Cannot cast expression type to QueryCollectionType."); var elementType = collectionType.ElementType as QueryEntityType; return(this.BuildFromEntitySetInstance(entitySetInstance, elementType, xmlBaseAnnotations)); } else if (primitiveProperty != null) { return(this.PayloadElementToQueryValueConverter.Convert(primitiveProperty.Value, queryType)); } else if (complexProperty != null) { return(this.PayloadElementToQueryValueConverter.Convert(complexProperty.Value, queryType)); } else if (primitiveMultiValueProperty != null) { return(this.PayloadElementToQueryValueConverter.Convert(primitiveMultiValueProperty.Value, queryType)); } else if (complexMultiValueProperty != null) { return(this.PayloadElementToQueryValueConverter.Convert(complexMultiValueProperty.Value, queryType)); } else if (primitiveCollection != null) { return(this.PayloadElementToQueryValueConverter.Convert(primitiveCollection, queryType)); } else if (complexInstanceCollection != null) { return(this.PayloadElementToQueryValueConverter.Convert(complexInstanceCollection, queryType)); } else { ExceptionUtilities.CheckArgumentNotNull(payload as EntityInstance, "Unexpected response payload type: " + payload.ElementType + "."); return(this.PayloadElementToQueryValueConverter.Convert(payload, queryType)); } }
/// <summary> /// Normalizes primitive multi-value properties, potentially replacing them with primitive collections if the metadata indicates the payload is from a service operation /// </summary> /// <param name="payloadElement">The payload element to potentially replace</param> /// <returns>The original element or a copy to replace it with</returns> public override ODataPayloadElement Visit(PrimitiveMultiValueProperty payloadElement) { var replaced = base.Visit(payloadElement); if (replaced.ElementType == ODataPayloadElementType.PrimitiveMultiValueProperty) { payloadElement = (PrimitiveMultiValueProperty)replaced; if (this.ShouldReplaceWithCollection(payloadElement, payloadElement.Value.IsNull, payloadElement.Value.FullTypeName)) { return payloadElement .ReplaceWith(new PrimitiveCollection(payloadElement.Value.ToArray())) .WithAnnotations(new CollectionNameAnnotation() { Name = payloadElement.Name }); } } return replaced; }
/// <summary> /// Creates a new MultiValue property and sets the value to the collection of primitive values. /// </summary> /// <param name="payloadElement">The primitive collection property to process.</param> public override void Visit(PrimitiveMultiValueProperty payloadElement) { var odataProperty = new ODataProperty() { Name = payloadElement.Name, Value = new ODataCollectionValue() { Items = payloadElement.Value.Select(pv => pv.ClrValue), TypeName = payloadElement.Value.FullTypeName } }; // not calling the base since we don't want to visit the primitive values in the collection this.currentProperties.Add(odataProperty); }
/// <summary> /// Normalizes primitive multi-value properties, potentially replacing them with primitive collections if the metadata indicates the payload is from a service operation /// </summary> /// <param name="payloadElement">The payload element to potentially replace</param> /// <returns>The original element or a copy to replace it with</returns> public override ODataPayloadElement Visit(PrimitiveMultiValueProperty payloadElement) { var replaced = base.Visit(payloadElement); if (replaced.ElementType == ODataPayloadElementType.PrimitiveMultiValueProperty) { payloadElement = (PrimitiveMultiValueProperty)replaced; if (this.ShouldReplaceWithCollection(payloadElement, payloadElement.Value.IsNull, payloadElement.Value.FullTypeName)) { return(payloadElement .ReplaceWith(new PrimitiveCollection(payloadElement.Value.ToArray())) .WithAnnotations(new CollectionNameAnnotation() { Name = payloadElement.Name })); } } return(replaced); }
private static ComplexInstance GenerateSimilarComplexInstance(IRandomNumberGenerator random, ComplexInstance currentInstance, bool randomizePropertyValues = false) { ComplexInstance instance = ((ComplexInstance)currentInstance.DeepCopy()); if (!randomizePropertyValues) { return(instance); } foreach (var property in instance.Properties) { PrimitiveProperty primitive = property as PrimitiveProperty; if (primitive != null) { primitive.Value = TestValues.GetDifferentPrimitiveValue(primitive.Value); } ComplexProperty complex = property as ComplexProperty; if (complex != null) { complex.Value = GenerateSimilarComplexInstance(random, complex.Value); } PrimitiveMultiValueProperty pmultival = property as PrimitiveMultiValueProperty; if (pmultival != null) { pmultival.Value = GenerateSimilarPrimitiveMultiValue(random, pmultival.Value); } ComplexMultiValueProperty cmultival = property as ComplexMultiValueProperty; if (cmultival != null) { cmultival.Value = GenerateSimilarComplexMultiValue(random, cmultival.Value); } } return(instance); }
public PropertyInstance MultiValueProperty(MemberProperty memberProperty, object anonymous) { ExceptionUtilities.CheckArgumentNotNull(memberProperty, "memberProperty"); var collectionType = memberProperty.PropertyType as CollectionDataType; ExceptionUtilities.CheckObjectNotNull(collectionType, "Property '{0}' was not a collection"); var enumerable = anonymous as IEnumerable; ExceptionUtilities.CheckObjectNotNull(enumerable, "Value for property '{0}' was not enumerable"); var primitiveType = collectionType.ElementDataType as PrimitiveDataType; if (primitiveType != null) { var primitiveCollection = new PrimitiveMultiValueProperty(memberProperty.Name, new PrimitiveMultiValue(primitiveType.BuildMultiValueTypeName(), false)); foreach (var thing in enumerable) { primitiveCollection.Value.Add(this.PrimitiveProperty(new MemberProperty("temp", primitiveType), thing).Value); } return(primitiveCollection); } else { var complexType = collectionType.ElementDataType as ComplexDataType; ExceptionUtilities.CheckObjectNotNull(complexType, "Collection property '{0}' did not have a primitive or complex collection type", memberProperty.Name); var complexCollection = new ComplexMultiValueProperty(memberProperty.Name, new ComplexMultiValue(complexType.BuildMultiValueTypeName(), false)); foreach (var thing in enumerable) { complexCollection.Value.Add(this.ComplexInstance(complexType.Definition, thing)); } return(complexCollection); } }
/// <summary> /// Creates a new MultiValue property and sets the value to the collection of primitive values. /// </summary> /// <param name="payloadElement">The primitive collection property to process.</param> public override void Visit(PrimitiveMultiValueProperty payloadElement) { var parent = this.items.Peek(); var odataProperty = new ODataProperty() { Name = payloadElement.Name, Value = new ODataCollectionValue() { Items = payloadElement.Value.Select(pv => pv.ClrValue), TypeName = payloadElement.Value.FullTypeName } }; // not calling the base since we don't want to visit the primitive values in the collection //If there is no parent then this is top level and add to items //otherwise add to parent. if (parent == null) { this.items.Push(odataProperty); } else { var entry = parent as ODataResource; if (entry != null) { var properties = (List <ODataProperty>)entry.Properties; properties.Add(odataProperty); } var complexValue = parent as ODataComplexValue; if (complexValue != null) { var properties = (List <ODataProperty>)complexValue.Properties; properties.Add(odataProperty); complexValue.Properties = properties; } } }
/// <summary> /// Visits a collection of parameters. /// </summary> /// <param name="parameters">The parameters to visit.</param> protected override ODataPayloadElement VisitParameters(ODataParameters parameters) { ExceptionUtilities.CheckArgumentNotNull(parameters, "parameters"); ComplexInstance result = new ComplexInstance(); result.IsNull = parameters.Count == 0; foreach (var parameter in parameters) { if (parameter.Value == null) { result.Add(new PrimitiveProperty(parameter.Key, null, null)); continue; } ODataCollectionStart odataCollectionStart = parameter.Value as ODataCollectionStart; if (odataCollectionStart != null) { ODataCollectionItemsObjectModelAnnotation annotation = odataCollectionStart.GetAnnotation <ODataCollectionItemsObjectModelAnnotation>(); PrimitiveMultiValue primitiveCollection = PayloadBuilder.PrimitiveMultiValue(); foreach (var value in annotation) { primitiveCollection.Item(value); } PrimitiveMultiValueProperty primitiveCollectionProperty = new PrimitiveMultiValueProperty(parameter.Key, primitiveCollection); result.Add(primitiveCollectionProperty); } else { result.Add(new PrimitiveProperty(parameter.Key, null, PayloadBuilder.PrimitiveValue(parameter.Value).ClrValue)); } } return(result); }
public void OpenTopLevelPropertiesTest() { IEdmModel model = TestModels.BuildTestModel(); var testCases = new OpenPropertyTestCase[] { new OpenPropertyTestCase { DebugDescription = "Integer open property.", ExpectedProperty = PayloadBuilder.PrimitiveProperty("OpenProperty", 42), ExpectedPropertyWhenTypeUnavailable = PayloadBuilder.PrimitiveProperty("OpenProperty", 42), ExpectedPropertyType = EdmCoreModel.Instance.GetInt32(false), JsonTypeInformation = "\"" + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataTypeAnnotationName + "\":\"Edm.Int32\",", Json = "{0}{1}\"" + JsonLightConstants.ODataValuePropertyName + "\":42", }, new OpenPropertyTestCase { DebugDescription = "Null open property.", ExpectedProperty = PayloadBuilder.PrimitiveProperty("OpenProperty", null), ExpectedPropertyWhenTypeUnavailable = PayloadBuilder.PrimitiveProperty("OpenProperty", null), ExpectedPropertyType = EdmCoreModel.Instance.GetString(true), JsonTypeInformation = string.Empty, Json = "{0}{1}\"value\":null", }, new OpenPropertyTestCase { DebugDescription = "String open property.", ExpectedProperty = PayloadBuilder.PrimitiveProperty("OpenProperty", "value"), ExpectedPropertyWhenTypeUnavailable = PayloadBuilder.PrimitiveProperty("OpenProperty", "value"), ExpectedPropertyType = EdmCoreModel.Instance.GetString(true), JsonTypeInformation = "\"" + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataTypeAnnotationName + "\":\"Edm.String\",", Json = "{0}{1}\"" + JsonLightConstants.ODataValuePropertyName + "\":\"" + JsonLightConstants.ODataValuePropertyName + "\"", }, new OpenPropertyTestCase { DebugDescription = "DateTimeOffset open property with type information.", ExpectedProperty = PayloadBuilder.PrimitiveProperty("OpenProperty", new DateTimeOffset(2012, 4, 13, 2, 43, 10, 215, TimeSpan.Zero)), ExpectedPropertyWhenTypeUnavailable = PayloadBuilder.PrimitiveProperty("OpenProperty", "2012-04-13T02:43:10.215Z"), ExpectedPropertyType = EdmCoreModel.Instance.GetDateTimeOffset(false), JsonTypeInformation = "\"" + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataTypeAnnotationName + "\":\"Edm.DateTimeOffset\",", Json = "{0}{1}\"" + JsonLightConstants.ODataValuePropertyName + "\":\"2012-04-13T02:43:10.215Z\"", }, }; bool[] withExpectedTypes = new bool[] { true, false }; bool[] withPayloadTypes = new bool[] { true, false }; bool[] includeContextUri = new bool[] { true, false }; this.CombinatorialEngineProvider.RunCombinations( testCases, withExpectedTypes, withPayloadTypes, includeContextUri, this.ReaderTestConfigurationProvider.JsonLightFormatConfigurations, (testCase, withExpectedType, withPayloadType, withContextUri, testConfiguration) => { if (withContextUri && testConfiguration.IsRequest) { return; } string expectedTypeName = testCase.ExpectedPropertyType is IEdmCollectionTypeReference ? "Collection(" + ((IEdmCollectionType)testCase.ExpectedPropertyType.Definition).ElementType.FullName() + ")" : testCase.ExpectedPropertyType.TestFullName(); string contextUri = withContextUri ? "\"" + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataContextAnnotationName + string.Format("\":\"http://odata.org/test/$metadata#{0}\",", expectedTypeName) : string.Empty; string json = string.Format( CultureInfo.InvariantCulture, testCase.Json, contextUri, withPayloadType ? testCase.JsonTypeInformation : string.Empty); bool typeGiven = withExpectedType || withPayloadType || withContextUri; if (!typeGiven && testCase.ExpectedPropertyWhenTypeUnavailable == null) { testCase.ExpectedException = ODataExpectedExceptions.ODataException("ReaderValidationUtils_ValueWithoutType"); } PropertyInstance property = typeGiven || testCase.ExpectedPropertyWhenTypeUnavailable == null ? testCase.ExpectedProperty : testCase.ExpectedPropertyWhenTypeUnavailable; property = property.DeepCopy(); if (withExpectedType) { property = property.ExpectedPropertyType(testCase.ExpectedPropertyType); } if (!withPayloadType) { ComplexProperty complexProperty = property as ComplexProperty; if (complexProperty != null) { complexProperty.Value.AddAnnotation(new SerializationTypeNameTestAnnotation() { TypeName = null }); } else { PrimitiveMultiValueProperty primitiveCollectionProperty = property as PrimitiveMultiValueProperty; if (primitiveCollectionProperty != null) { primitiveCollectionProperty.Value.AddAnnotation(new SerializationTypeNameTestAnnotation() { TypeName = null }); } else { ComplexMultiValueProperty complexCollectionProperty = property as ComplexMultiValueProperty; if (complexCollectionProperty != null) { complexCollectionProperty.Value.AddAnnotation(new SerializationTypeNameTestAnnotation() { TypeName = null }); } } } } ExpectedException expectedException = testCase.ExpectedException; if (!withContextUri && !testConfiguration.IsRequest) { expectedException = ODataExpectedExceptions.ODataException("ODataJsonLightDeserializer_ContextLinkNotFoundAsFirstProperty"); } PayloadReaderTestDescriptor testDescriptor = new PayloadReaderTestDescriptor(this.Settings) { DebugDescription = testCase.DebugDescription + "[Expected type: " + withExpectedType + ", payload type: " + withPayloadType + "]", PayloadElement = property .JsonRepresentation("{" + json + "}"), PayloadEdmModel = model, ExpectedException = expectedException, }; // These descriptors are already tailored specifically for Json Light and // do not require normalization. testDescriptor.TestDescriptorNormalizers.Clear(); testDescriptor.RunTest(testConfiguration); }); }
/// <summary> /// Deserializes the element as either a complex, a primitive, or a null property, based on the content /// </summary> /// <param name="property">The xml to deserialize</param> /// <param name="typeNameFallback">TypeName to use instead of the one from the XElement[type] attribute</param> /// <returns>A property representing the given xml</returns> private PropertyInstance DeserializeProperty(XElement property, string typeNameFallback) { string propertyName = property.Name.LocalName; // get the type name string typeNameFromPayload = null; XAttribute typeAttribute = property.Attribute(MetadataType); if (typeAttribute != null) { typeNameFromPayload = typeAttribute.Value; } // set type to be fallback when typeattribute does not exist var typeNameForClrTypeLookup = typeNameFromPayload; if (typeNameForClrTypeLookup == null && !string.IsNullOrEmpty(typeNameFallback)) { typeNameForClrTypeLookup = typeNameFallback; } // try to infer the clr type Type clrType = null; if (!string.IsNullOrEmpty(typeNameForClrTypeLookup)) { ExceptionUtilities.CheckObjectNotNull(this.PrimitiveDataTypeConverter, "Cannot infer clr type from edm type without converter"); clrType = this.PrimitiveDataTypeConverter.ToClrType(typeNameForClrTypeLookup); } PropertyInstance result; if (property.HasElements) { // must be complex, a multivalue, or spatial ExceptionUtilities.CheckObjectNotNull(this.SpatialFormatter, "Cannot safely deserialize element with children without spatial formatter."); // try to infer which spatial type hierarchy it is from the type name in the payload SpatialTypeKind?kind = null; if (clrType != null) { SpatialUtilities.TryInferSpatialTypeKind(clrType, out kind); } object spatialInstance; if (this.SpatialFormatter.TryParse(property.Elements().First(), kind, out spatialInstance)) { ExceptionUtilities.Assert(property.Elements().Count() == 1, "Spatial property had more than 1 sub-element"); result = new PrimitiveProperty(propertyName, typeNameFromPayload, spatialInstance); } else if (property.Elements().All(e => e.Name == DataServicesElement)) { result = this.DeserializeCollectionProperty(property); } else { result = new ComplexProperty(propertyName, this.DeserializeComplexInstance(property)); } } else { // check for the null attribute bool isNull = false; XAttribute isNullAttribute = property.Attribute(MetadataNull); if (isNullAttribute != null) { isNull = bool.Parse(isNullAttribute.Value); } // If its null and we can't tell whether it is primitive or complex, then return a null marker if (isNull && clrType == null) { result = new NullPropertyInstance(propertyName, typeNameFromPayload); } else if (typeNameFromPayload != null && typeNameFromPayload.StartsWith(ODataConstants.BeginMultiValueTypeIdentifier, StringComparison.Ordinal)) { ExceptionUtilities.CheckObjectNotNull(this.PrimitiveDataTypeConverter, "Cannot infer clr type from edm type without converter"); string elementTypeName = ParseBagElementTypeName(typeNameFromPayload); if (this.PrimitiveDataTypeConverter.ToClrType(elementTypeName) != null) { result = new PrimitiveMultiValueProperty(propertyName, new PrimitiveMultiValue(typeNameFromPayload, isNull)); } else { result = new ComplexMultiValueProperty(propertyName, new ComplexMultiValue(typeNameFromPayload, isNull)); } } else { object value; if (isNull) { value = null; } else if (clrType != null) { ExceptionUtilities.CheckObjectNotNull(this.PrimitiveConverter, "PrimitiveConverter has not been set."); value = this.PrimitiveConverter.DeserializePrimitive(property.Value, clrType); } else { value = property.Value; } result = new PrimitiveProperty(propertyName, typeNameFromPayload, value); } } AddXmlBaseAnnotation(result, property); return(result); }
/// <summary> /// Deserializes a collection property /// </summary> /// <param name="propertyElement">The xml element representing the property</param> /// <returns>The deserialized property</returns> private PropertyInstance DeserializeCollectionProperty(XElement propertyElement) { ExceptionUtilities.CheckArgumentNotNull(propertyElement, "propertyElement"); ExceptionUtilities.CheckCollectionNotEmpty(propertyElement.Elements(), "propertyElement.Elements()"); ExceptionUtilities.Assert(propertyElement.Elements().All(e => e.Name == DataServicesElement), "Collection property sub elements had inconsistent names"); string propertyName = propertyElement.Name.LocalName; string fullTypeName = null; string bagElementTypeName = null; var type = propertyElement.Attribute(MetadataType); if (type != null) { fullTypeName = type.Value; bagElementTypeName = ParseBagElementTypeName(type.Value); } // convert the elements first, then decide if its a primitive or complex collection // note that a collection containing all null values will appear as a primitive collection, regardless of what the type really is List <PropertyInstance> elements = null; if (bagElementTypeName != null) { elements = propertyElement.Elements().Select(e => this.DeserializeProperty(e, bagElementTypeName)).ToList(); } else { elements = propertyElement.Elements().Select(e => this.DeserializeProperty(e)).ToList(); } if (elements.OfType <ComplexProperty>().Any()) { var complex = new ComplexMultiValueProperty(propertyName, new ComplexMultiValue(fullTypeName, false)); foreach (var complexElement in elements) { if (complexElement.ElementType == ODataPayloadElementType.NullPropertyInstance) { var nullProperty = complexElement as NullPropertyInstance; complex.Value.Add(new ComplexInstance(nullProperty.FullTypeName, true)); } else { ExceptionUtilities.Assert(complexElement.ElementType == ODataPayloadElementType.ComplexProperty, "Complex value collection contained non-complex, non-null value"); complex.Value.Add((complexElement as ComplexProperty).Value); } } return(complex); } else { var primitive = new PrimitiveMultiValueProperty(propertyName, new PrimitiveMultiValue(fullTypeName, false)); foreach (var primitiveElement in elements) { if (primitiveElement.ElementType == ODataPayloadElementType.NullPropertyInstance) { var nullProperty = primitiveElement as NullPropertyInstance; primitive.Value.Add(new PrimitiveValue(nullProperty.FullTypeName, null)); } else { ExceptionUtilities.Assert(primitiveElement.ElementType == ODataPayloadElementType.PrimitiveProperty, "Primitive value collection contained non-primitive, non-null value"); primitive.Value.Add((primitiveElement as PrimitiveProperty).Value); } } return(primitive); } }
/// <summary> /// Visits a collection of parameters. /// </summary> /// <param name="parameters">The parameters to visit.</param> protected override ODataPayloadElement VisitParameters(ODataParameters parameters) { ExceptionUtilities.CheckArgumentNotNull(parameters, "parameters"); ComplexInstance result = new ComplexInstance(); result.IsNull = parameters.Count == 0; foreach (var parameter in parameters) { if (parameter.Value == null) { result.Add(new PrimitiveProperty(parameter.Key, null, null)); continue; } ODataComplexValue odataComplexValue = parameter.Value as ODataComplexValue; ODataCollectionStart odataCollectionStart = parameter.Value as ODataCollectionStart; if (odataCollectionStart != null) { ODataCollectionItemsObjectModelAnnotation annotation = odataCollectionStart.GetAnnotation <ODataCollectionItemsObjectModelAnnotation>(); if (annotation.OfType <ODataComplexValue>().FirstOrDefault() != null) { ComplexMultiValue complexCollection = PayloadBuilder.ComplexMultiValue(); foreach (var value in annotation) { complexCollection.Item(this.VisitComplexValue(value as ODataComplexValue) as ComplexInstance); } ComplexMultiValueProperty complexCollectionProperty = new ComplexMultiValueProperty(parameter.Key, complexCollection); result.Add(complexCollectionProperty); } else { PrimitiveMultiValue primitiveCollection = PayloadBuilder.PrimitiveMultiValue(); foreach (var value in annotation) { primitiveCollection.Item(value); } PrimitiveMultiValueProperty primitiveCollectionProperty = new PrimitiveMultiValueProperty(parameter.Key, primitiveCollection); result.Add(primitiveCollectionProperty); } } else if (odataComplexValue != null) { ComplexInstance complexInstance = PayloadBuilder.ComplexValue(odataComplexValue.TypeName); complexInstance.IsNull = false; foreach (ODataProperty odataProperty in odataComplexValue.Properties) { complexInstance.Property(odataProperty.Name, this.Visit(odataProperty.Value)); } result.Add(new ComplexProperty(parameter.Key, complexInstance)); } else { result.Add(new PrimitiveProperty(parameter.Key, null, PayloadBuilder.PrimitiveValue(parameter.Value).ClrValue)); } } return(result); }
/// <summary> /// Visits a payload element whose root is a PrimitiveMultiValueProperty. /// </summary> /// <param name="payloadElement">The root node of the payload element being visited.</param> public override void Visit(PrimitiveMultiValueProperty payloadElement) { base.Visit(payloadElement); if (this.CurrentElementIsRoot()) { Func<MemberProperty, bool> matchesProperty = (p) => { if (p.Name == payloadElement.Name && p.PropertyType is CollectionDataType) { var primitiveElementType = ((CollectionDataType)p.PropertyType).ElementDataType as PrimitiveDataType; return primitiveElementType != null && payloadElement.Value.FullTypeName == "Collection(" + primitiveElementType.FullEdmName() + ")"; } return false; }; Func<IEdmProperty, bool> EdmMatchesProperty = (p) => { if (p.Name == payloadElement.Name && p.DeclaringType as IEdmCollectionType != null) { var complexElementType = ((IEdmCollectionType)p.DeclaringType).ElementType as IEdmPrimitiveType; return complexElementType != null && payloadElement.Value.FullTypeName == "Collection(" + complexElementType.FullName() + ")"; } return false; }; var valueTypeAnnotation = payloadElement.Value.Annotations.OfType<EntityModelTypeAnnotation>().SingleOrDefault(); if (valueTypeAnnotation != null) { if (valueTypeAnnotation.EdmModelType != null) { var edmEntityType = valueTypeAnnotation.EdmModelType; this.AddExpectedTypeToProperty(payloadElement, edmEntityType, EdmMatchesProperty); } } else { var edmEntityType = this.ResolvePropertyEdmDataType(payloadElement.Value.FullTypeName); this.AddExpectedTypeToProperty(payloadElement, edmEntityType, EdmMatchesProperty); } } this.AnnotateIfOpenProperty(payloadElement, payloadElement.Value); }
/// <summary> /// Fix up expected collection parameter payload element for comparison. /// </summary> /// <param name="expectedResultPayloadElement"></param> /// <returns>Modified expected collection payload element</returns> internal static ODataPayloadElement FixupExpectedCollectionParameterPayloadElement(ODataPayloadElement expectedResultPayloadElement) { ComplexInstance expected = expectedResultPayloadElement as ComplexInstance; if (expected != null) { List<ComplexMultiValueProperty> propertiesToReplace = new List<ComplexMultiValueProperty>(); List<PrimitiveMultiValueProperty> replacementProperties = new List<PrimitiveMultiValueProperty>(); foreach (PropertyInstance pi in expected.Properties) { PrimitiveMultiValueProperty primitiveCollectionProperty = pi as PrimitiveMultiValueProperty; ComplexMultiValueProperty complexCollectionProperty = pi as ComplexMultiValueProperty; if (primitiveCollectionProperty != null) { // collection parameter is an array of element without type name or result wrapper if (primitiveCollectionProperty.Value.Annotations.OfType<JsonCollectionResultWrapperAnnotation>().Any(a => !a.Value)) { primitiveCollectionProperty.Value.FullTypeName = null; } } else if (complexCollectionProperty != null) { if (complexCollectionProperty.Value.Annotations.OfType<JsonCollectionResultWrapperAnnotation>().Any(a => !a.Value)) { // collection parameter is an array of element without type name or result wrapper complexCollectionProperty.Value.FullTypeName = null; // replace empty ComplexMultiValueProperty with empty PrimitiveMultiValueProperty for comparison since they have the same payload if (complexCollectionProperty.Value.Count == 0) { PrimitiveMultiValueProperty replacementProperty = new PrimitiveMultiValueProperty(complexCollectionProperty.Name, null); replacementProperty.Value.IsNull = complexCollectionProperty.Value.IsNull; foreach (var annotation in complexCollectionProperty.Annotations) { replacementProperty.Annotations.Add(annotation); } propertiesToReplace.Add(complexCollectionProperty); replacementProperties.Add(replacementProperty); } } } } for (int i = 0; i < propertiesToReplace.Count; i++) { expected.Replace(propertiesToReplace[i], replacementProperties[i]); } return expected; } return expectedResultPayloadElement; }
/// <summary> /// Normalizes primitive collection property. /// </summary> /// <param name="payloadElement">The payload element to normalize.</param> public override void Visit(PrimitiveMultiValueProperty payloadElement) { base.Visit(payloadElement); this.NormalizePropertyName(payloadElement); }
public override void Visit(PrimitiveMultiValueProperty payloadElement) { base.Visit(payloadElement); this.ReplaceExpectedTypeAnnotationIfRootElement(payloadElement); }
/// <summary> /// Creates a new MultiValue property and sets the value to the collection of primitive values. /// </summary> /// <param name="payloadElement">The primitive collection property to process.</param> public override void Visit(PrimitiveMultiValueProperty payloadElement) { var parent = this.items.Peek(); var odataProperty = new ODataProperty() { Name = payloadElement.Name, Value = new ODataCollectionValue() { Items = payloadElement.Value.Select(pv => pv.ClrValue), TypeName = payloadElement.Value.FullTypeName } }; // not calling the base since we don't want to visit the primitive values in the collection //If there is no parent then this is top level and add to items //otherwise add to parent. if (parent == null) { this.items.Push(odataProperty); } else { var entry = parent as ODataEntry; if (entry != null) { var properties = (List<ODataProperty>)entry.Properties; properties.Add(odataProperty); } var complexValue = parent as ODataComplexValue; if (complexValue != null) { var properties = (List<ODataProperty>)complexValue.Properties; properties.Add(odataProperty); complexValue.Properties = properties; } } }
/// <summary> /// Visits the payload element /// </summary> /// <param name="payloadElement">The payload element to visit</param> public virtual void Visit(PrimitiveMultiValueProperty payloadElement) { ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement"); this.VisitProperty(payloadElement, payloadElement.Value); }
private static PrimitiveMultiValueProperty GetPrimitiveMultiValueProperty(IRandomNumberGenerator random) { var val = random.ChooseFrom(TestValues.CreatePrimitiveCollections(true, true)); var payload = new PrimitiveMultiValueProperty("ArbitraryMultivalue", val); return payload; }
/// <summary> /// Visits a payload element whose root is a PrimitiveMultiValueProperty. /// </summary> /// <param name="payloadElement">The root node of payload element being visited.</param> public void Visit(PrimitiveMultiValueProperty payloadElement) { ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement"); var current = this.expectedValueStack.Peek(); var value = current as QueryCollectionValue; ExceptionUtilities.CheckObjectNotNull(value, "Value was not a collection. Value was: '{0}'", current.ToString()); this.RecurseWithMessage(payloadElement.Value, value, "Primitive multi-value property '{0}' did not match expectation", payloadElement.Name); }
/// <summary> /// Creates a set of interesting entity instances along with metadata. /// </summary> /// <param name="settings">The test descriptor settings to use.</param> /// <param name="model">If non-null, the method creates complex types for the complex values and adds them to the model.</param> /// <param name="withTypeNames">true if the payloads should specify type names.</param> /// <returns>List of test descriptors with interesting entity instances as payload.</returns> public static IEnumerable <PayloadTestDescriptor> CreateEntityInstanceTestDescriptors( EdmModel model, bool withTypeNames) { IEnumerable <PrimitiveValue> primitiveValues = TestValues.CreatePrimitiveValuesWithMetadata(fullSet: false); IEnumerable <ComplexInstance> complexValues = TestValues.CreateComplexValues(model, withTypeNames, fullSet: false); IEnumerable <NamedStreamInstance> streamReferenceValues = TestValues.CreateStreamReferenceValues(fullSet: false); IEnumerable <PrimitiveMultiValue> primitiveMultiValues = TestValues.CreatePrimitiveCollections(withTypeNames, fullSet: false); IEnumerable <ComplexMultiValue> complexMultiValues = TestValues.CreateComplexCollections(model, withTypeNames, fullSet: false); IEnumerable <NavigationPropertyInstance> navigationProperties = TestValues.CreateDeferredNavigationLinks(); // NOTE we have to copy the EntityModelTypeAnnotation on the primitive value to the NullPropertyInstance for null values since the // NullPropertyInstance does not expose a value. We will later copy it back to the value we generate for the null property. IEnumerable <PropertyInstance> primitiveProperties = primitiveValues.Select((pv, ix) => PayloadBuilder.Property("PrimitiveProperty" + ix, pv).CopyAnnotation <PropertyInstance, EntityModelTypeAnnotation>(pv)); IEnumerable <PropertyInstance> complexProperties = complexValues.Select((cv, ix) => PayloadBuilder.Property("ComplexProperty" + ix, cv)); IEnumerable <PropertyInstance> primitiveMultiValueProperties = primitiveMultiValues.Select((pmv, ix) => PayloadBuilder.Property("PrimitiveMultiValueProperty" + ix, pmv)); IEnumerable <PropertyInstance> complexMultiValueProperties = complexMultiValues.Select((cmv, ix) => PayloadBuilder.Property("ComplexMultiValueProperty" + ix, cmv)); PropertyInstance[][] propertyMatrix = new PropertyInstance[6][]; propertyMatrix[0] = primitiveProperties.ToArray(); propertyMatrix[1] = complexProperties.ToArray(); propertyMatrix[2] = streamReferenceValues.ToArray(); propertyMatrix[3] = primitiveMultiValueProperties.ToArray(); propertyMatrix[4] = complexMultiValueProperties.ToArray(); propertyMatrix[5] = navigationProperties.ToArray(); IEnumerable <PropertyInstance[]> propertyCombinations = propertyMatrix.ColumnCombinations(0, 1, 6); int count = 0; foreach (PropertyInstance[] propertyCombination in propertyCombinations) { // build the entity type, add it to the model EdmEntityType generatedEntityType = null; string typeName = "PGEntityType" + count; EdmEntityContainer container = null; EdmEntitySet entitySet = null; if (model != null) { // generate a new type with the auto-generated name, check that no type with this name exists and add the default key property to it. Debug.Assert(model.FindDeclaredType(typeName) == null, "Entity type '" + typeName + "' already exists."); generatedEntityType = new EdmEntityType("TestModel", typeName); generatedEntityType.AddKeys(generatedEntityType.AddStructuralProperty("Id", EdmPrimitiveTypeKind.Int32)); model.AddElement(generatedEntityType); container = model.EntityContainer as EdmEntityContainer; if (container == null) { container = new EdmEntityContainer("TestModel", "DefaultNamespace"); model.AddElement(container); } entitySet = container.AddEntitySet(typeName, generatedEntityType); } EntityInstance entityInstance = PayloadBuilder.Entity("TestModel." + typeName) .Property("Id", PayloadBuilder.PrimitiveValue(count).WithTypeAnnotation(EdmCoreModel.Instance.GetInt32(false))); for (int i = 0; i < propertyCombination.Length; ++i) { PropertyInstance currentProperty = propertyCombination[i]; entityInstance.Add(currentProperty); if (model != null) { if (entitySet == null) { entitySet = container.FindEntitySet(typeName) as EdmEntitySet; } switch (currentProperty.ElementType) { case ODataPayloadElementType.ComplexProperty: ComplexProperty complexProperty = (ComplexProperty)currentProperty; generatedEntityType.AddStructuralProperty(complexProperty.Name, complexProperty.Value.GetAnnotation <EntityModelTypeAnnotation>().EdmModelType); break; case ODataPayloadElementType.PrimitiveProperty: PrimitiveProperty primitiveProperty = (PrimitiveProperty)currentProperty; if (primitiveProperty.Value == null) { generatedEntityType.AddStructuralProperty( primitiveProperty.Name, PayloadBuilder.PrimitiveValueType(null)); } else { generatedEntityType.AddStructuralProperty(primitiveProperty.Name, primitiveProperty.Value.GetAnnotation <EntityModelTypeAnnotation>().EdmModelType); } break; case ODataPayloadElementType.NamedStreamInstance: NamedStreamInstance streamProperty = (NamedStreamInstance)currentProperty; generatedEntityType.AddStructuralProperty(streamProperty.Name, EdmPrimitiveTypeKind.Stream); break; case ODataPayloadElementType.EmptyCollectionProperty: throw new NotImplementedException(); case ODataPayloadElementType.NavigationPropertyInstance: NavigationPropertyInstance navigationProperty = (NavigationPropertyInstance)currentProperty; var navProperty = generatedEntityType.AddUnidirectionalNavigation(new EdmNavigationPropertyInfo() { ContainsTarget = false, Name = navigationProperty.Name, Target = generatedEntityType, TargetMultiplicity = EdmMultiplicity.One }); entitySet.AddNavigationTarget(navProperty, entitySet); break; case ODataPayloadElementType.ComplexMultiValueProperty: ComplexMultiValueProperty complexMultiValueProperty = (ComplexMultiValueProperty)currentProperty; generatedEntityType.AddStructuralProperty(complexMultiValueProperty.Name, complexMultiValueProperty.Value.GetAnnotation <EntityModelTypeAnnotation>().EdmModelType); break; case ODataPayloadElementType.PrimitiveMultiValueProperty: PrimitiveMultiValueProperty primitiveMultiValueProperty = (PrimitiveMultiValueProperty)currentProperty; generatedEntityType.AddStructuralProperty(primitiveMultiValueProperty.Name, primitiveMultiValueProperty.Value.GetAnnotation <EntityModelTypeAnnotation>().EdmModelType); break; default: throw new NotSupportedException("Unsupported element type found : " + propertyCombination[i].ElementType); } } } if (generatedEntityType != null) { entityInstance.AddAnnotation(new EntityModelTypeAnnotation(generatedEntityType.ToTypeReference(true))); } yield return(new PayloadTestDescriptor() { PayloadElement = entityInstance, PayloadEdmModel = model }); count++; } }
/// <summary> /// Builds a complex instance from the given payloadElements to represent a parameters payload. /// </summary> /// <param name="payloadElements">Each ODataPayloadElement represents the value for each parameter.</param> /// <param name="model">EdmModel instance.</param> /// <param name="functionImportName">Name of the function import to add to the model.</param> /// <returns></returns> private static ComplexInstance PayloadElementsToParameterPayload(ODataPayloadElement[] payloadElements, EdmModel model, string functionImportName) { EdmOperationImport operationImport = (EdmOperationImport)model.EntityContainer.FindOperationImports(functionImportName).FirstOrDefault(); EdmOperation operation = (EdmOperation)operationImport.Operation; var parameterPayload = new ComplexInstance(null, false); for (int idx = 0; idx < payloadElements.Length; idx++) { ODataPayloadElement p = payloadElements[idx]; string parameterName = "p" + idx; PropertyInstance parameter; IEdmTypeReference entityModelType = p.GetAnnotation <EntityModelTypeAnnotation>().EdmModelType; switch (p.ElementType) { case ODataPayloadElementType.PrimitiveValue: object clrValue = ((PrimitiveValue)p).ClrValue; PrimitiveValue primitiveValue = new PrimitiveValue(clrValue == null ? null : clrValue.GetType().FullName, clrValue); primitiveValue.CopyAnnotation <PrimitiveValue, EntityModelTypeAnnotation>(p); parameter = new PrimitiveProperty(parameterName, primitiveValue); operation.AddParameter(parameterName, MetadataUtils.GetPrimitiveTypeReference(primitiveValue.ClrValue.GetType())); break; case ODataPayloadElementType.ComplexInstance: parameter = new ComplexProperty(parameterName, (ComplexInstance)p); operation.AddParameter(parameterName, entityModelType); break; case ODataPayloadElementType.PrimitiveMultiValue: PrimitiveMultiValue primitiveMultiValue = (PrimitiveMultiValue)p; if (primitiveMultiValue.Annotations.OfType <JsonCollectionResultWrapperAnnotation>().SingleOrDefault() == null) { primitiveMultiValue.Annotations.Add(new JsonCollectionResultWrapperAnnotation(false)); } parameter = new PrimitiveMultiValueProperty(parameterName, primitiveMultiValue); operation.AddParameter(parameterName, entityModelType); break; case ODataPayloadElementType.ComplexMultiValue: ComplexMultiValue complexMultiValue = (ComplexMultiValue)p; if (complexMultiValue.Annotations.OfType <JsonCollectionResultWrapperAnnotation>().SingleOrDefault() == null) { complexMultiValue.Annotations.Add(new JsonCollectionResultWrapperAnnotation(false)); } parameter = new ComplexMultiValueProperty(parameterName, complexMultiValue); operation.AddParameter(parameterName, entityModelType); break; case ODataPayloadElementType.EntityInstance: parameter = new NavigationPropertyInstance(parameterName, (EntityInstance)p); operation.AddParameter(parameterName, entityModelType); break; case ODataPayloadElementType.EntitySetInstance: parameter = new NavigationPropertyInstance(parameterName, (EntitySetInstance)p); operation.AddParameter(parameterName, entityModelType); break; default: throw new NotSupportedException("PayloadElementsToParameterPayload() is called on unsupported ODataPayloadElement type: " + p.ElementType); } parameterPayload.Add(parameter); } parameterPayload.ExpectedFunctionImport(operationImport); return(parameterPayload); }
/// <summary> /// Visits a PrimitiveMultiValueProperty, if it visits this it will be a V3 payload /// </summary> /// <param name="payloadElement">payload Element</param> public override void Visit(PrimitiveMultiValueProperty payloadElement) { ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement"); this.IncreaseVersionIfRequired(DataServiceProtocolVersion.V4); base.Visit(payloadElement); }
public PropertyInstance MultiValuePropertyEmptyOrNull(MemberProperty memberProperty, object value) { var bagPropertyType = memberProperty.PropertyType as CollectionDataType; ExceptionUtilities.CheckObjectNotNull(bagPropertyType, "Expected property to be a BagProperty instead its a '{0}'", memberProperty.PropertyType); DataType elementDataType = bagPropertyType.ElementDataType; if (value == null) { return new NullPropertyInstance(memberProperty.Name, elementDataType.BuildMultiValueTypeName()); } else { ExceptionUtilities.Assert(value == EmptyData.Value, "value MUST be null or EmptyData.Value"); PropertyInstance collectionProperty = null; if (elementDataType is ComplexDataType) { collectionProperty = new ComplexMultiValueProperty(memberProperty.Name, new ComplexMultiValue(elementDataType.BuildMultiValueTypeName(), false)); } else { ExceptionUtilities.Assert(elementDataType is PrimitiveDataType, "DataType is not a PrimitiveDataType '{0}'", elementDataType); collectionProperty = new PrimitiveMultiValueProperty(memberProperty.Name, new PrimitiveMultiValue(elementDataType.BuildMultiValueTypeName(), false)); } // Add an empty one if specified to return collectionProperty; } }
/// <summary> /// Visits the payload element. /// </summary> /// <param name="payloadElement">The payload element to visit.</param> public override void Visit(PrimitiveMultiValueProperty payloadElement) { var observed = this.GetNextObservedElement <PrimitiveMultiValueProperty>(); this.WrapAccept(payloadElement.Value, observed.Value); }
/// <summary> /// Visits a payload element whose root is a PrimitiveCollectionProperty. /// </summary> /// <param name="payloadElement">The root node of payload element being visited.</param> public void Visit(PrimitiveMultiValueProperty payloadElement) { bool needsWrapping = this.isRootElement; if (needsWrapping) { this.isRootElement = false; this.writer.StartObjectScope(); } this.writer.WriteName(payloadElement.Name); // if an annotation is present that specifies not to use the wrapper, don't bool useResultsWrapper = !payloadElement.Value.Annotations.OfType<JsonCollectionResultWrapperAnnotation>().Any(a => !a.Value); if (useResultsWrapper) { this.writer.StartObjectScope(); if (payloadElement.Value.FullTypeName != null) { this.writer.WriteName("__metadata"); this.writer.StartObjectScope(); this.writer.WriteName("type"); this.writer.WriteString(payloadElement.Value.FullTypeName); this.writer.EndScope(); } this.writer.WriteName("results"); } if (payloadElement.Value.IsNull) { this.writer.WriteNull(); } else { this.Recurse(payloadElement.Value); } if (useResultsWrapper) { this.writer.EndScope(); } if (needsWrapping) { this.writer.EndScope(); } }
/// <summary> /// Builds a complex instance from the given payloadElements to represent a parameters payload. /// </summary> /// <param name="payloadElements">Each ODataPayloadElement represents the value for each parameter.</param> /// <param name="model">EdmModel instance.</param> /// <param name="functionImportName">Name of the function import to add to the model.</param> /// <returns></returns> private static ComplexInstance PayloadElementsToParameterPayload(ODataPayloadElement[] payloadElements, EdmModel model, string functionImportName) { EdmOperationImport operationImport = (EdmOperationImport)model.EntityContainer.FindOperationImports(functionImportName).FirstOrDefault(); EdmOperation operation = (EdmOperation)operationImport.Operation; var parameterPayload = new ComplexInstance(null, false); for (int idx = 0; idx < payloadElements.Length; idx++) { ODataPayloadElement p = payloadElements[idx]; string parameterName = "p" + idx; PropertyInstance parameter; IEdmTypeReference entityModelType = p.GetAnnotation<EntityModelTypeAnnotation>().EdmModelType; switch (p.ElementType) { case ODataPayloadElementType.PrimitiveValue: object clrValue = ((PrimitiveValue)p).ClrValue; PrimitiveValue primitiveValue = new PrimitiveValue(clrValue == null ? null : clrValue.GetType().FullName, clrValue); primitiveValue.CopyAnnotation<PrimitiveValue, EntityModelTypeAnnotation>(p); parameter = new PrimitiveProperty(parameterName, primitiveValue); operation.AddParameter(parameterName, MetadataUtils.GetPrimitiveTypeReference(primitiveValue.ClrValue.GetType())); break; case ODataPayloadElementType.ComplexInstance: parameter = new ComplexProperty(parameterName, (ComplexInstance)p); operation.AddParameter(parameterName, entityModelType); break; case ODataPayloadElementType.PrimitiveMultiValue: PrimitiveMultiValue primitiveMultiValue = (PrimitiveMultiValue)p; if (primitiveMultiValue.Annotations.OfType<JsonCollectionResultWrapperAnnotation>().SingleOrDefault() == null) { primitiveMultiValue.Annotations.Add(new JsonCollectionResultWrapperAnnotation(false)); } parameter = new PrimitiveMultiValueProperty(parameterName, primitiveMultiValue); operation.AddParameter(parameterName, entityModelType); break; case ODataPayloadElementType.ComplexMultiValue: ComplexMultiValue complexMultiValue = (ComplexMultiValue)p; if (complexMultiValue.Annotations.OfType<JsonCollectionResultWrapperAnnotation>().SingleOrDefault() == null) { complexMultiValue.Annotations.Add(new JsonCollectionResultWrapperAnnotation(false)); } parameter = new ComplexMultiValueProperty(parameterName, complexMultiValue); operation.AddParameter(parameterName, entityModelType); break; case ODataPayloadElementType.EntityInstance: parameter = new NavigationPropertyInstance(parameterName, (EntityInstance)p); operation.AddParameter(parameterName, entityModelType); break; case ODataPayloadElementType.EntitySetInstance: parameter = new NavigationPropertyInstance(parameterName, (EntitySetInstance)p); operation.AddParameter(parameterName, entityModelType); break; default: throw new NotSupportedException("PayloadElementsToParameterPayload() is called on unsupported ODataPayloadElement type: " + p.ElementType); } parameterPayload.Add(parameter); } parameterPayload.ExpectedFunctionImport(operationImport); return parameterPayload; }
/// <summary> /// Deserializes a collection property /// </summary> /// <param name="propertyElement">The xml element representing the property</param> /// <returns>The deserialized property</returns> private PropertyInstance DeserializeCollectionProperty(XElement propertyElement) { ExceptionUtilities.CheckArgumentNotNull(propertyElement, "propertyElement"); ExceptionUtilities.CheckCollectionNotEmpty(propertyElement.Elements(), "propertyElement.Elements()"); ExceptionUtilities.Assert(propertyElement.Elements().All(e => e.Name == DataServicesElement), "Collection property sub elements had inconsistent names"); string propertyName = propertyElement.Name.LocalName; string fullTypeName = null; string bagElementTypeName = null; var type = propertyElement.Attribute(MetadataType); if (type != null) { fullTypeName = type.Value; bagElementTypeName = ParseBagElementTypeName(type.Value); } // convert the elements first, then decide if its a primitive or complex collection // note that a collection containing all null values will appear as a primitive collection, regardless of what the type really is List<PropertyInstance> elements = null; if (bagElementTypeName != null) { elements = propertyElement.Elements().Select(e => this.DeserializeProperty(e, bagElementTypeName)).ToList(); } else { elements = propertyElement.Elements().Select(e => this.DeserializeProperty(e)).ToList(); } if (elements.OfType<ComplexProperty>().Any()) { var complex = new ComplexMultiValueProperty(propertyName, new ComplexMultiValue(fullTypeName, false)); foreach (var complexElement in elements) { if (complexElement.ElementType == ODataPayloadElementType.NullPropertyInstance) { var nullProperty = complexElement as NullPropertyInstance; complex.Value.Add(new ComplexInstance(nullProperty.FullTypeName, true)); } else { ExceptionUtilities.Assert(complexElement.ElementType == ODataPayloadElementType.ComplexProperty, "Complex value collection contained non-complex, non-null value"); complex.Value.Add((complexElement as ComplexProperty).Value); } } return complex; } else { var primitive = new PrimitiveMultiValueProperty(propertyName, new PrimitiveMultiValue(fullTypeName, false)); foreach (var primitiveElement in elements) { if (primitiveElement.ElementType == ODataPayloadElementType.NullPropertyInstance) { var nullProperty = primitiveElement as NullPropertyInstance; primitive.Value.Add(new PrimitiveValue(nullProperty.FullTypeName, null)); } else { ExceptionUtilities.Assert(primitiveElement.ElementType == ODataPayloadElementType.PrimitiveProperty, "Primitive value collection contained non-primitive, non-null value"); primitive.Value.Add((primitiveElement as PrimitiveProperty).Value); } } return primitive; } }
/// <summary> /// Deserializes the element as either a complex, a primitive, or a null property, based on the content /// </summary> /// <param name="property">The xml to deserialize</param> /// <param name="typeNameFallback">TypeName to use instead of the one from the XElement[type] attribute</param> /// <returns>A property representing the given xml</returns> private PropertyInstance DeserializeProperty(XElement property, string typeNameFallback) { string propertyName = property.Name.LocalName; // get the type name string typeNameFromPayload = null; XAttribute typeAttribute = property.Attribute(MetadataType); if (typeAttribute != null) { typeNameFromPayload = typeAttribute.Value; } // set type to be fallback when typeattribute does not exist var typeNameForClrTypeLookup = typeNameFromPayload; if (typeNameForClrTypeLookup == null && !string.IsNullOrEmpty(typeNameFallback)) { typeNameForClrTypeLookup = typeNameFallback; } // try to infer the clr type Type clrType = null; if (!string.IsNullOrEmpty(typeNameForClrTypeLookup)) { ExceptionUtilities.CheckObjectNotNull(this.PrimitiveDataTypeConverter, "Cannot infer clr type from edm type without converter"); clrType = this.PrimitiveDataTypeConverter.ToClrType(typeNameForClrTypeLookup); } PropertyInstance result; if (property.HasElements) { // must be complex, a multivalue, or spatial ExceptionUtilities.CheckObjectNotNull(this.SpatialFormatter, "Cannot safely deserialize element with children without spatial formatter."); // try to infer which spatial type hierarchy it is from the type name in the payload SpatialTypeKind? kind = null; if (clrType != null) { SpatialUtilities.TryInferSpatialTypeKind(clrType, out kind); } object spatialInstance; if (this.SpatialFormatter.TryParse(property.Elements().First(), kind, out spatialInstance)) { ExceptionUtilities.Assert(property.Elements().Count() == 1, "Spatial property had more than 1 sub-element"); result = new PrimitiveProperty(propertyName, typeNameFromPayload, spatialInstance); } else if (property.Elements().All(e => e.Name == DataServicesElement)) { result = this.DeserializeCollectionProperty(property); } else { result = new ComplexProperty(propertyName, this.DeserializeComplexInstance(property)); } } else { // check for the null attribute bool isNull = false; XAttribute isNullAttribute = property.Attribute(MetadataNull); if (isNullAttribute != null) { isNull = bool.Parse(isNullAttribute.Value); } // If its null and we can't tell whether it is primitive or complex, then return a null marker if (isNull && clrType == null) { result = new NullPropertyInstance(propertyName, typeNameFromPayload); } else if (typeNameFromPayload != null && typeNameFromPayload.StartsWith(ODataConstants.BeginMultiValueTypeIdentifier, StringComparison.Ordinal)) { ExceptionUtilities.CheckObjectNotNull(this.PrimitiveDataTypeConverter, "Cannot infer clr type from edm type without converter"); string elementTypeName = ParseBagElementTypeName(typeNameFromPayload); if (this.PrimitiveDataTypeConverter.ToClrType(elementTypeName) != null) { result = new PrimitiveMultiValueProperty(propertyName, new PrimitiveMultiValue(typeNameFromPayload, isNull)); } else { result = new ComplexMultiValueProperty(propertyName, new ComplexMultiValue(typeNameFromPayload, isNull)); } } else { object value; if (isNull) { value = null; } else if (clrType != null) { ExceptionUtilities.CheckObjectNotNull(this.PrimitiveConverter, "PrimitiveConverter has not been set."); value = this.PrimitiveConverter.DeserializePrimitive(property.Value, clrType); } else { value = property.Value; } result = new PrimitiveProperty(propertyName, typeNameFromPayload, value); } } AddXmlBaseAnnotation(result, property); return result; }
/// <summary> /// Visits a payload element whose root is a PrimitiveCollectionProperty. /// </summary> /// <param name="payloadElement">The root node of payload element being visited.</param> public override void Visit(PrimitiveMultiValueProperty payloadElement) { RemoveChangeAnnotations(payloadElement); base.Visit(payloadElement); }
public PropertyInstance MultiValueProperty(MemberProperty memberProperty, object anonymous) { ExceptionUtilities.CheckArgumentNotNull(memberProperty, "memberProperty"); var collectionType = memberProperty.PropertyType as CollectionDataType; ExceptionUtilities.CheckObjectNotNull(collectionType, "Property '{0}' was not a collection"); var enumerable = anonymous as IEnumerable; ExceptionUtilities.CheckObjectNotNull(enumerable, "Value for property '{0}' was not enumerable"); var primitiveType = collectionType.ElementDataType as PrimitiveDataType; if (primitiveType != null) { var primitiveCollection = new PrimitiveMultiValueProperty(memberProperty.Name, new PrimitiveMultiValue(primitiveType.BuildMultiValueTypeName(), false)); foreach (var thing in enumerable) { primitiveCollection.Value.Add(this.PrimitiveProperty(new MemberProperty("temp", primitiveType), thing).Value); } return primitiveCollection; } else { var complexType = collectionType.ElementDataType as ComplexDataType; ExceptionUtilities.CheckObjectNotNull(complexType, "Collection property '{0}' did not have a primitive or complex collection type", memberProperty.Name); var complexCollection = new ComplexMultiValueProperty(memberProperty.Name, new ComplexMultiValue(complexType.BuildMultiValueTypeName(), false)); foreach (var thing in enumerable) { complexCollection.Value.Add(this.ComplexInstance(complexType.Definition, thing)); } return complexCollection; } }
/// <summary> /// Visits the payload element /// </summary> /// <param name="payloadElement">The payload element to visit</param> public override void Visit(PrimitiveMultiValueProperty payloadElement) { ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement"); this.SerializeMultiValueProperty <PrimitiveMultiValue, PrimitiveValue>(payloadElement); }