You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by ar...@apache.org on 2018/04/02 11:31:55 UTC

[14/24] olingo-odata2 git commit: [OLINGO-1253]Client Module for Olingo v2

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/9e949e40/odata2-lib/odata-client-core/src/test/java/org/apache/olingo/odata2/client/core/ep/deserializer/JsonPropertyDeserializerTest.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-client-core/src/test/java/org/apache/olingo/odata2/client/core/ep/deserializer/JsonPropertyDeserializerTest.java b/odata2-lib/odata-client-core/src/test/java/org/apache/olingo/odata2/client/core/ep/deserializer/JsonPropertyDeserializerTest.java
new file mode 100644
index 0000000..3a89af0
--- /dev/null
+++ b/odata2-lib/odata-client-core/src/test/java/org/apache/olingo/odata2/client/core/ep/deserializer/JsonPropertyDeserializerTest.java
@@ -0,0 +1,834 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.client.core.ep.deserializer;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.UnsupportedEncodingException;
+import java.math.BigDecimal;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import org.apache.olingo.odata2.api.edm.EdmFacets;
+import org.apache.olingo.odata2.api.edm.EdmProperty;
+import org.apache.olingo.odata2.api.edm.EdmSimpleTypeKind;
+import org.apache.olingo.odata2.api.ep.EntityProviderException;
+import org.apache.olingo.odata2.client.api.ep.DeserializerProperties;
+import org.apache.olingo.odata2.core.ep.aggregator.EntityComplexPropertyInfo;
+import org.apache.olingo.odata2.core.ep.aggregator.EntityInfoAggregator;
+import org.apache.olingo.odata2.core.ep.aggregator.EntityPropertyInfo;
+import org.apache.olingo.odata2.testutil.fit.BaseTest;
+import org.apache.olingo.odata2.testutil.mock.MockFacade;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import com.google.gson.stream.JsonReader;
+
+/**
+ *  
+ */
+public class JsonPropertyDeserializerTest extends BaseTest {
+  
+  @Rule
+  public ExpectedException expectedEx = ExpectedException.none();
+  
+  @Test
+  public void booleanSimpleProperty() throws Exception {
+    EdmProperty property = mock(EdmProperty.class);
+    when(property.getName()).thenReturn("Boolean");
+    when(property.isSimple()).thenReturn(true);
+    when(property.getType()).thenReturn(EdmSimpleTypeKind.Boolean.getEdmSimpleTypeInstance());
+
+    JsonReader reader = prepareReader("{\"Boolean\":true}");
+    final Map<String, Object> resultMap = execute(property, reader);
+    assertEquals(Boolean.TRUE, resultMap.get("Boolean"));
+  }
+
+  @Test
+  public void allNumberSimplePropertyKinds() throws Exception {
+    String simplePropertyJson = "{\"d\":{\"Age\":67}}";
+    EdmProperty edmProperty = mock(EdmProperty.class);
+    when(edmProperty.getName()).thenReturn("Age");
+    when(edmProperty.isSimple()).thenReturn(true);
+
+    // Byte
+    JsonReader reader = prepareReader(simplePropertyJson);
+    when(edmProperty.getType()).thenReturn(EdmSimpleTypeKind.Byte.getEdmSimpleTypeInstance());
+    Map<String, Object> resultMap = execute(edmProperty, reader);
+    assertEquals(Short.valueOf("67"), resultMap.get("Age"));
+
+    // SByte
+    reader = prepareReader(simplePropertyJson);
+    when(edmProperty.getType()).thenReturn(EdmSimpleTypeKind.SByte.getEdmSimpleTypeInstance());
+    resultMap = execute(edmProperty, reader);
+    assertEquals(Byte.valueOf("67"), resultMap.get("Age"));
+    // Int16
+    reader = prepareReader(simplePropertyJson);
+    when(edmProperty.getType()).thenReturn(EdmSimpleTypeKind.Int16.getEdmSimpleTypeInstance());
+    resultMap = execute(edmProperty, reader);
+    assertEquals(Short.valueOf("67"), resultMap.get("Age"));
+    // Int32
+    reader = prepareReader(simplePropertyJson);
+    when(edmProperty.getType()).thenReturn(EdmSimpleTypeKind.Int32.getEdmSimpleTypeInstance());
+    resultMap = execute(edmProperty, reader);
+    assertEquals(Integer.valueOf("67"), resultMap.get("Age"));
+  }
+
+  @Test
+  public void allStringSimplePropertyKinds() throws Exception {
+    EdmProperty edmProperty = mock(EdmProperty.class);
+    when(edmProperty.getName()).thenReturn("Name");
+    when(edmProperty.isSimple()).thenReturn(true);
+    String simplePropertyJson;
+
+    // DateTime
+    simplePropertyJson = "{\"d\":{\"Name\":\"\\/Date(915148800000)\\/\"}}";
+    JsonReader reader = prepareReader(simplePropertyJson);
+    when(edmProperty.getType()).thenReturn(EdmSimpleTypeKind.DateTime.getEdmSimpleTypeInstance());
+    Map<String, Object> resultMap = execute(edmProperty, reader);
+    Calendar entryDate = (Calendar) resultMap.get("Name");
+    assertEquals(Long.valueOf(915148800000l), Long.valueOf(entryDate.getTimeInMillis()));
+    // DateTimeOffset
+    simplePropertyJson = "{\"d\":{\"Name\":\"\\/Date(915148800000)\\/\"}}";
+    reader = prepareReader(simplePropertyJson);
+    when(edmProperty.getType()).thenReturn(EdmSimpleTypeKind.DateTime.getEdmSimpleTypeInstance());
+    resultMap = execute(edmProperty, reader);
+    entryDate = (Calendar) resultMap.get("Name");
+    assertEquals(Long.valueOf(915148800000l), Long.valueOf(entryDate.getTimeInMillis()));
+    // Decimal
+    simplePropertyJson = "{\"d\":{\"Name\":\"123456789\"}}";
+    reader = prepareReader(simplePropertyJson);
+    when(edmProperty.getType()).thenReturn(EdmSimpleTypeKind.Decimal.getEdmSimpleTypeInstance());
+    resultMap = execute(edmProperty, reader);
+    assertEquals(BigDecimal.valueOf(Long.valueOf("123456789")), resultMap.get("Name"));
+    // Double
+    simplePropertyJson = "{\"d\":{\"Name\":\"123456789\"}}";
+    reader = prepareReader(simplePropertyJson);
+    when(edmProperty.getType()).thenReturn(EdmSimpleTypeKind.Double.getEdmSimpleTypeInstance());
+    resultMap = execute(edmProperty, reader);
+    assertEquals(Double.valueOf("123456789"), resultMap.get("Name"));
+    // Double without "
+    simplePropertyJson = "{\"d\":{\"Name\":123456789}}";
+    reader = prepareReader(simplePropertyJson);
+    when(edmProperty.getType()).thenReturn(EdmSimpleTypeKind.Double.getEdmSimpleTypeInstance());
+    resultMap = execute(edmProperty, reader);
+    assertEquals(Double.valueOf("123456789"), resultMap.get("Name"));
+    // Int64
+    simplePropertyJson = "{\"d\":{\"Name\":\"123456789\"}}";
+    reader = prepareReader(simplePropertyJson);
+    when(edmProperty.getType()).thenReturn(EdmSimpleTypeKind.Int64.getEdmSimpleTypeInstance());
+    resultMap = execute(edmProperty, reader);
+    assertEquals(Long.valueOf("123456789"), resultMap.get("Name"));
+    // Single
+    simplePropertyJson = "{\"d\":{\"Name\":\"123456\"}}";
+    reader = prepareReader(simplePropertyJson);
+    when(edmProperty.getType()).thenReturn(EdmSimpleTypeKind.Single.getEdmSimpleTypeInstance());
+    resultMap = execute(edmProperty, reader);
+    assertEquals(Float.valueOf("123456"), resultMap.get("Name"));
+    // Single without "
+    simplePropertyJson = "{\"d\":{\"Name\":123456}}";
+    reader = prepareReader(simplePropertyJson);
+    when(edmProperty.getType()).thenReturn(EdmSimpleTypeKind.Single.getEdmSimpleTypeInstance());
+    resultMap = execute(edmProperty, reader);
+    assertEquals(Float.valueOf("123456"), resultMap.get("Name"));
+    // String
+    simplePropertyJson = "{\"d\":{\"Name\":\"123456789\"}}";
+    reader = prepareReader(simplePropertyJson);
+    when(edmProperty.getType()).thenReturn(EdmSimpleTypeKind.String.getEdmSimpleTypeInstance());
+    resultMap = execute(edmProperty, reader);
+    assertEquals("123456789", resultMap.get("Name"));
+    // Guid
+    simplePropertyJson = "{\"d\":{\"Name\":\"AABBCCDD-AABB-CCDD-EEFF-AABBCCDDEEFF\"}}";
+    reader = prepareReader(simplePropertyJson);
+    when(edmProperty.getType()).thenReturn(EdmSimpleTypeKind.Guid.getEdmSimpleTypeInstance());
+    resultMap = execute(edmProperty, reader);
+    assertEquals(UUID.fromString("aabbccdd-aabb-ccdd-eeff-aabbccddeeff"), resultMap.get("Name"));
+    // Binary
+    simplePropertyJson = "{\"d\":{\"Name\":\"qrvM\"}}";
+    reader = prepareReader(simplePropertyJson);
+    when(edmProperty.getType()).thenReturn(EdmSimpleTypeKind.Binary.getEdmSimpleTypeInstance());
+    resultMap = execute(edmProperty, reader);
+    assertTrue(Arrays.equals(new byte[] { (byte) 0xAA, (byte) 0xBB, (byte) 0xCC },
+        (byte[]) resultMap.get("Name")));
+    // Time
+    simplePropertyJson = "{\"d\":{\"Name\":\"PT23H32M3S\"}}";
+    reader = prepareReader(simplePropertyJson);
+    when(edmProperty.getType()).thenReturn(EdmSimpleTypeKind.Time.getEdmSimpleTypeInstance());
+    resultMap = execute(edmProperty, reader);
+    Calendar dateTime = Calendar.getInstance();
+    dateTime.clear();
+    dateTime.set(Calendar.HOUR_OF_DAY, 23);
+    dateTime.set(Calendar.MINUTE, 32);
+    dateTime.set(Calendar.SECOND, 3);
+    assertEquals(dateTime, resultMap.get("Name"));
+  }
+
+  @Test
+  public void simplePropertyOnOpenReader() throws Exception {
+    String simplePropertyJson = "{\"Name\":\"Team 1\"}";
+    JsonReader reader = prepareReader(simplePropertyJson);
+    EdmProperty edmProperty =
+        (EdmProperty) MockFacade.getMockEdm().getDefaultEntityContainer().getEntitySet("Teams").getEntityType()
+            .getProperty("Name");
+    EntityPropertyInfo entityPropertyInfo = EntityInfoAggregator.create(edmProperty);
+    reader.beginObject();
+    reader.nextName();
+
+    JsonPropertyDeserializer jpc = new JsonPropertyDeserializer();
+    Object value = jpc.readPropertyValue(reader, entityPropertyInfo, null, null);
+    assertEquals("Team 1", value);
+  }
+
+  @Test
+  public void veryLongStringStandalone() throws Exception {
+    char[] chars = new char[32768];
+    Arrays.fill(chars, 0, 32768, 'a');
+    String propertyValue = new String(chars);
+    String simplePropertyJson = "{\"d\":{\"Name\":\"" + propertyValue + "\"}}";
+    JsonReader reader = prepareReader(simplePropertyJson);
+    final EdmProperty edmProperty =
+        (EdmProperty) MockFacade.getMockEdm().getEntityType("RefScenario", "Room").getProperty("Name");
+
+    DeserializerProperties readProperties = mock(DeserializerProperties.class);
+    when(readProperties.getTypeMappings()).thenReturn(null);
+    Map<String, Object> resultMap =
+        new JsonPropertyDeserializer().readPropertyStandalone(reader, edmProperty, readProperties);
+
+    assertEquals(propertyValue, resultMap.get("Name"));
+  }
+
+  @Test(expected = EntityProviderException.class)
+  public void simplePropertyViolatingValidation() throws Exception {
+    EdmProperty property = (EdmProperty) MockFacade.getMockEdm().getEntityType("RefScenario", "Room")
+        .getProperty("Name");
+    EdmFacets facets = mock(EdmFacets.class);
+    when(facets.getMaxLength()).thenReturn(10);
+    when(property.getFacets()).thenReturn(facets);
+    new JsonPropertyDeserializer().readPropertyStandalone(prepareReader("{\"Name\":\"TooLongName\"}"), property, null);
+  }
+
+  @Test
+  public void simplePropertyIgnoringValidation() throws Exception {
+    EdmProperty property = (EdmProperty) MockFacade.getMockEdm().getEntityType("RefScenario", "Room")
+        .getProperty("Name");
+    EdmFacets facets = mock(EdmFacets.class);
+    when(facets.getMaxLength()).thenReturn(10);
+    when(property.getFacets()).thenReturn(facets);
+    final DeserializerProperties readProperties = mock(DeserializerProperties.class);
+    final Map<String, Object> resultMap = new JsonPropertyDeserializer()
+        .readPropertyStandalone(prepareReader("{\"Name\":\"TooLongName\"}"), property, readProperties);
+    assertTrue(resultMap.containsKey("Name"));
+    assertEquals("TooLongName", resultMap.get("Name"));
+  }
+
+  @Test
+  public void simplePropertyNull() throws Exception {
+    JsonReader reader = prepareReader("{\"Name\":null}");
+    final EdmProperty property =
+        (EdmProperty) MockFacade.getMockEdm().getEntityType("RefScenario", "Room").getProperty("Name");
+    final Map<String, Object> resultMap = new JsonPropertyDeserializer().readPropertyStandalone(reader, property, null);
+    assertTrue(resultMap.containsKey("Name"));
+    assertNull(resultMap.get("Name"));
+  }
+
+  @Test(expected = EntityProviderException.class)
+  public void simplePropertyNullValueNotAllowed() throws Exception {
+    JsonReader reader = prepareReader("{\"Age\":null}");
+    EdmProperty property =
+        (EdmProperty) MockFacade.getMockEdm().getEntityType("RefScenario", "Employee").getProperty("Age");
+    EdmFacets facets = mock(EdmFacets.class);
+    when(facets.isNullable()).thenReturn(false);
+    when(property.getFacets()).thenReturn(facets);
+
+    new JsonPropertyDeserializer().readPropertyStandalone(reader, property, null);
+  }
+
+  @Test(expected = EntityProviderException.class)
+  public void simplePropertyInvalidName() throws Exception {
+    EdmProperty property = mock(EdmProperty.class);
+    when(property.getName()).thenReturn("property-name");
+    when(property.isSimple()).thenReturn(true);
+    when(property.getType()).thenReturn(EdmSimpleTypeKind.Boolean.getEdmSimpleTypeInstance());
+
+    JsonReader reader = prepareReader("{\"Boolean\":true}");
+    execute(property, reader);
+    expectedEx.expect(RuntimeException.class);
+    expectedEx.expectMessage("'property-name' name pattern not valid.");
+  }
+  
+  @Test
+  public void simplePropertyWithNullMappingStandalone() throws Exception {
+    String simplePropertyJson = "{\"d\":{\"Age\":67}}";
+    JsonReader reader = prepareReader(simplePropertyJson);
+    final EdmProperty edmProperty =
+        (EdmProperty) MockFacade.getMockEdm().getEntityType("RefScenario", "Employee").getProperty("Age");
+
+    DeserializerProperties readProperties = mock(DeserializerProperties.class);
+    when(readProperties.getTypeMappings()).thenReturn(null);
+    Map<String, Object> resultMap =
+        new JsonPropertyDeserializer().readPropertyStandalone(reader, edmProperty, readProperties);
+
+    assertEquals(Integer.valueOf(67), resultMap.get("Age"));
+  }
+
+  @Test
+  public void simplePropertyWithNullMappingStandaloneWithoutD() throws Exception {
+    String simplePropertyJson = "{\"Age\":67}";
+    JsonReader reader = prepareReader(simplePropertyJson);
+    final EdmProperty edmProperty =
+        (EdmProperty) MockFacade.getMockEdm().getEntityType("RefScenario", "Employee").getProperty("Age");
+
+    DeserializerProperties readProperties = mock(DeserializerProperties.class);
+    when(readProperties.getTypeMappings()).thenReturn(null);
+    Map<String, Object> resultMap =
+        new JsonPropertyDeserializer().readPropertyStandalone(reader, edmProperty, readProperties);
+
+    assertEquals(Integer.valueOf(67), resultMap.get("Age"));
+  }
+
+  @Test
+  public void simplePropertyWithEmptyMappingStandalone() throws Exception {
+    String simplePropertyJson = "{\"d\":{\"Age\":67}}";
+    JsonReader reader = prepareReader(simplePropertyJson);
+    final EdmProperty edmProperty =
+        (EdmProperty) MockFacade.getMockEdm().getEntityType("RefScenario", "Employee").getProperty("Age");
+
+    DeserializerProperties readProperties = mock(DeserializerProperties.class);
+    when(readProperties.getTypeMappings()).thenReturn(new HashMap<String, Object>());
+    Map<String, Object> resultMap =
+        new JsonPropertyDeserializer().readPropertyStandalone(reader, edmProperty, readProperties);
+
+    assertEquals(Integer.valueOf(67), resultMap.get("Age"));
+  }
+
+  @Test
+  public void simplePropertyWithStringToLongMappingStandalone() throws Exception {
+    String simplePropertyJson = "{\"d\":{\"Age\":67}}";
+    JsonReader reader = prepareReader(simplePropertyJson);
+    final EdmProperty edmProperty =
+        (EdmProperty) MockFacade.getMockEdm().getEntityType("RefScenario", "Employee").getProperty("Age");
+
+    DeserializerProperties readProperties = mock(DeserializerProperties.class);
+    Map<String, Object> typeMappings = new HashMap<String, Object>();
+    typeMappings.put("Age", Integer.class);
+    when(readProperties.getTypeMappings()).thenReturn(typeMappings);
+    Map<String, Object> resultMap =
+        new JsonPropertyDeserializer().readPropertyStandalone(reader, edmProperty, readProperties);
+
+    assertEquals(Integer.valueOf(67), resultMap.get("Age"));
+  }
+
+  @Test
+  public void simplePropertyWithStringToNullMappingStandalone() throws Exception {
+    String simplePropertyJson = "{\"d\":{\"Age\":67}}";
+    JsonReader reader = prepareReader(simplePropertyJson);
+    final EdmProperty edmProperty =
+        (EdmProperty) MockFacade.getMockEdm().getEntityType("RefScenario", "Employee").getProperty("Age");
+
+    DeserializerProperties readProperties = mock(DeserializerProperties.class);
+    Map<String, Object> typeMappings = new HashMap<String, Object>();
+    typeMappings.put("Age", null);
+    when(readProperties.getTypeMappings()).thenReturn(typeMappings);
+    Map<String, Object> resultMap =
+        new JsonPropertyDeserializer().readPropertyStandalone(reader, edmProperty, readProperties);
+
+    assertEquals(Integer.valueOf(67), resultMap.get("Age"));
+  }
+
+  @Test(expected = EntityProviderException.class)
+  public void noContent() throws Exception {
+    final EdmProperty property =
+        (EdmProperty) MockFacade.getMockEdm().getEntityType("RefScenario", "Employee").getProperty("Age");
+    JsonReader reader = prepareReader("{}");
+    new JsonPropertyDeserializer().readPropertyStandalone(reader, property, null);
+  }
+
+  @Test(expected = EntityProviderException.class)
+  public void simplePropertyUnfinished() throws Exception {
+    final EdmProperty property =
+        (EdmProperty) MockFacade.getMockEdm().getEntityType("RefScenario", "Employee").getProperty("Age");
+    JsonReader reader = prepareReader("{\"Age\":67");
+    new JsonPropertyDeserializer().readPropertyStandalone(reader, property, null);
+  }
+
+  @Test(expected = EntityProviderException.class)
+  public void simplePropertInvalidName() throws Exception {
+    String simplePropertyJson = "{\"d\":{\"Invalid\":67}}";
+    JsonReader reader = prepareReader(simplePropertyJson);
+    final EdmProperty edmProperty =
+        (EdmProperty) MockFacade.getMockEdm().getEntityType("RefScenario", "Employee").getProperty("Age");
+
+    new JsonPropertyDeserializer().readPropertyStandalone(reader, edmProperty, null);
+  }
+
+  @Test
+  public void complexPropertyWithStringToStringMappingStandalone() throws Exception {
+    final String complexPropertyJson =
+        "{\"d\":{\"City\":{\"__metadata\":{\"type\":\"RefScenario.c_City\"}," +
+            "\"PostalCode\":\"69124\",\"CityName\":\"Heidelberg\"}}}";
+    JsonReader reader = prepareReader(complexPropertyJson);
+    final EdmProperty property =
+        (EdmProperty) MockFacade.getMockEdm().getComplexType("RefScenario", "c_Location").getProperty("City");
+
+    DeserializerProperties readProperties = mock(DeserializerProperties.class);
+    Map<String, Object> innerMappings = new HashMap<String, Object>();
+    innerMappings.put("PostalCode", String.class);
+    Map<String, Object> typeMappings = new HashMap<String, Object>();
+    typeMappings.put("City", innerMappings);
+    when(readProperties.getTypeMappings()).thenReturn(typeMappings);
+    Map<String, Object> result = new JsonPropertyDeserializer().
+        readPropertyStandalone(reader, property, readProperties);
+
+    assertEquals(1, result.size());
+    @SuppressWarnings("unchecked")
+    Map<String, Object> innerResult = (Map<String, Object>) result.get("City");
+    assertEquals("Heidelberg", innerResult.get("CityName"));
+    assertEquals("69124", innerResult.get("PostalCode"));
+  }
+
+  @Test
+  public void deepComplexPropertyWithStringToStringMappingStandalone() throws Exception {
+    final String complexPropertyJson =
+        "{\"d\":{\"Location\":{\"__metadata\":{\"type\":\"RefScenario.c_Location\"}," +
+            "\"City\":{\"__metadata\":{\"type\":\"RefScenario.c_City\"},\"PostalCode\":\"69124\"," +
+            "\"CityName\":\"Heidelberg\"},\"Country\":\"Germany\"}}}";
+    JsonReader reader = prepareReader(complexPropertyJson);
+    EdmProperty edmProperty =
+        (EdmProperty) MockFacade.getMockEdm().getDefaultEntityContainer().getEntitySet("Employees").getEntityType()
+            .getProperty("Location");
+
+    DeserializerProperties readProperties = mock(DeserializerProperties.class);
+    Map<String, Object> cityMappings = new HashMap<String, Object>();
+    cityMappings.put("PostalCode", String.class);
+    Map<String, Object> locationMappings = new HashMap<String, Object>();
+    locationMappings.put("City", cityMappings);
+    Map<String, Object> mappings = new HashMap<String, Object>();
+    mappings.put("Location", locationMappings);
+    when(readProperties.getTypeMappings()).thenReturn(mappings);
+
+    final Map<String, Object> result =
+        new JsonPropertyDeserializer().readPropertyStandalone(reader, edmProperty, readProperties);
+
+    assertEquals(1, result.size());
+    @SuppressWarnings("unchecked")
+    Map<String, Object> locationResult = (Map<String, Object>) result.get("Location");
+    assertEquals(2, locationResult.size());
+    assertEquals("Germany", locationResult.get("Country"));
+    @SuppressWarnings("unchecked")
+    Map<String, Object> innerResult = (Map<String, Object>) locationResult.get("City");
+    assertEquals(2, innerResult.size());
+    assertEquals("Heidelberg", innerResult.get("CityName"));
+    assertEquals("69124", innerResult.get("PostalCode"));
+  }
+
+  @Test
+  public void complexPropertyOnOpenReader() throws Exception {
+    final String complexPropertyJson =
+        "{\"__metadata\":{\"type\":\"RefScenario.c_City\"},\"PostalCode\":\"69124\",\"CityName\":\"Heidelberg\"}";
+    JsonReader reader = prepareReader(complexPropertyJson);
+    final EdmProperty property =
+        (EdmProperty) MockFacade.getMockEdm().getComplexType("RefScenario", "c_Location").getProperty("City");
+    EntityComplexPropertyInfo entityPropertyInfo = (EntityComplexPropertyInfo) EntityInfoAggregator.create(property);
+
+    JsonPropertyDeserializer jpc = new JsonPropertyDeserializer();
+    @SuppressWarnings("unchecked")
+    Map<String, Object> result = (Map<String, Object>) jpc.readPropertyValue(reader, entityPropertyInfo, null, null);
+
+    assertEquals(2, result.size());
+    assertEquals("Heidelberg", result.get("CityName"));
+    assertEquals("69124", result.get("PostalCode"));
+  }
+
+  @Test
+  public void complexPropertyOnOpenReaderWithNoMetadata() throws Exception {
+    final String complexPropertyJson = "{\"PostalCode\":\"69124\",\"CityName\":\"Heidelberg\"}";
+    JsonReader reader = prepareReader(complexPropertyJson);
+    final EdmProperty property =
+        (EdmProperty) MockFacade.getMockEdm().getComplexType("RefScenario", "c_Location").getProperty("City");
+    EntityComplexPropertyInfo entityPropertyInfo = (EntityComplexPropertyInfo) EntityInfoAggregator.create(property);
+
+    JsonPropertyDeserializer jpc = new JsonPropertyDeserializer();
+    @SuppressWarnings("unchecked")
+    Map<String, Object> result = (Map<String, Object>) jpc.readPropertyValue(reader, entityPropertyInfo, null, null);
+
+    assertEquals(2, result.size());
+    assertEquals("Heidelberg", result.get("CityName"));
+    assertEquals("69124", result.get("PostalCode"));
+  }
+
+  @Test
+  public void deepComplexPropertyOnOpenReader() throws Exception {
+    final String complexPropertyJson =
+        "{\"__metadata\":{\"type\":\"RefScenario.c_Location\"}," +
+            "\"City\":{\"__metadata\":{\"type\":\"RefScenario.c_City\"},\"PostalCode\":\"69124\"," +
+            "\"CityName\":\"Heidelberg\"},\"Country\":\"Germany\"}";
+    JsonReader reader = prepareReader(complexPropertyJson);
+    EdmProperty edmProperty =
+        (EdmProperty) MockFacade.getMockEdm().getDefaultEntityContainer().getEntitySet("Employees").getEntityType()
+            .getProperty("Location");
+    EntityComplexPropertyInfo entityPropertyInfo = (EntityComplexPropertyInfo) EntityInfoAggregator.create(edmProperty);
+
+    JsonPropertyDeserializer jpc = new JsonPropertyDeserializer();
+    @SuppressWarnings("unchecked")
+    Map<String, Object> result = (Map<String, Object>) jpc.readPropertyValue(reader, entityPropertyInfo, null, null);
+
+    assertEquals(2, result.size());
+    assertEquals("Germany", result.get("Country"));
+    @SuppressWarnings("unchecked")
+    Map<String, Object> innerResult = (Map<String, Object>) result.get("City");
+    assertEquals(2, innerResult.size());
+    assertEquals("Heidelberg", innerResult.get("CityName"));
+    assertEquals("69124", innerResult.get("PostalCode"));
+  }
+
+  @Test
+  public void simplePropertyStandalone() throws Exception {
+    String simplePropertyJson = "{\"d\":{\"Name\":\"Team 1\"}}";
+    EdmProperty edmProperty =
+        (EdmProperty) MockFacade.getMockEdm().getDefaultEntityContainer().getEntitySet("Teams").getEntityType()
+            .getProperty("Name");
+    JsonReader reader = prepareReader(simplePropertyJson);
+
+    Map<String, Object> result = new JsonPropertyDeserializer().readPropertyStandalone(reader, edmProperty, null);
+    assertEquals("Team 1", result.get("Name"));
+  }
+
+  @Test
+  public void complexPropertyStandalone() throws Exception {
+    final String complexPropertyJson =
+        "{\"d\":{\"City\":{\"__metadata\":{\"type\":\"RefScenario.c_City\"}," +
+            "\"PostalCode\":\"69124\",\"CityName\":\"Heidelberg\"}}}";
+    JsonReader reader = prepareReader(complexPropertyJson);
+    final EdmProperty property =
+        (EdmProperty) MockFacade.getMockEdm().getComplexType("RefScenario", "c_Location").getProperty("City");
+
+    final Map<String, Object> result = new JsonPropertyDeserializer().readPropertyStandalone(reader, property, null);
+
+    assertEquals(1, result.size());
+    @SuppressWarnings("unchecked")
+    Map<String, Object> innerResult = (Map<String, Object>) result.get("City");
+    assertEquals("Heidelberg", innerResult.get("CityName"));
+    assertEquals("69124", innerResult.get("PostalCode"));
+  }
+
+  @Test
+  public void deepComplexPropertyStandalone() throws Exception {
+    final String complexPropertyJson =
+        "{\"d\":{\"Location\":{\"__metadata\":{\"type\":\"RefScenario.c_Location\"}," +
+            "\"City\":{\"__metadata\":{\"type\":\"RefScenario.c_City\"},\"PostalCode\":\"69124\"," +
+            "\"CityName\":\"Heidelberg\"},\"Country\":\"Germany\"}}}";
+    JsonReader reader = prepareReader(complexPropertyJson);
+    EdmProperty edmProperty =
+        (EdmProperty) MockFacade.getMockEdm().getDefaultEntityContainer().getEntitySet("Employees").getEntityType()
+            .getProperty("Location");
+
+    JsonPropertyDeserializer jpc = new JsonPropertyDeserializer();
+    Map<String, Object> result = jpc.readPropertyStandalone(reader, edmProperty, null);
+
+    assertEquals(1, result.size());
+    @SuppressWarnings("unchecked")
+    Map<String, Object> locationResult = (Map<String, Object>) result.get("Location");
+    assertEquals(2, locationResult.size());
+    assertEquals("Germany", locationResult.get("Country"));
+    @SuppressWarnings("unchecked")
+    Map<String, Object> innerResult = (Map<String, Object>) locationResult.get("City");
+    assertEquals(2, innerResult.size());
+    assertEquals("Heidelberg", innerResult.get("CityName"));
+    assertEquals("69124", innerResult.get("PostalCode"));
+  }
+
+  @Test(expected = EntityProviderException.class)
+  public void complexPropertyWithInvalidChild() throws Exception {
+    String cityProperty = "{\"d\":{\"City\":{\"Invalid\":\"69124\",\"CityName\":\"Heidelberg\"}}}";
+    JsonReader reader = prepareReader(cityProperty);
+    final EdmProperty property =
+        (EdmProperty) MockFacade.getMockEdm().getComplexType("RefScenario", "c_Location").getProperty("City");
+
+    new JsonPropertyDeserializer().readPropertyStandalone(reader, property, null);
+  }
+
+  @Test(expected = EntityProviderException.class)
+  public void complexPropertyWithInvalidName() throws Exception {
+    String cityProperty = "{\"d\":{\"Invalid\":{\"PostalCode\":\"69124\",\"CityName\":\"Heidelberg\"}}}";
+    JsonReader reader = prepareReader(cityProperty);
+    final EdmProperty property =
+        (EdmProperty) MockFacade.getMockEdm().getComplexType("RefScenario", "c_Location").getProperty("City");
+
+    new JsonPropertyDeserializer().readPropertyStandalone(reader, property, null);
+  }
+
+  @Test
+  public void complexPropertyNull() throws Exception {
+    final String locationProperty = "{\"Location\":null}";
+    JsonReader reader = prepareReader(locationProperty);
+    final EdmProperty property =
+        (EdmProperty) MockFacade.getMockEdm().getDefaultEntityContainer().
+        getEntitySet("Employees").getEntityType()
+            .getProperty("Location");
+
+    final Map<String, Object> propertyData = new JsonPropertyDeserializer().
+        readPropertyStandalone(reader, property, null);
+    assertNotNull(propertyData);
+    assertEquals(1, propertyData.size());
+    assertTrue(propertyData.containsKey("Location"));
+    assertNull(propertyData.get("Location"));
+  }
+
+  @Test(expected = EntityProviderException.class)
+  public void complexPropertyNullValueNotAllowed() throws Exception {
+    final String locationProperty = "{\"Location\":null}";
+    JsonReader reader = prepareReader(locationProperty);
+    EdmProperty property =
+        (EdmProperty) MockFacade.getMockEdm().getDefaultEntityContainer().getEntitySet("Employees").getEntityType()
+            .getProperty("Location");
+    EdmFacets facets = mock(EdmFacets.class);
+    when(facets.isNullable()).thenReturn(false);
+    when(property.getFacets()).thenReturn(facets);
+
+    new JsonPropertyDeserializer().readPropertyStandalone(reader, property, null);
+  }
+
+  @Test
+  public void complexPropertyNullValueNotAllowedButNotValidated() throws Exception {
+    final EdmProperty property = (EdmProperty) MockFacade.getMockEdm().getDefaultEntityContainer()
+        .getEntitySet("Employees").getEntityType().getProperty("Location");
+    EdmFacets facets = mock(EdmFacets.class);
+    when(facets.isNullable()).thenReturn(false);
+    when(property.getFacets()).thenReturn(facets);
+    final DeserializerProperties readProperties = mock(DeserializerProperties.class);
+
+    final Map<String, Object> propertyData = new JsonPropertyDeserializer()
+        .readPropertyStandalone(prepareReader("{\"Location\":null}"), property, readProperties);
+    assertNotNull(propertyData);
+    assertEquals(1, propertyData.size());
+    assertTrue(propertyData.containsKey("Location"));
+    assertNull(propertyData.get("Location"));
+  }
+
+  @Test
+  public void complexPropertyEmpty() throws Exception {
+    final String cityProperty = "{\"d\":{\"City\":{}}}";
+    JsonReader reader = prepareReader(cityProperty);
+    final EdmProperty property =
+        (EdmProperty) MockFacade.getMockEdm().
+        getComplexType("RefScenario", "c_Location").getProperty("City");
+
+    final Map<String, Object> propertyData = new JsonPropertyDeserializer().
+        readPropertyStandalone(reader, property, null);
+    assertNotNull(propertyData);
+    assertEquals(1, propertyData.size());
+    assertNotNull(propertyData.get("City"));
+    @SuppressWarnings("unchecked")
+    final Map<String, Object> innerMap = (Map<String, Object>) propertyData.get("City");
+    assertTrue(innerMap.isEmpty());
+  }
+
+  @Test(expected = EntityProviderException.class)
+  public void complexPropertyMetadataInvalidTag() throws Exception {
+    String complexPropertyJson =
+        "{\"__metadata\":{\"invalid\":\"RefScenario.c_City\"},"
+        + "\"PostalCode\":\"69124\",\"CityName\":\"Heidelberg\"}";
+    JsonReader reader = prepareReader(complexPropertyJson);
+    final EdmProperty property =
+        (EdmProperty) MockFacade.getMockEdm().getComplexType
+        ("RefScenario", "c_Location").getProperty("City");
+    EntityComplexPropertyInfo entityPropertyInfo = (EntityComplexPropertyInfo) 
+        EntityInfoAggregator.create(property);
+
+    new JsonPropertyDeserializer().readPropertyValue(reader, entityPropertyInfo, null, null);
+  }
+
+  @Test(expected = EntityProviderException.class)
+  public void complexPropertyMetadataInvalidTypeContent() throws Exception {
+    String complexPropertyJson =
+        "{\"__metadata\":{\"type\":\"Invalid\"},\"PostalCode\":\"69124\",\"CityName\":\"Heidelberg\"}";
+    JsonReader reader = prepareReader(complexPropertyJson);
+    final EdmProperty property =
+        (EdmProperty) MockFacade.getMockEdm().getComplexType
+        ("RefScenario", "c_Location").getProperty("City");
+    EntityComplexPropertyInfo entityPropertyInfo = (EntityComplexPropertyInfo) 
+        EntityInfoAggregator.create(property);
+
+    new JsonPropertyDeserializer().readPropertyValue(reader, entityPropertyInfo, null, null);
+  }
+
+  private JsonReader prepareReader(final String json) throws UnsupportedEncodingException {
+    InputStream jsonStream = createContentAsStream(json);
+    JsonReader reader = new JsonReader(new InputStreamReader(jsonStream));
+    return reader;
+  }
+
+  private Map<String, Object> execute(final EdmProperty edmProperty, final JsonReader reader)
+      throws EntityProviderException {
+    JsonPropertyDeserializer jpc = new JsonPropertyDeserializer();
+    Map<String, Object> resultMap = jpc.readPropertyStandalone(reader, edmProperty, null);
+    return resultMap;
+  }
+
+  @Test(expected = EntityProviderException.class)
+  public void invalidDoubleClosingBrackets() throws Exception {
+    String simplePropertyJson = "{\"d\":{\"Name\":\"Team 1\"}}}";
+    EdmProperty edmProperty =
+        (EdmProperty) MockFacade.getMockEdm().getDefaultEntityContainer().getEntitySet("Teams").getEntityType()
+            .getProperty("Name");
+    JsonReader reader = prepareReader(simplePropertyJson);
+
+    new JsonPropertyDeserializer().readPropertyStandalone(reader, edmProperty, null);
+  }
+
+  @Test(expected = EntityProviderException.class)
+  public void invalidDoubleClosingBracketsWithoutD() throws Exception {
+    String simplePropertyJson = "{\"Name\":\"Team 1\"}}";
+    EdmProperty edmProperty =
+        (EdmProperty) MockFacade.getMockEdm().getDefaultEntityContainer().getEntitySet("Teams").getEntityType()
+            .getProperty("Name");
+    JsonReader reader = prepareReader(simplePropertyJson);
+
+    new JsonPropertyDeserializer().readPropertyStandalone(reader, edmProperty, null);
+  }
+
+  @Test
+  public void collectionEmpty() throws Exception {
+    final EntityPropertyInfo info = EntityInfoAggregator.create(
+        MockFacade.getMockEdm().getDefaultEntityContainer().getFunctionImport("AllUsedRoomIds"));
+    List<?> collection = new JsonPropertyDeserializer().readCollection(prepareReader("[]"), info, null);
+    assertNotNull(collection);
+    assertTrue(collection.isEmpty());
+
+    collection = new JsonPropertyDeserializer().readCollection(prepareReader("{\"d\":[]}"), info, null);
+    assertNotNull(collection);
+    assertTrue(collection.isEmpty());
+
+    collection = new JsonPropertyDeserializer().readCollection(prepareReader("{\"results\":[]}"), info, null);
+    assertNotNull(collection);
+    assertTrue(collection.isEmpty());
+
+    collection = new JsonPropertyDeserializer().readCollection(prepareReader("{\"d\":{\"results\":[]}}"), info, null);
+    assertNotNull(collection);
+    assertTrue(collection.isEmpty());
+  }
+
+  @Test
+  public void collectionSimple() throws Exception {
+    final EntityPropertyInfo info = EntityInfoAggregator.create(
+        MockFacade.getMockEdm().getDefaultEntityContainer().getFunctionImport("AllUsedRoomIds"));
+    List<?> collection = new JsonPropertyDeserializer().readCollection(prepareReader("[\"1\",\"42\"]"), info, null);
+    assertNotNull(collection);
+    assertEquals(Arrays.asList("1", "42"), collection);
+  }
+
+  @Test
+  public void collectionSimpleWithMetadata() throws Exception {
+    final EntityPropertyInfo info = EntityInfoAggregator.create(
+        MockFacade.getMockEdm().getDefaultEntityContainer().getFunctionImport("AllUsedRoomIds"));
+    List<?> collection = new JsonPropertyDeserializer().readCollection(prepareReader(
+        "{\"__metadata\":{\"type\":\"Collection(Edm.String)\"},\"results\":[\"1\",\"42\"]}"),
+        info, null);
+    assertNotNull(collection);
+    assertEquals(Arrays.asList("1", "42"), collection);
+  }
+
+  @Test
+  public void collectionSimpleWithMapping() throws Exception {
+    final EntityPropertyInfo info = EntityInfoAggregator.create(
+        MockFacade.getMockEdm().getDefaultEntityContainer().getFunctionImport("AllUsedRoomIds"));
+    DeserializerProperties readProperties = mock(DeserializerProperties.class);
+    when(readProperties.getTypeMappings()).thenReturn(
+        Collections.<String, Object> singletonMap("AllUsedRoomIds", String.class));
+    List<?> collection = new JsonPropertyDeserializer().readCollection(prepareReader("[\"1\",\"42\"]"), info,
+        readProperties);
+    assertNotNull(collection);
+    assertEquals(Arrays.asList("1", "42"), collection);
+  }
+
+  @Test
+  public void collectionComplex() throws Exception {
+    final EntityPropertyInfo info = EntityInfoAggregator.create(
+        MockFacade.getMockEdm().getDefaultEntityContainer().getFunctionImport("AllLocations"));
+    DeserializerProperties readProperties = mock(DeserializerProperties.class);
+    final Map<String, Object> mappings = Collections.<String, Object> singletonMap("Location",
+        Collections.<String, Object> singletonMap("City",
+            Collections.<String, Object> singletonMap("PostalCode", String.class)));
+    when(readProperties.getTypeMappings()).thenReturn(mappings);
+    List<?> collection = new JsonPropertyDeserializer().readCollection(prepareReader(
+        "{\"__metadata\":{\"type\":\"Collection(RefScenario.c_Location)\"},"
+            + "\"results\":["
+            + "{\"City\":{\"PostalCode\":\"69124\",\"CityName\":\"Heidelberg\"},\"Country\":\"Germany\"},"
+            + "{\"City\":{\"PostalCode\":\"69190\",\"CityName\":\"Walldorf\"},\"Country\":\"Germany\"}]}"),
+        info, readProperties);
+    assertNotNull(collection);
+    assertEquals(2, collection.size());
+    @SuppressWarnings("unchecked")
+    final Map<String, Object> secondLocation = (Map<String, Object>) collection.get(1);
+    assertEquals("Germany", secondLocation.get("Country"));
+  }
+
+  @Test(expected = EntityProviderException.class)
+  public void collectionUnfinished() throws Exception {
+    final EntityPropertyInfo info = EntityInfoAggregator.create(
+        MockFacade.getMockEdm().getDefaultEntityContainer().getFunctionImport("AllUsedRoomIds"));
+    new JsonPropertyDeserializer().readCollection(prepareReader("[\"1\""), info, null);
+  }
+
+  @Test(expected = EntityProviderException.class)
+  public void collectionWithoutClosing() throws Exception {
+    final EntityPropertyInfo info = EntityInfoAggregator.create(
+        MockFacade.getMockEdm().getDefaultEntityContainer().getFunctionImport("AllUsedRoomIds"));
+    new JsonPropertyDeserializer().readCollection(prepareReader("{\"results\":[]"), info, null);
+  }
+
+  @Test(expected = EntityProviderException.class)
+  public void collectionWithWrongTag() throws Exception {
+    final EntityPropertyInfo info = EntityInfoAggregator.create(
+        MockFacade.getMockEdm().getDefaultEntityContainer().getFunctionImport("AllUsedRoomIds"));
+    new JsonPropertyDeserializer().readCollection(prepareReader("{\"something\":[]}"), info, null);
+  }
+
+  @Test(expected = EntityProviderException.class)
+  public void collectionWithWrongInnerTag() throws Exception {
+    final EntityPropertyInfo info = EntityInfoAggregator.create(
+        MockFacade.getMockEdm().getDefaultEntityContainer().getFunctionImport("AllUsedRoomIds"));
+    new JsonPropertyDeserializer().readCollection(prepareReader("{\"d\":{\"something\":[]}}"), info, null);
+  }
+
+  @Test(expected = EntityProviderException.class)
+  public void collectionWithTrailing() throws Exception {
+    final EntityPropertyInfo info = EntityInfoAggregator.create(
+        MockFacade.getMockEdm().getDefaultEntityContainer().getFunctionImport("AllUsedRoomIds"));
+    new JsonPropertyDeserializer().readCollection(prepareReader("{\"results\":[],\"a\":0}"), info, null);
+  }
+
+  private InputStream createContentAsStream(final String json) throws UnsupportedEncodingException {
+    return new ByteArrayInputStream(json.getBytes("UTF-8"));
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/9e949e40/odata2-lib/odata-client-core/src/test/java/org/apache/olingo/odata2/client/core/ep/deserializer/XMLMetadataFunctionImportDeserializerTest.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-client-core/src/test/java/org/apache/olingo/odata2/client/core/ep/deserializer/XMLMetadataFunctionImportDeserializerTest.java b/odata2-lib/odata-client-core/src/test/java/org/apache/olingo/odata2/client/core/ep/deserializer/XMLMetadataFunctionImportDeserializerTest.java
new file mode 100644
index 0000000..c2870a4
--- /dev/null
+++ b/odata2-lib/odata-client-core/src/test/java/org/apache/olingo/odata2/client/core/ep/deserializer/XMLMetadataFunctionImportDeserializerTest.java
@@ -0,0 +1,583 @@
+package org.apache.olingo.odata2.client.core.ep.deserializer;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.List;
+
+import javax.xml.stream.XMLStreamException;
+
+import org.apache.olingo.odata2.api.edm.Edm;
+import org.apache.olingo.odata2.api.edm.EdmAnnotationAttribute;
+import org.apache.olingo.odata2.api.edm.EdmAnnotationElement;
+import org.apache.olingo.odata2.api.edm.EdmAnnotations;
+import org.apache.olingo.odata2.api.edm.EdmEntityContainer;
+import org.apache.olingo.odata2.api.edm.EdmException;
+import org.apache.olingo.odata2.api.edm.EdmFunctionImport;
+import org.apache.olingo.odata2.api.edm.EdmMultiplicity;
+import org.apache.olingo.odata2.api.edm.EdmParameter;
+import org.apache.olingo.odata2.api.ep.EntityProviderException;
+import org.apache.olingo.odata2.client.api.edm.EdmDataServices;
+import org.apache.olingo.odata2.client.api.edm.EdmSchema;
+import org.junit.Test;
+
+public class XMLMetadataFunctionImportDeserializerTest {
+  private static final String NAMESPACE = "RefScenario";
+  private static final String NAMESPACE2 = "RefScenario2";
+  
+  private final String[] propertyNames = { "EmployeeId", "EmployeeName", "Location" };
+  
+  @Test
+  public void testFunctionImport() throws XMLStreamException, 
+  EntityProviderException, EdmException, UnsupportedEncodingException {
+    final String xmWithEntityContainer =
+        "<edmx:Edmx Version=\"1.0\" xmlns:edmx=\""
+            + Edm.NAMESPACE_EDMX_2007_06
+            + "\">"
+            + "<edmx:DataServices m:DataServiceVersion=\"2.0\" xmlns:m=\""
+            + Edm.NAMESPACE_M_2007_08
+            + "\">"
+            + "<Schema Namespace=\""
+            + NAMESPACE
+            + "\" xmlns=\""
+            + Edm.NAMESPACE_EDM_2008_09
+            + "\">"
+            + "<EntityType Name= \"Employee\" m:HasStream=\"true\">"
+            + "<Key><PropertyRef Name=\"EmployeeId\"/></Key>"
+            + "<Property Name=\""
+            + propertyNames[0]
+            + "\" Type=\"Edm.String\" Nullable=\"false\"/>"
+            + "<Property Name=\""
+            + propertyNames[1]
+            + "\" Type=\"Edm.String\" m:FC_TargetPath=\"SyndicationTitle\"/>"
+            + "</EntityType>"
+            + "<EntityContainer Name=\"Container1\" m:IsDefaultEntityContainer=\"true\">"
+            + "<EntitySet Name=\"Employees\" EntityType=\"RefScenario.Employee\"/>"
+            + "<FunctionImport Name=\"EmployeeSearch\" ReturnType=\"Collection(RefScenario.Employee)\" " +
+            "EntitySet=\"Employees\" m:HttpMethod=\"GET\">"
+            + "<Parameter Name=\"q1\" Type=\"Edm.String\" Nullable=\"true\" />"
+            + "<Parameter Name=\"q2\" Type=\"Edm.Int32\" Nullable=\"false\" />"
+            + "</FunctionImport>"
+            + "<FunctionImport Name=\"RoomSearch\" ReturnType=\"Collection(RefScenario.Employee)\" " +
+            "EntitySet=\"Employees\" m:HttpMethod=\"GET\">"
+            + "<Parameter Name=\"q1\" Type=\"Edm.String\" Nullable=\"true\" Mode=\"In\"/>"
+            + "<Parameter Name=\"q2\" Type=\"Edm.Int32\" Nullable=\"false\" />"
+            + "</FunctionImport>"
+            + "<FunctionImport Name=\"NoParamters\" ReturnType=\"Collection(RefScenario.Employee)\" " +
+            "EntitySet=\"Employees\" m:HttpMethod=\"GET\">"
+            + "</FunctionImport>"
+            + "<FunctionImport Name=\"NoReturn\" " +
+            "EntitySet=\"Rooms\" m:HttpMethod=\"GET\"/>"
+            + "<FunctionImport Name=\"SingleRoomReturnType\" ReturnType=\"RefScenario.Employee\" " +
+            "EntitySet=\"Employees\" m:HttpMethod=\"GET\">"
+            + "</FunctionImport>"
+            + "</EntityContainer>" + "</Schema>" + "</edmx:DataServices>" + "</edmx:Edmx>";
+    XmlMetadataDeserializer parser = new XmlMetadataDeserializer();
+    InputStream reader = createStreamReader(xmWithEntityContainer);
+    EdmDataServices result = parser.readMetadata(reader, true);
+    for (EdmSchema schema : result.getEdm().getSchemas()) {
+      for (EdmEntityContainer container : schema.getEntityContainers()) {
+        assertEquals("Container1", container.getName());
+        assertEquals(Boolean.TRUE, container.isDefaultEntityContainer());
+
+        EdmFunctionImport functionImport1 = container.getFunctionImport("EmployeeSearch");
+
+        assertEquals("EmployeeSearch", functionImport1.getName());
+        checkParameters1(functionImport1);
+
+        EdmFunctionImport functionImport2 = container.getFunctionImport("RoomSearch");
+        assertEquals("RoomSearch", functionImport2.getName());
+        assertEquals("Employees", functionImport2.getEntitySet().getName());
+        assertEquals(NAMESPACE, functionImport2.getReturnType().getType().getNamespace());
+        assertEquals("Employee", functionImport2.getReturnType().getName());
+        assertEquals(EdmMultiplicity.MANY, functionImport2.getReturnType().getMultiplicity());
+        assertEquals("GET", functionImport2.getHttpMethod());
+        List<String> parameterNames = (List<String>) functionImport2.getParameterNames();
+        
+        assertEquals(2, parameterNames.size());
+
+        EdmParameter edmParam = functionImport2.getParameter(parameterNames.get(0));
+        assertEquals("q1", parameterNames.get(0));
+        assertEquals("String", edmParam.getType().getName());
+        assertEquals(Boolean.TRUE, edmParam.getFacets().isNullable());
+        
+        edmParam = functionImport2.getParameter(parameterNames.get(1));
+        assertEquals("q2", parameterNames.get(1));
+        assertEquals("Int32", edmParam.getType().getName());
+        assertEquals(Boolean.FALSE, edmParam.getFacets().isNullable());
+        
+        EdmFunctionImport functionImport3 = container.getFunctionImport("NoParamters");
+        assertEquals("NoParamters", functionImport3.getName());
+        parameterNames = (List<String>) functionImport3.getParameterNames();
+        assertNotNull(parameterNames);
+        assertEquals(0, parameterNames.size());
+
+        EdmFunctionImport functionImport4 = container.getFunctionImport("NoReturn");
+        assertEquals("NoReturn", functionImport4.getName());
+        parameterNames = (List<String>) functionImport4.getParameterNames();
+        assertNotNull(parameterNames);
+        assertEquals(0, parameterNames.size());
+        assertNull(functionImport4.getReturnType());
+
+        EdmFunctionImport functionImport5 = container.getFunctionImport("SingleRoomReturnType");
+        assertEquals("SingleRoomReturnType", functionImport5.getName());
+        parameterNames = (List<String>) functionImport4.getParameterNames();
+        assertNotNull(parameterNames);
+        assertEquals(0, parameterNames.size());
+        assertEquals("Employee",
+            functionImport5.getReturnType().getType().getName());
+        assertEquals(EdmMultiplicity.ONE, functionImport5.getReturnType().getMultiplicity());
+      }
+    }
+  }
+  
+  private InputStream createStreamReader(final String xml) throws 
+  XMLStreamException, UnsupportedEncodingException {
+    return new ByteArrayInputStream(xml.getBytes("UTF-8"));
+  }
+  
+  @Test
+  public void testFunctionImportIn2Containers() throws XMLStreamException, 
+  EntityProviderException, EdmException, UnsupportedEncodingException {
+    final String xmWithEntityContainer =
+        "<edmx:Edmx Version=\"1.0\" xmlns:edmx=\""
+            + Edm.NAMESPACE_EDMX_2007_06
+            + "\">"
+            + "<edmx:DataServices m:DataServiceVersion=\"2.0\" xmlns:m=\""
+            + Edm.NAMESPACE_M_2007_08
+            + "\">"
+            + "<Schema Namespace=\""
+            + NAMESPACE
+            + "\" xmlns=\""
+            + Edm.NAMESPACE_EDM_2008_09
+            + "\">"
+            + "<EntityType Name= \"Employee\" m:HasStream=\"true\">"
+            + "<Key><PropertyRef Name=\"EmployeeId\"/></Key>"
+            + "<Property Name=\""
+            + propertyNames[0]
+            + "\" Type=\"Edm.String\" Nullable=\"false\"/>"
+            + "<Property Name=\""
+            + propertyNames[1]
+            + "\" Type=\"Edm.String\" m:FC_TargetPath=\"SyndicationTitle\"/>"
+            + "</EntityType>"
+            + "<EntityContainer Name=\"Container1\" m:IsDefaultEntityContainer=\"true\">"
+            + "<EntitySet Name=\"Employees\" EntityType=\"RefScenario.Employee\"/>"
+            + "<FunctionImport Name=\"EmployeeSearch\" ReturnType=\"Collection(RefScenario.Employee)\" " +
+            "EntitySet=\"Employees\" m:HttpMethod=\"GET\">"
+            + "<Parameter Name=\"q1\" Type=\"Edm.String\" Nullable=\"true\" />"
+            + "<Parameter Name=\"q2\" Type=\"Edm.Int32\" Nullable=\"false\" />"
+            + "</FunctionImport>"
+            + "<FunctionImport Name=\"RoomSearch\" ReturnType=\"Collection(RefScenario.Employee)\" " +
+            "EntitySet=\"Employees\" m:HttpMethod=\"GET\">"
+            + "<Parameter Name=\"q1\" Type=\"Edm.String\" Nullable=\"true\" Mode=\"In\"/>"
+            + "<Parameter Name=\"q2\" Type=\"Edm.Int32\" Nullable=\"false\" />"
+            + "</FunctionImport>"
+            + "</EntityContainer>" 
+            + "<EntityContainer Name=\"Container2\" m:IsDefaultEntityContainer=\"false\">"
+            + "<EntitySet Name=\"Employees\" EntityType=\"RefScenario.Employee\"/>"
+            + "<FunctionImport Name=\"RoomSearch\" ReturnType=\"Collection(RefScenario.Employee)\" " +
+            "EntitySet=\"Employees\" m:HttpMethod=\"GET\">"
+            + "<Parameter Name=\"q1\" Type=\"Edm.String\" Nullable=\"true\" Mode=\"In\"/>"
+            + "<Parameter Name=\"q2\" Type=\"Edm.Int32\" Nullable=\"false\" />"
+            + "</FunctionImport>"
+            + "</EntityContainer>" + 
+            "</Schema>" + "</edmx:DataServices>" + "</edmx:Edmx>";
+    XmlMetadataDeserializer parser = new XmlMetadataDeserializer();
+    InputStream reader = createStreamReader(xmWithEntityContainer);
+    EdmDataServices result = parser.readMetadata(reader, true);
+    for (EdmSchema schema : result.getEdm().getSchemas()) {
+      int i = 0;
+      for (EdmEntityContainer container : schema.getEntityContainers()) {
+        i++;
+        assertEquals("Container" + i, container.getName());
+        EdmFunctionImport functionImport = null;
+        if (container.getName().equals("Container1")) {
+          assertEquals(Boolean.TRUE, container.isDefaultEntityContainer());
+          functionImport = container.getFunctionImport("EmployeeSearch");
+          assertEquals("EmployeeSearch", functionImport.getName());
+          checkParameters1(functionImport);
+          assertEquals(Boolean.TRUE, container.isDefaultEntityContainer());
+          functionImport = container.getFunctionImport("RoomSearch");
+          assertEquals("RoomSearch", functionImport.getName());
+          checkParameters1(functionImport);
+        } else {
+          assertEquals(Boolean.FALSE, container.isDefaultEntityContainer());
+          functionImport = container.getFunctionImport("RoomSearch");
+          assertEquals("RoomSearch", functionImport.getName());
+        }
+        
+      }
+    }
+  }
+
+  /**
+   * @param functionImport
+   * @throws EdmException
+   */
+  private void checkParameters1(EdmFunctionImport functionImport) throws EdmException {
+    assertEquals("Employees", functionImport.getEntitySet().getName());
+    assertEquals("Employee", functionImport.getReturnType().getName());
+    assertEquals(EdmMultiplicity.MANY, functionImport.getReturnType().getMultiplicity());
+    assertEquals(NAMESPACE, functionImport.getReturnType().getType().getNamespace());
+    assertEquals("GET", functionImport.getHttpMethod());
+    List<String> parameterNames = (List<String>) functionImport.getParameterNames();
+    assertEquals(2, parameterNames.size());
+
+    assertEquals("q1", parameterNames.get(0));
+    EdmParameter edmParam = functionImport.getParameter(parameterNames.get(0)); 
+    assertEquals("String", edmParam.getType().getName());
+    assertEquals(Boolean.TRUE, edmParam.getFacets().isNullable());
+
+    assertEquals("q2", parameterNames.get(1));
+    edmParam = functionImport.getParameter(parameterNames.get(1));
+    assertEquals("Int32", edmParam.getType().getName());
+    assertEquals(Boolean.FALSE, edmParam.getFacets().isNullable());
+  }
+  
+  @Test
+  public void testFunctionImportIn2Schemas() throws XMLStreamException,
+  EntityProviderException, EdmException, UnsupportedEncodingException {
+    final String xmWithEntityContainer =
+        "<edmx:Edmx Version=\"1.0\" xmlns:edmx=\""
+            + Edm.NAMESPACE_EDMX_2007_06
+            + "\">"
+            + "<edmx:DataServices m:DataServiceVersion=\"2.0\" xmlns:m=\""
+            + Edm.NAMESPACE_M_2007_08
+            + "\">"
+            + "<Schema Namespace=\""
+            + NAMESPACE + "1"
+            + "\" xmlns=\""
+            + Edm.NAMESPACE_EDM_2008_09
+            + "\">"
+            + "<EntityType Name= \"Employee\" m:HasStream=\"true\">"
+            + "<Key><PropertyRef Name=\"EmployeeId\"/></Key>"
+            + "<Property Name=\""
+            + propertyNames[0]
+            + "\" Type=\"Edm.String\" Nullable=\"false\"/>"
+            + "<Property Name=\""
+            + propertyNames[1]
+            + "\" Type=\"Edm.String\" m:FC_TargetPath=\"SyndicationTitle\"/>"
+            + "</EntityType>"
+            + "<EntityContainer Name=\"Container1\" m:IsDefaultEntityContainer=\"true\">"
+            + "<EntitySet Name=\"Employees\" EntityType=\"RefScenario1.Employee\"/>"
+            + "<FunctionImport Name=\"EmployeeSearch\" ReturnType=\"Collection(RefScenario1.Employee)\" " +
+            "EntitySet=\"Employees\" m:HttpMethod=\"GET\">"
+            + "<Parameter Name=\"q1\" Type=\"Edm.String\" Nullable=\"true\" />"
+            + "<Parameter Name=\"q2\" Type=\"Edm.Int32\" Nullable=\"false\" />"
+            + "</FunctionImport>"
+            + "<FunctionImport Name=\"RoomSearch\" ReturnType=\"Collection(RefScenario1.Employee)\" " +
+            "EntitySet=\"Employees\" m:HttpMethod=\"GET\">"
+            + "<Parameter Name=\"q1\" Type=\"Edm.String\" Nullable=\"true\" Mode=\"In\"/>"
+            + "<Parameter Name=\"q2\" Type=\"Edm.Int32\" Nullable=\"false\" />"
+            + "</FunctionImport>"
+            + "</EntityContainer>" 
+            + "<EntityContainer Name=\"Container2\" m:IsDefaultEntityContainer=\"false\">"
+            + "<EntitySet Name=\"Employees\" EntityType=\"RefScenario1.Employee\"/>"
+            + "<FunctionImport Name=\"RoomSearch\" ReturnType=\"Collection(RefScenario1.Employee)\" " +
+            "EntitySet=\"Employees\" m:HttpMethod=\"GET\">"
+            + "<Parameter Name=\"q1\" Type=\"Edm.String\" Nullable=\"true\" Mode=\"In\"/>"
+            + "<Parameter Name=\"q2\" Type=\"Edm.Int32\" Nullable=\"false\" />"
+            + "</FunctionImport>"
+            + "</EntityContainer>" + 
+            "</Schema>" 
+            + "<Schema Namespace=\""
+            + NAMESPACE2
+            + "\" xmlns=\""
+            + Edm.NAMESPACE_EDM_2008_09
+            + "\">"
+            + "<EntityType Name= \"Employee\" m:HasStream=\"true\">"
+            + "<Key><PropertyRef Name=\"EmployeeId\"/></Key>"
+            + "<Property Name=\""
+            + propertyNames[0]
+            + "\" Type=\"Edm.String\" Nullable=\"false\"/>"
+            + "<Property Name=\""
+            + propertyNames[1]
+            + "\" Type=\"Edm.String\" m:FC_TargetPath=\"SyndicationTitle\"/>"
+            + "</EntityType>"
+            + "<EntityContainer Name=\"Container1\" m:IsDefaultEntityContainer=\"true\">"
+            + "<EntitySet Name=\"Employees\" EntityType=\"RefScenario2.Employee\"/>"
+            + "<FunctionImport Name=\"EmployeeSearch\" ReturnType=\"Collection(RefScenario2.Employee)\" " +
+            "EntitySet=\"Employees\" m:HttpMethod=\"GET\">"
+            + "<Parameter Name=\"q1\" Type=\"Edm.String\" Nullable=\"true\" />"
+            + "<Parameter Name=\"q2\" Type=\"Edm.Int32\" Nullable=\"false\" />"
+            + "</FunctionImport>"
+            + "<FunctionImport Name=\"RoomSearch\" ReturnType=\"Collection(RefScenario2.Employee)\" " +
+            "EntitySet=\"Employees\" m:HttpMethod=\"GET\">"
+            + "<Parameter Name=\"q1\" Type=\"Edm.String\" Nullable=\"true\" Mode=\"In\"/>"
+            + "<Parameter Name=\"q2\" Type=\"Edm.Int32\" Nullable=\"false\" />"
+            + "</FunctionImport>"
+            + "</EntityContainer>" 
+            + "</Schema>"
+            + "</edmx:DataServices>" + "</edmx:Edmx>";
+    XmlMetadataDeserializer parser = new XmlMetadataDeserializer();
+    InputStream reader = createStreamReader(xmWithEntityContainer);
+    EdmDataServices result = parser.readMetadata(reader, true);
+    int i = 0;
+    for (EdmSchema schema : result.getEdm().getSchemas()) {
+      i++;
+      assertEquals("RefScenario" + i, schema.getNamespace());
+      int j = 0;
+      for (EdmEntityContainer container : schema.getEntityContainers()) {
+        j++;
+        assertEquals("Container" + j, container.getName());
+        EdmFunctionImport functionImport = null;
+        if (container.getName().equals("Container1") && schema.getNamespace().equalsIgnoreCase("RefScenario" + i)) {
+          assertEquals(Boolean.TRUE, container.isDefaultEntityContainer());
+          functionImport = container.getFunctionImport("EmployeeSearch");
+          assertEquals("EmployeeSearch", functionImport.getName());
+          checkParameters(i, functionImport);
+        } else if (container.getName().equals("Container2") && 
+            schema.getNamespace().equalsIgnoreCase("RefScenario" + i)) {
+          assertEquals(Boolean.FALSE, container.isDefaultEntityContainer());
+          functionImport = container.getFunctionImport("RoomSearch");
+          assertEquals("RoomSearch", functionImport.getName());
+          checkParameters(i, functionImport);
+        }
+      }
+    }
+  }
+
+  /**
+   * @param i
+   * @param functionImport
+   * @throws EdmException
+   */
+  private void checkParameters(int i, EdmFunctionImport functionImport) throws EdmException {
+    assertEquals("Employees", functionImport.getEntitySet().getName());
+    assertEquals("Employee", functionImport.getReturnType().getName());
+    assertEquals(EdmMultiplicity.MANY, functionImport.getReturnType().getMultiplicity());
+    assertEquals(NAMESPACE + i, functionImport.getReturnType().getType().getNamespace());
+    assertEquals("GET", functionImport.getHttpMethod());
+    List<String> parameterNames = (List<String>) functionImport.getParameterNames();
+    assertEquals(2, parameterNames.size());
+
+    assertEquals("q1", parameterNames.get(0));
+    EdmParameter edmParam = functionImport.getParameter(parameterNames.get(0)); 
+    assertEquals("String", edmParam.getType().getName());
+    assertEquals(Boolean.TRUE, edmParam.getFacets().isNullable());
+
+    assertEquals("q2", parameterNames.get(1));
+    edmParam = functionImport.getParameter(parameterNames.get(1));
+    assertEquals("Int32", edmParam.getType().getName());
+    assertEquals(Boolean.FALSE, edmParam.getFacets().isNullable());
+  }
+  
+  @Test(expected = EntityProviderException.class)
+  public void testMissingTypeAtFunctionImport() throws Exception {
+    final String xml =
+        "<edmx:Edmx Version=\"1.0\" xmlns:edmx=\""
+            + Edm.NAMESPACE_EDMX_2007_06
+            + "\">"
+            + "<edmx:DataServices m:DataServiceVersion=\"2.0\" xmlns:m=\""
+            + Edm.NAMESPACE_M_2007_08
+            + "\">"
+            + "<Schema Namespace=\""
+            + NAMESPACE
+            + "\" xmlns=\""
+            + Edm.NAMESPACE_EDM_2008_09
+            + "\">"
+            + "<EntityType Name= \"Employee\" m:HasStream=\"true\">"
+            + "<Key><PropertyRef Name=\"EmployeeId\"/></Key>"
+            + "<Property Name=\""
+            + propertyNames[0]
+            + "\" Type=\"Edm.String\" Nullable=\"false\"/>"
+            + "<Property Name=\""
+            + propertyNames[1]
+            + "\" Type=\"Edm.String\" m:FC_TargetPath=\"SyndicationTitle\"/>"
+            + "</EntityType>"
+            + "<EntityContainer Name=\"Container1\" m:IsDefaultEntityContainer=\"true\">"
+            + "<EntitySet Name=\"Employees\" EntityType=\"RefScenario.Employee\"/>"
+            + "<FunctionImport Name=\"EmployeeSearch\" ReturnType=\"Collection(RefScenario.Employee)\" " +
+            "EntitySet=\"Employees\" m:HttpMethod=\"GET\">"
+            + "<Parameter Name=\"q\" Nullable=\"true\" />" + "</FunctionImport>"
+            + "</EntityContainer></Schema></edmx:DataServices></edmx:Edmx>";
+    XmlMetadataDeserializer parser = new XmlMetadataDeserializer();
+    InputStream reader = createStreamReader(xml);
+    try {
+      parser.readMetadata(reader, true);
+    } catch (EntityProviderException e) {
+      assertEquals(EntityProviderException.MISSING_ATTRIBUTE.getKey(), e.getMessageReference().getKey());
+      assertEquals(2, e.getMessageReference().getContent().size());
+      assertEquals("Type", e.getMessageReference().getContent().get(0));
+      assertEquals("Parameter", e.getMessageReference().getContent().get(1));
+      throw e;
+    }
+  }
+  
+  @Test
+  public void testFunctionImportWithAnnotations() throws XMLStreamException, 
+  EntityProviderException, EdmException, UnsupportedEncodingException {
+    final String xmWithEntityContainer =
+        "<edmx:Edmx Version=\"1.0\" xmlns:edmx=\""
+            + Edm.NAMESPACE_EDMX_2007_06 
+            + "\" xmlns:sap=\"http://www.sap.com/Protocols/SAPData\">"
+            + "<edmx:DataServices m:DataServiceVersion=\"2.0\" xmlns:m=\""
+            + Edm.NAMESPACE_M_2007_08
+            + "\">"
+            + "<Schema Namespace=\""
+            + NAMESPACE
+            + "\" xmlns=\""
+            + Edm.NAMESPACE_EDM_2008_09
+            + "\">"
+            + "<EntityType Name= \"Employee\" m:HasStream=\"true\">"
+            + "<Key><PropertyRef Name=\"EmployeeId\"/></Key>"
+            + "<Property Name=\""
+            + propertyNames[0]
+            + "\" Type=\"Edm.String\" Nullable=\"false\"/>"
+            + "<Property Name=\""
+            + propertyNames[1]
+            + "\" Type=\"Edm.String\" m:FC_TargetPath=\"SyndicationTitle\"/>"
+            + "</EntityType>"
+            + "<EntityContainer Name=\"Container1\" m:IsDefaultEntityContainer=\"true\">"
+            + "<EntitySet Name=\"Employees\" EntityType=\"RefScenario.Employee\"/>"
+            + "<FunctionImport Name=\"EmployeeSearch\" ReturnType=\"Collection(RefScenario.Employee)\" " 
+            + "EntitySet=\"Employees\" m:HttpMethod=\"GET\" sap:label=\"Approve\" "
+            + "sap:action-for=\"RefScenario.LeaveRequest\" sap:applicable-path=\"ControlData/NeedsApproval\">"
+            + "<Parameter Name=\"q1\" Type=\"Edm.String\" Nullable=\"true\" />"
+            + "<Parameter Name=\"q2\" Type=\"Edm.Int32\" Nullable=\"false\" >"
+            + "<sap:value-constraint set=\"Employees\">"
+            + "<sap:parameter-ref name=\"EmployeeId\" />"
+            + "</sap:value-constraint>"
+            + "</Parameter>"
+            + "</FunctionImport>"
+            + "</EntityContainer>" + "</Schema>" + "</edmx:DataServices>" + "</edmx:Edmx>";
+    XmlMetadataDeserializer parser = new XmlMetadataDeserializer();
+    InputStream reader = createStreamReader(xmWithEntityContainer);
+    EdmDataServices result = parser.readMetadata(reader, true);
+    for (EdmSchema schema : result.getEdm().getSchemas()) {
+      for (EdmEntityContainer container : schema.getEntityContainers()) {
+        assertEquals("Container1", container.getName());
+        assertEquals(Boolean.TRUE, container.isDefaultEntityContainer());
+
+        EdmFunctionImport functionImport1 = container.getFunctionImport("EmployeeSearch");
+
+        assertEquals("EmployeeSearch", functionImport1.getName());
+        checkParametersWithAnnotations(functionImport1);
+      }
+    }
+  }
+  
+  /**
+   * @param functionImport
+   * @throws EdmException
+   */
+  private void checkParametersWithAnnotations(EdmFunctionImport functionImport) throws EdmException {
+    assertEquals("Employees", functionImport.getEntitySet().getName());
+    assertEquals("Employee", functionImport.getReturnType().getName());
+    assertEquals(EdmMultiplicity.MANY, functionImport.getReturnType().getMultiplicity());
+    assertEquals(NAMESPACE, functionImport.getReturnType().getType().getNamespace());
+    assertEquals("GET", functionImport.getHttpMethod());
+    List<EdmAnnotationAttribute> annotationAttrs = functionImport.getAnnotations().getAnnotationAttributes();
+    assertEquals(3, annotationAttrs.size());
+    assertEquals("label", annotationAttrs.get(0).getName());
+    assertEquals("Approve", annotationAttrs.get(0).getText());
+    assertEquals("sap", annotationAttrs.get(0).getPrefix());
+    assertEquals("http://www.sap.com/Protocols/SAPData", annotationAttrs.get(0).getNamespace());
+    assertEquals("action-for", annotationAttrs.get(1).getName());
+    assertEquals("RefScenario.LeaveRequest", annotationAttrs.get(1).getText());
+    assertEquals("sap", annotationAttrs.get(1).getPrefix());
+    assertEquals("http://www.sap.com/Protocols/SAPData", annotationAttrs.get(1).getNamespace());
+    assertEquals("applicable-path", annotationAttrs.get(2).getName());
+    assertEquals("ControlData/NeedsApproval", annotationAttrs.get(2).getText());
+    assertEquals("sap", annotationAttrs.get(2).getPrefix());
+    assertEquals("http://www.sap.com/Protocols/SAPData", annotationAttrs.get(2).getNamespace());
+      
+    List<String> parameterNames = (List<String>) functionImport.getParameterNames();
+    assertEquals(2, parameterNames.size());
+
+    assertEquals("q1", parameterNames.get(0));
+    EdmParameter edmParam = functionImport.getParameter(parameterNames.get(0)); 
+    assertEquals("String", edmParam.getType().getName());
+    assertEquals(Boolean.TRUE, edmParam.getFacets().isNullable());
+
+    assertEquals("q2", parameterNames.get(1));
+    edmParam = functionImport.getParameter(parameterNames.get(1));
+    EdmAnnotations edmParamAnnotations = edmParam.getAnnotations();
+    if (edmParamAnnotations != null) {
+      for (EdmAnnotationElement annotationEle : edmParamAnnotations.getAnnotationElements()) {
+        assertEquals("value-constraint", annotationEle.getName());
+        assertEquals("http://www.sap.com/Protocols/SAPData", annotationEle.getNamespace());
+        assertEquals("sap", annotationEle.getPrefix());
+        for (EdmAnnotationAttribute annotationAttr : annotationEle.getAttributes()) {
+          assertEquals("set", annotationAttr.getName());
+          assertEquals("Employees", annotationAttr.getText());
+        }
+        for (EdmAnnotationElement childAnnotationEle : annotationEle.getChildElements()) {
+          assertEquals("parameter-ref", childAnnotationEle.getName());
+          assertEquals("http://www.sap.com/Protocols/SAPData", childAnnotationEle.getNamespace());
+          assertEquals("sap", childAnnotationEle.getPrefix());
+          for (EdmAnnotationAttribute childAnnotationAttr : childAnnotationEle.getAttributes()) {
+            assertEquals("name", childAnnotationAttr.getName());
+            assertEquals("EmployeeId", childAnnotationAttr.getText());
+          }
+        }
+      }
+    }
+    assertEquals("Int32", edmParam.getType().getName());
+    assertEquals(Boolean.FALSE, edmParam.getFacets().isNullable());
+  }
+  
+  @Test
+  public void testSameFunctionImportIn2Containers() throws XMLStreamException, 
+  EntityProviderException, EdmException, UnsupportedEncodingException {
+    final String xmWithEntityContainer =
+        "<edmx:Edmx Version=\"1.0\" xmlns:edmx=\""
+            + Edm.NAMESPACE_EDMX_2007_06
+            + "\">"
+            + "<edmx:DataServices m:DataServiceVersion=\"2.0\" xmlns:m=\""
+            + Edm.NAMESPACE_M_2007_08
+            + "\">"
+            + "<Schema Namespace=\""
+            + NAMESPACE
+            + "\" xmlns=\""
+            + Edm.NAMESPACE_EDM_2008_09
+            + "\">"
+            + "<EntityType Name= \"Employee\" m:HasStream=\"true\">"
+            + "<Key><PropertyRef Name=\"EmployeeId\"/></Key>"
+            + "<Property Name=\""
+            + propertyNames[0]
+            + "\" Type=\"Edm.String\" Nullable=\"false\"/>"
+            + "<Property Name=\""
+            + propertyNames[1]
+            + "\" Type=\"Edm.String\" m:FC_TargetPath=\"SyndicationTitle\"/>"
+            + "</EntityType>"
+            + "<EntityContainer Name=\"Container1\" m:IsDefaultEntityContainer=\"true\">"
+            + "<EntitySet Name=\"Employees\" EntityType=\"RefScenario.Employee\"/>"
+            + "<FunctionImport Name=\"EmployeeSearch\" ReturnType=\"Collection(RefScenario.Employee)\" " +
+            "EntitySet=\"Employees\" m:HttpMethod=\"GET\">"
+            + "<Parameter Name=\"q1\" Type=\"Edm.String\" Nullable=\"true\" />"
+            + "<Parameter Name=\"q2\" Type=\"Edm.Int32\" Nullable=\"false\" />"
+            + "</FunctionImport>"
+            + "</EntityContainer>" + "<EntityContainer Name=\"Container2\" m:IsDefaultEntityContainer=\"false\">"
+            + "<EntitySet Name=\"Employees\" EntityType=\"RefScenario.Employee\"/>"
+            + "<FunctionImport Name=\"EmployeeSearch\" ReturnType=\"Collection(RefScenario.Employee)\" " +
+            "EntitySet=\"Employees\" m:HttpMethod=\"GET\">"
+            + "<Parameter Name=\"q1\" Type=\"Edm.String\" Nullable=\"true\" />"
+            + "<Parameter Name=\"q2\" Type=\"Edm.Int32\" Nullable=\"false\" />"
+            + "</FunctionImport>"
+            + "</EntityContainer>" 
+            + "</Schema>" + "</edmx:DataServices>" + "</edmx:Edmx>";
+    XmlMetadataDeserializer parser = new XmlMetadataDeserializer();
+    InputStream reader = createStreamReader(xmWithEntityContainer);
+    EdmDataServices result = parser.readMetadata(reader, true);
+    for (EdmSchema schema : result.getEdm().getSchemas()) {
+      for (EdmEntityContainer container : schema.getEntityContainers()) {
+        if (container.getName().equalsIgnoreCase("Container1")) {
+          assertEquals(Boolean.TRUE, container.isDefaultEntityContainer());
+          EdmFunctionImport functionImport1 = container.getFunctionImport("EmployeeSearch");
+          assertEquals("EmployeeSearch", functionImport1.getName());
+          checkParameters1(functionImport1);
+        } else if (container.getName().equalsIgnoreCase("Container2")) {
+          assertEquals(Boolean.FALSE, container.isDefaultEntityContainer());
+          EdmFunctionImport functionImport1 = container.getFunctionImport("EmployeeSearch");
+          assertEquals("EmployeeSearch", functionImport1.getName());
+          checkParameters1(functionImport1);
+        }
+      }
+    }
+  }
+}