[OLINGO-508] Fixed OneToMany self reference
diff --git a/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/edm/AnnotationEdmProvider.java b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/edm/AnnotationEdmProvider.java
index 8b6e7f6..81546a7 100644
--- a/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/edm/AnnotationEdmProvider.java
+++ b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/edm/AnnotationEdmProvider.java
@@ -374,9 +374,13 @@
         }
         EdmNavigationProperty enp = field.getAnnotation(EdmNavigationProperty.class);
         if (enp != null) {
-          final NavigationProperty navProperty = createNavigationProperty(namespace, enp, field);
+          Class<?> fromClass = field.getDeclaringClass();
+          Class<?> toClass = ClassHelper.getFieldType(field);
+          AnnotationHelper.AnnotatedNavInfo info = ANNOTATION_HELPER.getCommonNavigationInfo(fromClass, toClass);
+
+          final NavigationProperty navProperty = createNavigationProperty(namespace, field, info);
           navProperties.add(navProperty);
-          Association association = createAssociation(field, navProperty);
+          Association association = createAssociation(info);
           associations.add(association);
         }
         EdmMediaResourceContent emrc = field.getAnnotation(EdmMediaResourceContent.class);
@@ -498,17 +502,15 @@
       return cp;
     }
 
-    private NavigationProperty createNavigationProperty(final String namespace, final EdmNavigationProperty enp,
-        final Field field) {
+    private NavigationProperty createNavigationProperty(final String namespace, Field field,
+                                                        AnnotationHelper.AnnotatedNavInfo navInfo) {
       NavigationProperty navProp = new NavigationProperty();
       navProp.setName(ANNOTATION_HELPER.getPropertyName(field));
-      String fromRole = ANNOTATION_HELPER.extractFromRoleName(enp, field);
+      String fromRole = navInfo.getFromRoleName();
       navProp.setFromRole(fromRole);
+      navProp.setToRole(navInfo.getToRoleName());
 
-      String toRole = ANNOTATION_HELPER.extractToRoleName(enp, field);
-      navProp.setToRole(toRole);
-
-      String relationshipName = ANNOTATION_HELPER.extractRelationshipName(enp, field);
+      String relationshipName = navInfo.getRelationshipName();
       navProp.setRelationship(new FullQualifiedName(namespace, relationshipName));
 
       return navProp;
@@ -600,25 +602,22 @@
       return ANNOTATION_HELPER.extractEntityTypeFqn(baseEntityClass);
     }
 
-    private Association createAssociation(final Field field, final NavigationProperty navProperty) {
+    private Association createAssociation(final AnnotationHelper.AnnotatedNavInfo info) {
       Association association = new Association();
-      EdmNavigationProperty navigation = field.getAnnotation(EdmNavigationProperty.class);
 
       AssociationEnd fromEnd = new AssociationEnd();
-      fromEnd.setRole(navProperty.getFromRole());
-      String typeName = ANNOTATION_HELPER.extractEntityTypeName(field.getDeclaringClass());
-      fromEnd.setType(new FullQualifiedName(namespace, typeName));
-      fromEnd.setMultiplicity(EdmMultiplicity.ONE);
+      fromEnd.setRole(info.getFromRoleName());
+      fromEnd.setType(new FullQualifiedName(namespace, info.getFromTypeName()));
+      fromEnd.setMultiplicity(info.getFromMultiplicity());
       association.setEnd1(fromEnd);
 
       AssociationEnd toEnd = new AssociationEnd();
-      toEnd.setRole(navProperty.getToRole());
-      String toTypeName = ANNOTATION_HELPER.extractEntitTypeName(navigation, field);
-      toEnd.setType(new FullQualifiedName(namespace, toTypeName));
-      toEnd.setMultiplicity(ANNOTATION_HELPER.getMultiplicity(navigation, field));
+      toEnd.setRole(info.getToRoleName());
+      toEnd.setType(new FullQualifiedName(namespace, info.getToTypeName()));
+      toEnd.setMultiplicity(info.getToMultiplicity());
       association.setEnd2(toEnd);
 
-      String associationName = navProperty.getRelationship().getName();
+      String associationName = info.getRelationshipName();
       association.setName(associationName);
       return association;
     }
diff --git a/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/util/AnnotationHelper.java b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/util/AnnotationHelper.java
index 0d2ff11..d0f072a 100644
--- a/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/util/AnnotationHelper.java
+++ b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/util/AnnotationHelper.java
@@ -103,22 +103,18 @@
 
   private boolean isEqual(final Object firstKey, final Object secondKey) {
     if (firstKey == null) {
-      if (secondKey == null) {
-        return true;
-      } else {
-        return secondKey.equals(firstKey);
-      }
+      return secondKey == null || secondKey.equals(firstKey);
     } else {
       return firstKey.equals(secondKey);
     }
   }
 
-  public String extractEntitTypeName(final EdmNavigationProperty enp, final Class<?> fallbackClass) {
+  public String extractEntityTypeName(final EdmNavigationProperty enp, final Class<?> fallbackClass) {
     Class<?> entityTypeClass = enp.toType();
     return extractEntityTypeName(entityTypeClass == Object.class ? fallbackClass : entityTypeClass);
   }
 
-  public String extractEntitTypeName(final EdmNavigationProperty enp, final Field field) {
+  public String extractEntityTypeName(final EdmNavigationProperty enp, final Field field) {
     Class<?> entityTypeClass = enp.toType();
     if (entityTypeClass == Object.class) {
       Class<?> toClass = field.getType();
@@ -199,8 +195,7 @@
   }
 
   public String generateNamespace(final Class<?> annotatedClass) {
-    String packageName = annotatedClass.getPackage().getName();
-    return packageName;
+    return annotatedClass.getPackage().getName();
   }
 
   /**
@@ -263,40 +258,53 @@
     return propertyName;
   }
 
-  public String extractFromRoleName(final EdmNavigationProperty enp, final Field field) {
-    return getCanonicalRole(field.getDeclaringClass());
-  }
-
   public String extractToRoleName(final EdmNavigationProperty enp, final Field field) {
     String role = enp.toRole();
     if (role.isEmpty()) {
-      role = getCanonicalRole(
-          field.getType().isArray() || Collection.class.isAssignableFrom(field.getType()) ?
-              (Class<?>) ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0] : field.getType());
+      role = getCanonicalRoleName(field.getName());
     }
     return role;
   }
 
-  public String getCanonicalRole(final Class<?> fallbackClass) {
-    String toRole = extractEntityTypeName(fallbackClass);
-    return "r_" + toRole;
+  public String extractFromRoleEntityName(final Field field) {
+    return extractEntityTypeName(field.getDeclaringClass());
+  }
+
+  public String extractToRoleEntityName(final EdmNavigationProperty enp, final Field field) {
+    Class<?> clazz = enp.toType();
+    if (clazz == Object.class) {
+      if(field.getType().isArray() || Collection.class.isAssignableFrom(field.getType())) {
+        clazz = (Class<?>) ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0];
+      } else {
+        clazz = field.getType();
+      }
+    }
+    return extractEntityTypeName(clazz);
+  }
+
+  public String getCanonicalRoleName(String name) {
+    return "r_" + name.substring(0, 1).toUpperCase(Locale.ENGLISH) + name.substring(1);
   }
 
   public String extractRelationshipName(final EdmNavigationProperty enp, final Field field) {
     String relationshipName = enp.association();
     if (relationshipName.isEmpty()) {
-      final String fromRole = extractFromRoleName(enp, field);
-      final String toRole = extractToRoleName(enp, field);
-      if (fromRole.compareTo(toRole) > 0) {
-        relationshipName = toRole + "-" + fromRole;
-      } else {
-        relationshipName = fromRole + "-" + toRole;
-      }
+      final String fromRole = extractFromRoleEntityName(field);
+      final String toRole = extractToRoleEntityName(enp, field);
+      return createCanonicalRelationshipName(fromRole, toRole);
     }
     return relationshipName;
   }
 
-  public EdmMultiplicity getMultiplicity(final EdmNavigationProperty enp, final Field field) {
+  public String createCanonicalRelationshipName(String fromRole, String toRole) {
+      if (fromRole.compareTo(toRole) > 0) {
+        return toRole + "-" + fromRole;
+      } else {
+        return fromRole + "-" + toRole;
+      }
+  }
+
+  public EdmMultiplicity extractMultiplicity(final EdmNavigationProperty enp, final Field field) {
     EdmMultiplicity multiplicity = mapMultiplicity(enp.toMultiplicity());
     final boolean isCollectionType = field.getType().isArray() || Collection.class.isAssignableFrom(field.getType());
 
@@ -357,48 +365,131 @@
       return fromField;
     }
 
+    public String getFromRoleName() {
+      if(isBiDirectional()) {
+        return extractFromRoleEntityName(toField);
+      }
+      return extractToRoleName(toNavigation, toField);
+    }
+
     public Field getToField() {
       return toField;
     }
 
+    public String getToRoleName() {
+      if(isBiDirectional()) {
+        return extractToRoleName(toNavigation, toField);
+      }
+      return extractToRoleName(fromNavigation, fromField);
+    }
+
     public EdmMultiplicity getFromMultiplicity() {
-      return getMultiplicity(toNavigation, toField);
+      if(isBiDirectional()) {
+        return EdmMultiplicity.ONE;
+      }
+      return extractMultiplicity(toNavigation, toField);
     }
 
     public EdmMultiplicity getToMultiplicity() {
-      return getMultiplicity(fromNavigation, fromField);
+      if(isBiDirectional()) {
+        return extractMultiplicity(toNavigation, toField);
+      }
+      return extractMultiplicity(fromNavigation, fromField);
     }
 
     public boolean isBiDirectional() {
-      return toNavigation != null;
+      return fromNavigation == null;
+    }
+
+    public String getRelationshipName() {
+      String toAssociation = toNavigation.association();
+      String fromAssociation = "";
+      if(!isBiDirectional()) {
+        fromAssociation = fromNavigation.association();
+      }
+
+      if(fromAssociation.isEmpty() && fromAssociation.equals(toAssociation)) {
+        return createCanonicalRelationshipName(getFromRoleName(), getToRoleName());
+      } else if(toAssociation.isEmpty()) {
+        return fromAssociation;
+      } else if(!toAssociation.equals(fromAssociation)) {
+        throw new AnnotationRuntimeException("Invalid associations for navigation properties '" +
+            this.toString() + "'");
+      }
+      return toAssociation;
+    }
+
+    public String getFromTypeName() {
+      if(isBiDirectional()) {
+        return extractEntityTypeName(toField.getDeclaringClass());
+      }
+      return extractEntityTypeName(fromField.getDeclaringClass());
+    }
+
+    public String getToTypeName() {
+      if(isBiDirectional()) {
+        return extractEntityTypeName(ClassHelper.getFieldType(toField));
+      }
+      return extractEntityTypeName(toField.getDeclaringClass());
+    }
+
+    @Override
+    public String toString() {
+      if(isBiDirectional()) {
+        return "AnnotatedNavInfo{biDirectional = true" +
+            ", toField=" + toField.getName() +
+            ", toNavigation=" + toNavigation.name() + '}';
+      }
+      return "AnnotatedNavInfo{" +
+          "fromField=" + fromField.getName() +
+          ", toField=" + toField.getName() +
+          ", fromNavigation=" + fromNavigation.name() +
+          ", toNavigation=" + toNavigation.name() + '}';
     }
   }
 
+
   public AnnotatedNavInfo getCommonNavigationInfo(final Class<?> sourceClass, final Class<?> targetClass) {
     List<Field> sourceFields = getAnnotatedFields(sourceClass, EdmNavigationProperty.class);
     List<Field> targetFields = getAnnotatedFields(targetClass, EdmNavigationProperty.class);
 
+    if(sourceClass == targetClass) {
+      // special case, actual handled as bi-directional
+      return getCommonNavigationInfoBiDirectional(sourceClass, targetClass);
+    }
+
     // first try via association name to get full navigation information
     for (Field sourceField : sourceFields) {
-      final EdmNavigationProperty sourceNav = sourceField.getAnnotation(EdmNavigationProperty.class);
-      final String sourceAssociation = extractRelationshipName(sourceNav, sourceField);
-      for (Field targetField : targetFields) {
-        final EdmNavigationProperty targetNav = targetField.getAnnotation(EdmNavigationProperty.class);
-        final String targetAssociation = extractRelationshipName(targetNav, targetField);
-        if (sourceAssociation.equals(targetAssociation)) {
-          return new AnnotatedNavInfo(sourceField, targetField, sourceNav, targetNav);
+      if(ClassHelper.getFieldType(sourceField) == targetClass) {
+        final EdmNavigationProperty sourceNav = sourceField.getAnnotation(EdmNavigationProperty.class);
+        final String sourceAssociation = extractRelationshipName(sourceNav, sourceField);
+        for (Field targetField : targetFields) {
+          if(ClassHelper.getFieldType(targetField) == sourceClass) {
+            final EdmNavigationProperty targetNav = targetField.getAnnotation(EdmNavigationProperty.class);
+            final String targetAssociation = extractRelationshipName(targetNav, targetField);
+            if (sourceAssociation.equals(targetAssociation)) {
+              return new AnnotatedNavInfo(sourceField, targetField, sourceNav, targetNav);
+            }
+          }
         }
       }
     }
 
-    // if nothing was found assume none bi-directinal navigation
+    // if nothing was found assume/guess none bi-directional navigation
+    return getCommonNavigationInfoBiDirectional(sourceClass, targetClass);
+  }
+
+  private AnnotatedNavInfo getCommonNavigationInfoBiDirectional(final Class<?> sourceClass,
+                                                                final Class<?> targetClass) {
+    List<Field> sourceFields = getAnnotatedFields(sourceClass, EdmNavigationProperty.class);
+
     String targetEntityTypeName = extractEntityTypeName(targetClass);
     for (Field sourceField : sourceFields) {
       final EdmNavigationProperty sourceNav = sourceField.getAnnotation(EdmNavigationProperty.class);
-      final String navTargetEntityName = extractEntitTypeName(sourceNav, sourceField);
+      final String navTargetEntityName = extractEntityTypeName(sourceNav, sourceField);
 
       if (navTargetEntityName.equals(targetEntityTypeName)) {
-        return new AnnotatedNavInfo(sourceField, null, sourceNav, null);
+        return new AnnotatedNavInfo(null, sourceField, null, sourceNav);
       }
     }
 
@@ -576,7 +667,6 @@
 
   /**
    * 
-   * @param instance
    * @param resultClass
    * @param annotation
    * @param inherited
diff --git a/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/util/ClassHelper.java b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/util/ClassHelper.java
index 24082ff..a5e9eb9 100644
--- a/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/util/ClassHelper.java
+++ b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/util/ClassHelper.java
@@ -23,6 +23,7 @@
 import java.io.FilenameFilter;
 import java.io.IOException;
 import java.lang.reflect.Field;
+import java.lang.reflect.ParameterizedType;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.net.URL;
@@ -180,6 +181,21 @@
     }
   }
 
+  /**
+   * Get the type of the field. For arrays and collections the type of the array or collection is returned.
+   *
+   * @param field field for which the type is extracted
+   * @return type of the field (also for arrays or collections)
+   */
+  public static Class<?> getFieldType(Field field) {
+    if(field.getType().isArray() || Collection.class.isAssignableFrom(field.getType())) {
+      return (Class<?>) ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0];
+    } else {
+      return field.getType();
+    }
+  }
+
+
   public static Object getFieldValue(final Object instance, final Field field) {
     try {
       synchronized (field) {
diff --git a/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/annotation/processor/core/edm/AnnotationEdmProviderTest.java b/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/annotation/processor/core/edm/AnnotationEdmProviderTest.java
index 44187d4..50a1520 100644
--- a/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/annotation/processor/core/edm/AnnotationEdmProviderTest.java
+++ b/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/annotation/processor/core/edm/AnnotationEdmProviderTest.java
@@ -222,7 +222,7 @@
     assertEquals("Buildings", asBuildingRooms.getEnd1().getEntitySet());
     assertEquals("r_Building", asBuildingRooms.getEnd1().getRole());
     assertEquals("Rooms", asBuildingRooms.getEnd2().getEntitySet());
-    assertEquals("r_Room", asBuildingRooms.getEnd2().getRole());
+    assertEquals("r_Rooms", asBuildingRooms.getEnd2().getRole());
   }
 
   @Test
@@ -252,7 +252,7 @@
     assertEquals(6, entitySets.size());
 
     List<Association> associations = schema.getAssociations();
-    assertEquals(4, associations.size());
+    assertEquals(5, associations.size());
     for (Association association : associations) {
       assertNotNull(association.getName());
       validateAssociation(association);
@@ -265,22 +265,26 @@
 
   private void validateAssociation(final Association association) {
     String name = association.getName();
-    if (name.equals("r_Employee-r_Room")) {
+    if (name.equals("r_Employees-r_Room")) {
       validateAssociation(association,
           "r_Room", EdmMultiplicity.ONE, defaultFqn("Room"),
-          "r_Employee", EdmMultiplicity.MANY, defaultFqn("Employee"));
+          "r_Employees", EdmMultiplicity.MANY, defaultFqn("Employee"));
     } else if (name.equals("BuildingRooms")) {
       validateAssociation(association,
           "r_Building", EdmMultiplicity.ONE, defaultFqn("Building"),
-          "r_Room", EdmMultiplicity.MANY, defaultFqn("Room"));
+          "r_Rooms", EdmMultiplicity.MANY, defaultFqn("Room"));
     } else if (name.equals("ManagerEmployees")) {
       validateAssociation(association,
           "r_Manager", EdmMultiplicity.ONE, defaultFqn("Manager"),
-          "r_Employee", EdmMultiplicity.MANY, defaultFqn("Employee"));
+          "r_Employees", EdmMultiplicity.MANY, defaultFqn("Employee"));
     } else if (name.equals("TeamEmployees")) {
       validateAssociation(association,
           "r_Team", EdmMultiplicity.ONE, defaultFqn("Team"),
-          "r_Employee", EdmMultiplicity.MANY, defaultFqn("Employee"));
+          "r_Employees", EdmMultiplicity.MANY, defaultFqn("Employee"));
+    } else if (name.equals("Team-r_SubTeam")) {
+      validateAssociation(association,
+          "Team", EdmMultiplicity.ONE, defaultFqn("Team"),
+          "r_SubTeam", EdmMultiplicity.ONE, defaultFqn("Team"));
     } else {
       fail("Got unknown association to validate with name '" + name + "'.");
     }
@@ -333,11 +337,11 @@
 
     for (NavigationProperty navigationProperty : employee.getNavigationProperties()) {
       if (navigationProperty.getName().equals("ne_Manager")) {
-        validateNavProperty(navigationProperty, "ManagerEmployees", "r_Employee", "r_Manager");
+        validateNavProperty(navigationProperty, "ManagerEmployees", "r_Employees", "r_Manager");
       } else if (navigationProperty.getName().equals("ne_Team")) {
-        validateNavProperty(navigationProperty, "TeamEmployees", "r_Employee", "r_Team");
+        validateNavProperty(navigationProperty, "TeamEmployees", "r_Employees", "r_Team");
       } else if (navigationProperty.getName().equals("ne_Room")) {
-        validateNavProperty(navigationProperty, "r_Employee-r_Room", "r_Employee", "r_Room");
+        validateNavProperty(navigationProperty, "r_Employees-r_Room", "r_Employees", "r_Room");
       } else {
         fail("Got unexpected navigation property with name '" + navigationProperty.getName() + "'.");
       }
@@ -376,9 +380,11 @@
     assertEquals(ModelSharedConstants.NAMESPACE_1, team.getBaseType().getNamespace());
 
     assertEquals(1, team.getProperties().size());
-    assertEquals(1, team.getNavigationProperties().size());
-    NavigationProperty navigationProperty = team.getNavigationProperties().get(0);
-    validateNavProperty(navigationProperty, "TeamEmployees", "r_Team", "r_Employee");
+    assertEquals(2, team.getNavigationProperties().size());
+    NavigationProperty navPropTeamEmployess = team.getNavigationProperties().get(0);
+    validateNavProperty(navPropTeamEmployess, "TeamEmployees", "r_Team", "r_Employees");
+    NavigationProperty navPropTeamTeam = team.getNavigationProperties().get(1);
+    validateNavProperty(navPropTeamTeam, "Team-r_SubTeam", "Team", "r_SubTeam");
   }
 
   @Test
@@ -459,9 +465,9 @@
 
     for (NavigationProperty navigationProperty : navigationProperties) {
       if (navigationProperty.getName().equals("nr_Employees")) {
-        validateNavProperty(navigationProperty, "r_Employee-r_Room", "r_Room", "r_Employee");
+        validateNavProperty(navigationProperty, "r_Employees-r_Room", "r_Room", "r_Employees");
       } else if (navigationProperty.getName().equals("nr_Building")) {
-        validateNavProperty(navigationProperty, "BuildingRooms", "r_Room", "r_Building");
+        validateNavProperty(navigationProperty, "BuildingRooms", "r_Rooms", "r_Building");
       } else {
         fail("Got unexpected navigation property with name '" + navigationProperty.getName() + "'.");
       }
diff --git a/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/annotation/processor/core/model/Team.java b/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/annotation/processor/core/model/Team.java
index 8e5e794..23371a6 100644
--- a/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/annotation/processor/core/model/Team.java
+++ b/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/annotation/processor/core/model/Team.java
@@ -38,6 +38,8 @@
   private Boolean isScrumTeam;
   @EdmNavigationProperty(name = "nt_Employees", association = "TeamEmployees", toMultiplicity = Multiplicity.MANY)
   private List<Employee> employees = new ArrayList<Employee>();
+  @EdmNavigationProperty
+  private Team subTeam;
 
   public Team() {
     super(-1, null);
@@ -63,6 +65,10 @@
     return employees;
   }
 
+  public Team getSubTeam() {
+    return subTeam;
+  }
+
   @Override
   public int hashCode() {
     return id;
diff --git a/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/annotation/processor/core/util/AnnotationHelperTest.java b/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/annotation/processor/core/util/AnnotationHelperTest.java
index 18d7df2..478a1b7 100644
--- a/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/annotation/processor/core/util/AnnotationHelperTest.java
+++ b/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/annotation/processor/core/util/AnnotationHelperTest.java
@@ -17,6 +17,7 @@
 
 import java.lang.reflect.Field;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 import junit.framework.Assert;
@@ -160,26 +161,36 @@
   }
 
   @Test
-  public void extractEntitTypeNameViaNavigation() throws Exception {
+  public void extractEntityTypeNameViaNavigation() throws Exception {
     Field field = NavigationAnnotated.class.getDeclaredField("navigationPropertySimpleEntity");
     EdmNavigationProperty enp = field.getAnnotation(EdmNavigationProperty.class);
 
-    String name = annotationHelper.extractEntitTypeName(enp, SimpleEntity.class);
+    String name = annotationHelper.extractEntityTypeName(enp, SimpleEntity.class);
 
     Assert.assertEquals("SimpleEntity", name);
   }
 
   @Test
-  public void extractEntitTypeNameViaNavigationField() throws Exception {
+  public void extractEntityTypeNameViaNavigationField() throws Exception {
     Field field = NavigationAnnotated.class.getDeclaredField("navigationPropertyDefault");
     EdmNavigationProperty enp = field.getAnnotation(EdmNavigationProperty.class);
 
-    String name = annotationHelper.extractEntitTypeName(enp, field);
+    String name = annotationHelper.extractEntityTypeName(enp, field);
 
     Assert.assertEquals("SimpleEntity", name);
   }
 
   @Test
+  public void selfReferencedEntityTypeNameViaNavigationField() throws Exception {
+    Field field = NavigationAnnotated.class.getDeclaredField("selfReferencedNavigation");
+    EdmNavigationProperty enp = field.getAnnotation(EdmNavigationProperty.class);
+
+    String name = annotationHelper.extractToRoleName(enp, field);
+
+    Assert.assertEquals("r_SelfReferencedNavigation", name);
+  }
+
+  @Test
   public void getFieldTypeForPropertyNullInstance() throws Exception {
     Object result = annotationHelper.getFieldTypeForProperty(null, "");
     Assert.assertNull(result);
@@ -247,11 +258,14 @@
     }
   }
 
+  @EdmEntityType
   private class NavigationAnnotated {
     @EdmNavigationProperty(toType = SimpleEntity.class)
     SimpleEntity navigationPropertySimpleEntity;
     @EdmNavigationProperty
     SimpleEntity navigationPropertyDefault;
+    @EdmNavigationProperty
+    List<NavigationAnnotated> selfReferencedNavigation;
   }
 
   private class ConversionProperty {
diff --git a/odata2-annotation-processor/annotation-processor-ref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/AnnotationRefServiceFactory.java b/odata2-annotation-processor/annotation-processor-ref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/AnnotationRefServiceFactory.java
index 5a3766f..6bf3588 100644
--- a/odata2-annotation-processor/annotation-processor-ref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/AnnotationRefServiceFactory.java
+++ b/odata2-annotation-processor/annotation-processor-ref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/AnnotationRefServiceFactory.java
@@ -126,7 +126,7 @@
     teamDs.create(createTeam("Team Beta", false));
     teamDs.create(createTeam("Team Gamma", false));
     teamDs.create(createTeam("Team Omega", true));
-    teamDs.create(createTeam("Team Zeta", true));
+    teamDs.create(createTeam("Team Zeta", true, createTeam("SubTeamOne", false)));
 
     DataStore<Building> buildingsDs = getDataStore(Building.class);
     Building redBuilding = createBuilding("Red Building");
@@ -179,9 +179,14 @@
   }
 
   private static Team createTeam(final String teamName, final boolean isScrumTeam) {
+    return createTeam(teamName, isScrumTeam, null);
+  }
+
+  private static Team createTeam(final String teamName, final boolean isScrumTeam, Team subTeam) {
     Team team = new Team();
     team.setName(teamName);
     team.setScrumTeam(isScrumTeam);
+    subTeam.setSubTeam(subTeam);
     return team;
   }
 
diff --git a/odata2-annotation-processor/annotation-processor-ref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/Team.java b/odata2-annotation-processor/annotation-processor-ref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/Team.java
index 7f48f66..9e3d38c 100644
--- a/odata2-annotation-processor/annotation-processor-ref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/Team.java
+++ b/odata2-annotation-processor/annotation-processor-ref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/Team.java
@@ -38,6 +38,8 @@
   private Boolean isScrumTeam;
   @EdmNavigationProperty(name = "nt_Employees", association = "TeamEmployees", toMultiplicity = Multiplicity.MANY)
   private List<Employee> employees = new ArrayList<Employee>();
+  @EdmNavigationProperty
+  private Team subTeam;
 
   public Boolean isScrumTeam() {
     return isScrumTeam;
@@ -55,6 +57,14 @@
     return employees;
   }
 
+  public void setSubTeam(Team subTeam) {
+    this.subTeam = subTeam;
+  }
+
+  public Team getSubTeam() {
+    return subTeam;
+  }
+
   @Override
   public int hashCode() {
     return super.hashCode();
diff --git a/odata2-annotation-processor/annotation-processor-ref/src/test/java/org/apache/olingo/odata2/annotation/processor/ref/MetadataTest.java b/odata2-annotation-processor/annotation-processor-ref/src/test/java/org/apache/olingo/odata2/annotation/processor/ref/MetadataTest.java
index 5114594..0068869 100644
--- a/odata2-annotation-processor/annotation-processor-ref/src/test/java/org/apache/olingo/odata2/annotation/processor/ref/MetadataTest.java
+++ b/odata2-annotation-processor/annotation-processor-ref/src/test/java/org/apache/olingo/odata2/annotation/processor/ref/MetadataTest.java
@@ -101,17 +101,17 @@
     assertXpathExists(
         "/edmx:Edmx/edmx:DataServices/edm:Schema/edm:EntityType[@Name='Employee' and" +
             " @m:HasStream='true']/edm:NavigationProperty[@Name='ne_Manager' and " +
-            "@Relationship='RefScenario.ManagerEmployees' and @FromRole='r_Employee' and @ToRole='r_Manager']",
+            "@Relationship='RefScenario.ManagerEmployees' and @FromRole='r_Employees' and @ToRole='r_Manager']",
         payload);
     assertXpathExists(
         "/edmx:Edmx/edmx:DataServices/edm:Schema/edm:EntityType[@Name='Employee' and" +
             " @m:HasStream='true']/edm:NavigationProperty[@Name='ne_Team' and " +
-            "@Relationship='RefScenario.TeamEmployees' and @FromRole='r_Employee' and @ToRole='r_Team']",
+            "@Relationship='RefScenario.TeamEmployees' and @FromRole='r_Employees' and @ToRole='r_Team']",
         payload);
     assertXpathExists(
         "/edmx:Edmx/edmx:DataServices/edm:Schema/edm:EntityType[@Name='Employee' and " +
             "@m:HasStream='true']/edm:NavigationProperty[@Name='ne_Room' and " +
-            "@Relationship='RefScenario.r_Employee-r_Room' and @FromRole='r_Employee' and @ToRole='r_Room']",
+            "@Relationship='RefScenario.r_Employees-r_Room' and @FromRole='r_Employees' and @ToRole='r_Room']",
         payload);
 
     // Team
@@ -126,7 +126,7 @@
     assertXpathExists(
         "/edmx:Edmx/edmx:DataServices/edm:Schema/edm:EntityType[@Name='Team' and " +
             "@BaseType='RefScenario.Base']/edm:NavigationProperty[@Name='nt_Employees' and " +
-            "@Relationship='RefScenario.TeamEmployees' and @FromRole='r_Team' and @ToRole='r_Employee']",
+            "@Relationship='RefScenario.TeamEmployees' and @FromRole='r_Team' and @ToRole='r_Employees']",
         payload);
 
     // Room
@@ -144,12 +144,12 @@
     assertXpathExists(
         "/edmx:Edmx/edmx:DataServices/edm:Schema/edm:EntityType[@Name='Room' and" +
             " @BaseType='RefScenario.Base']/edm:NavigationProperty[@Name='nr_Employees' and " +
-            "@Relationship='RefScenario.r_Employee-r_Room' and @FromRole='r_Room' and @ToRole='r_Employee']",
+            "@Relationship='RefScenario.r_Employees-r_Room' and @FromRole='r_Room' and @ToRole='r_Employees']",
         payload);
     assertXpathExists(
         "/edmx:Edmx/edmx:DataServices/edm:Schema/edm:EntityType[@Name='Room' and " +
             "@BaseType='RefScenario.Base']/edm:NavigationProperty[@Name='nr_Building' and " +
-            "@Relationship='RefScenario.BuildingRooms' and @FromRole='r_Room' and @ToRole='r_Building']",
+            "@Relationship='RefScenario.BuildingRooms' and @FromRole='r_Rooms' and @ToRole='r_Building']",
         payload);
 
     // Manager
@@ -157,7 +157,7 @@
             "@BaseType='RefScenario.Employee']", payload);
     assertXpathExists("/edmx:Edmx/edmx:DataServices/edm:Schema/edm:EntityType[@Name='Manager' and " +
             "@BaseType='RefScenario.Employee']/edm:NavigationProperty[@Name='nm_Employees' and " +
-            "@Relationship='RefScenario.ManagerEmployees' and @FromRole='r_Manager' and @ToRole='r_Employee']",
+            "@Relationship='RefScenario.ManagerEmployees' and @FromRole='r_Manager' and @ToRole='r_Employees']",
         payload);
 
     // Building
@@ -174,7 +174,7 @@
     assertXpathExists(
         "/edmx:Edmx/edmx:DataServices/edm:Schema/edm:EntityType[@Name='Building']" +
                 "/edm:NavigationProperty[@Name='nb_Rooms' and @Relationship='RefScenario.BuildingRooms' " +
-                "and @FromRole='r_Building' and @ToRole='r_Room']", payload);
+                "and @FromRole='r_Building' and @ToRole='r_Rooms']", payload);
 
     // Base
     assertXpathExists("/edmx:Edmx/edmx:DataServices/edm:Schema/edm:EntityType[@Name='Base' and @Abstract='true']",
@@ -219,22 +219,22 @@
     // ManagerEmployees
     assertXpathExists("/edmx:Edmx/edmx:DataServices/edm:Schema/edm:Association[@Name='ManagerEmployees']", payload);
     assertXpathExists("/edmx:Edmx/edmx:DataServices/edm:Schema/edm:Association[@Name='ManagerEmployees']" +
-            "/edm:End[@Type='RefScenario.Employee' and @Multiplicity='*' and @Role='r_Employee']", payload);
+            "/edm:End[@Type='RefScenario.Employee' and @Multiplicity='*' and @Role='r_Employees']", payload);
     assertXpathExists( "/edmx:Edmx/edmx:DataServices/edm:Schema/edm:Association[@Name='ManagerEmployees']" +
             "/edm:End[@Type='RefScenario.Manager' and @Multiplicity='1' and @Role='r_Manager']", payload);
 
     // TeamEmployees
     assertXpathExists("/edmx:Edmx/edmx:DataServices/edm:Schema/edm:Association[@Name='TeamEmployees']", payload);
     assertXpathExists( "/edmx:Edmx/edmx:DataServices/edm:Schema/edm:Association[@Name='TeamEmployees']" +
-            "/edm:End[@Type='RefScenario.Employee' and @Multiplicity='*' and @Role='r_Employee']", payload);
+            "/edm:End[@Type='RefScenario.Employee' and @Multiplicity='*' and @Role='r_Employees']", payload);
     assertXpathExists("/edmx:Edmx/edmx:DataServices/edm:Schema/edm:Association[@Name='TeamEmployees']" +
             "/edm:End[@Type='RefScenario.Team' and @Multiplicity='1' and @Role='r_Team']", payload);
 
     // RoomEmployees
-    assertXpathExists("/edmx:Edmx/edmx:DataServices/edm:Schema/edm:Association[@Name='r_Employee-r_Room']", payload);
-    assertXpathExists("/edmx:Edmx/edmx:DataServices/edm:Schema/edm:Association[@Name='r_Employee-r_Room']" +
-            "/edm:End[@Type='RefScenario.Employee' and @Multiplicity='*' and @Role='r_Employee']", payload);
-    assertXpathExists("/edmx:Edmx/edmx:DataServices/edm:Schema/edm:Association[@Name='r_Employee-r_Room']" +
+    assertXpathExists("/edmx:Edmx/edmx:DataServices/edm:Schema/edm:Association[@Name='r_Employees-r_Room']", payload);
+    assertXpathExists("/edmx:Edmx/edmx:DataServices/edm:Schema/edm:Association[@Name='r_Employees-r_Room']" +
+            "/edm:End[@Type='RefScenario.Employee' and @Multiplicity='*' and @Role='r_Employees']", payload);
+    assertXpathExists("/edmx:Edmx/edmx:DataServices/edm:Schema/edm:Association[@Name='r_Employees-r_Room']" +
             "/edm:End[@Type='RefScenario.Room' and @Multiplicity='1' and @Role='r_Room']", payload);
 
     // BuildingRooms
@@ -242,7 +242,7 @@
     assertXpathExists("/edmx:Edmx/edmx:DataServices/edm:Schema/edm:Association[@Name='BuildingRooms']" +
             "/edm:End[@Type='RefScenario.Building' and @Multiplicity='1' and @Role='r_Building']", payload);
     assertXpathExists("/edmx:Edmx/edmx:DataServices/edm:Schema/edm:Association[@Name='BuildingRooms']" +
-            "/edm:End[@Type='RefScenario.Room' and @Multiplicity='*' and @Role='r_Room']", payload);
+            "/edm:End[@Type='RefScenario.Room' and @Multiplicity='*' and @Role='r_Rooms']", payload);
   }
 
   @Test
@@ -291,7 +291,7 @@
     assertXpathExists(
         "/edmx:Edmx/edmx:DataServices/edm:Schema/edm:EntityContainer[@Name='DefaultContainer' and " +
             "@m:IsDefaultEntityContainer='true']/edm:AssociationSet[@Name='ManagerEmployees' and " +
-            "@Association='RefScenario.ManagerEmployees']/edm:End[@EntitySet='Employees' and @Role='r_Employee']",
+            "@Association='RefScenario.ManagerEmployees']/edm:End[@EntitySet='Employees' and @Role='r_Employees']",
         payload);
 
     assertXpathExists(
@@ -307,23 +307,23 @@
     assertXpathExists(
         "/edmx:Edmx/edmx:DataServices/edm:Schema/edm:EntityContainer[@Name='DefaultContainer' and " +
             "@m:IsDefaultEntityContainer='true']/edm:AssociationSet[@Name='TeamEmployees' and " +
-            "@Association='RefScenario.TeamEmployees']/edm:End[@EntitySet='Employees' and @Role='r_Employee']",
+            "@Association='RefScenario.TeamEmployees']/edm:End[@EntitySet='Employees' and @Role='r_Employees']",
         payload);
 
     assertXpathExists(
         "/edmx:Edmx/edmx:DataServices/edm:Schema/edm:EntityContainer[@Name='DefaultContainer' and " +
-            "@m:IsDefaultEntityContainer='true']/edm:AssociationSet[@Name='r_Employee-r_Room' and " +
-            "@Association='RefScenario.r_Employee-r_Room']",
+            "@m:IsDefaultEntityContainer='true']/edm:AssociationSet[@Name='r_Employees-r_Room' and " +
+            "@Association='RefScenario.r_Employees-r_Room']",
         payload);
     assertXpathExists(
         "/edmx:Edmx/edmx:DataServices/edm:Schema/edm:EntityContainer[@Name='DefaultContainer' and " +
-            "@m:IsDefaultEntityContainer='true']/edm:AssociationSet[@Name='r_Employee-r_Room' and " +
-            "@Association='RefScenario.r_Employee-r_Room']/edm:End[@EntitySet='Rooms' and @Role='r_Room']",
+            "@m:IsDefaultEntityContainer='true']/edm:AssociationSet[@Name='r_Employees-r_Room' and " +
+            "@Association='RefScenario.r_Employees-r_Room']/edm:End[@EntitySet='Rooms' and @Role='r_Room']",
         payload);
     assertXpathExists(
         "/edmx:Edmx/edmx:DataServices/edm:Schema/edm:EntityContainer[@Name='DefaultContainer' and " +
-            "@m:IsDefaultEntityContainer='true']/edm:AssociationSet[@Name='r_Employee-r_Room' and " +
-            "@Association='RefScenario.r_Employee-r_Room']/edm:End[@EntitySet='Employees' and @Role='r_Employee']",
+            "@m:IsDefaultEntityContainer='true']/edm:AssociationSet[@Name='r_Employees-r_Room' and " +
+            "@Association='RefScenario.r_Employees-r_Room']/edm:End[@EntitySet='Employees' and @Role='r_Employees']",
         payload);
 
     assertXpathExists(
@@ -339,7 +339,7 @@
     assertXpathExists(
         "/edmx:Edmx/edmx:DataServices/edm:Schema/edm:EntityContainer[@Name='DefaultContainer' and " +
             "@m:IsDefaultEntityContainer='true']/edm:AssociationSet[@Name='BuildingRooms' and " +
-            "@Association='RefScenario.BuildingRooms']/edm:End[@EntitySet='Rooms' and @Role='r_Room']",
+            "@Association='RefScenario.BuildingRooms']/edm:End[@EntitySet='Rooms' and @Role='r_Rooms']",
         payload);
   }
 }