Repository: olingo-odata2 Updated Branches: refs/heads/OLINGO-508_FixAnnotationEdmProvider [created] 6f7b76f68
[OLINGO-508] Fixed OneToMany self reference Project: http://git-wip-us.apache.org/repos/asf/olingo-odata2/repo Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata2/commit/6f7b76f6 Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata2/tree/6f7b76f6 Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata2/diff/6f7b76f6 Branch: refs/heads/OLINGO-508_FixAnnotationEdmProvider Commit: 6f7b76f689e4a8c8889c59760715c80d4a4c17f2 Parents: 4bab6aa Author: mibo <[email protected]> Authored: Sat Dec 13 16:50:52 2014 +0100 Committer: mibo <[email protected]> Committed: Sat Dec 13 16:50:52 2014 +0100 ---------------------------------------------------------------------- .../core/edm/AnnotationEdmProvider.java | 39 +++-- .../processor/core/util/AnnotationHelper.java | 170 ++++++++++++++----- .../processor/core/util/ClassHelper.java | 16 ++ .../core/edm/AnnotationEdmProviderTest.java | 36 ++-- .../annotation/processor/core/model/Team.java | 6 + .../core/util/AnnotationHelperTest.java | 22 ++- .../ref/AnnotationRefServiceFactory.java | 7 +- .../annotation/processor/ref/model/Team.java | 10 ++ .../annotation/processor/ref/MetadataTest.java | 48 +++--- 9 files changed, 250 insertions(+), 104 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/6f7b76f6/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/edm/AnnotationEdmProvider.java ---------------------------------------------------------------------- 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 @@ public class AnnotationEdmProvider extends EdmProvider { } 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 @@ public class AnnotationEdmProvider extends EdmProvider { 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 @@ public class AnnotationEdmProvider extends EdmProvider { 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; } http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/6f7b76f6/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/util/AnnotationHelper.java ---------------------------------------------------------------------- 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 @@ public class AnnotationHelper { 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 class AnnotationHelper { } public String generateNamespace(final Class<?> annotatedClass) { - String packageName = annotatedClass.getPackage().getName(); - return packageName; + return annotatedClass.getPackage().getName(); } /** @@ -263,40 +258,53 @@ public class AnnotationHelper { 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); + final String fromRole = extractFromRoleEntityName(field); + final String toRole = extractToRoleEntityName(enp, field); + return createCanonicalRelationshipName(fromRole, toRole); + } + return relationshipName; + } + + public String createCanonicalRelationshipName(String fromRole, String toRole) { if (fromRole.compareTo(toRole) > 0) { - relationshipName = toRole + "-" + fromRole; + return toRole + "-" + fromRole; } else { - relationshipName = fromRole + "-" + toRole; + return fromRole + "-" + toRole; } - } - return relationshipName; } - public EdmMultiplicity getMultiplicity(final EdmNavigationProperty enp, final Field field) { + 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 @@ public class AnnotationHelper { 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 @@ public class AnnotationHelper { /** * - * @param instance * @param resultClass * @param annotation * @param inherited http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/6f7b76f6/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/annotation/processor/core/util/ClassHelper.java ---------------------------------------------------------------------- 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.FileFilter; 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 @@ public class ClassHelper { } } + /** + * 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) { http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/6f7b76f6/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/annotation/processor/core/edm/AnnotationEdmProviderTest.java ---------------------------------------------------------------------- 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 @@ public class AnnotationEdmProviderTest { 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 @@ public class AnnotationEdmProviderTest { 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 @@ public class AnnotationEdmProviderTest { 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 @@ public class AnnotationEdmProviderTest { 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 @@ public class AnnotationEdmProviderTest { 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 @@ public class AnnotationEdmProviderTest { 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() + "'."); } http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/6f7b76f6/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/annotation/processor/core/model/Team.java ---------------------------------------------------------------------- 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 @@ public class Team extends RefBase { 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 @@ public class Team extends RefBase { return employees; } + public Team getSubTeam() { + return subTeam; + } + @Override public int hashCode() { return id; http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/6f7b76f6/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/annotation/processor/core/util/AnnotationHelperTest.java ---------------------------------------------------------------------- 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 @@ package org.apache.olingo.odata2.annotation.processor.core.util; 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 @@ public class AnnotationHelperTest { } @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 @@ public class AnnotationHelperTest { } } + @EdmEntityType private class NavigationAnnotated { @EdmNavigationProperty(toType = SimpleEntity.class) SimpleEntity navigationPropertySimpleEntity; @EdmNavigationProperty SimpleEntity navigationPropertyDefault; + @EdmNavigationProperty + List<NavigationAnnotated> selfReferencedNavigation; } private class ConversionProperty { http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/6f7b76f6/odata2-annotation-processor/annotation-processor-ref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/AnnotationRefServiceFactory.java ---------------------------------------------------------------------- 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 @@ public class AnnotationRefServiceFactory extends ODataServiceFactory { 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 @@ public class AnnotationRefServiceFactory extends ODataServiceFactory { } 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; } http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/6f7b76f6/odata2-annotation-processor/annotation-processor-ref/src/main/java/org/apache/olingo/odata2/annotation/processor/ref/model/Team.java ---------------------------------------------------------------------- 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 @@ public class Team extends RefBase { 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 @@ public class Team extends RefBase { return employees; } + public void setSubTeam(Team subTeam) { + this.subTeam = subTeam; + } + + public Team getSubTeam() { + return subTeam; + } + @Override public int hashCode() { return super.hashCode(); http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/6f7b76f6/odata2-annotation-processor/annotation-processor-ref/src/test/java/org/apache/olingo/odata2/annotation/processor/ref/MetadataTest.java ---------------------------------------------------------------------- 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 @@ public class MetadataTest extends AbstractRefXmlTest { 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 @@ public class MetadataTest extends AbstractRefXmlTest { 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 @@ public class MetadataTest extends AbstractRefXmlTest { 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 @@ public class MetadataTest extends AbstractRefXmlTest { "@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 @@ public class MetadataTest extends AbstractRefXmlTest { 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 @@ public class MetadataTest extends AbstractRefXmlTest { // 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 @@ public class MetadataTest extends AbstractRefXmlTest { 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 @@ public class MetadataTest extends AbstractRefXmlTest { 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 @@ public class MetadataTest extends AbstractRefXmlTest { 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 @@ public class MetadataTest extends AbstractRefXmlTest { 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); } }
