You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by sk...@apache.org on 2014/02/17 13:40:58 UTC
[31/51] [abbrv] Renamed project
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/39485c57/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/util/AnnotationHelper.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/util/AnnotationHelper.java b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/util/AnnotationHelper.java
new file mode 100644
index 0000000..0c81fb1
--- /dev/null
+++ b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/util/AnnotationHelper.java
@@ -0,0 +1,726 @@
+/**
+ * *****************************************************************************
+ * 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.core.annotation.util;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.ParameterizedType;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.olingo.odata2.api.annotation.edm.EdmComplexType;
+import org.apache.olingo.odata2.api.annotation.edm.EdmEntitySet;
+import org.apache.olingo.odata2.api.annotation.edm.EdmEntityType;
+import org.apache.olingo.odata2.api.annotation.edm.EdmKey;
+import org.apache.olingo.odata2.api.annotation.edm.EdmNavigationProperty;
+import org.apache.olingo.odata2.api.annotation.edm.EdmNavigationProperty.Multiplicity;
+import org.apache.olingo.odata2.api.annotation.edm.EdmProperty;
+import org.apache.olingo.odata2.api.edm.EdmLiteralKind;
+import org.apache.olingo.odata2.api.edm.EdmMultiplicity;
+import org.apache.olingo.odata2.api.edm.EdmSimpleTypeException;
+import org.apache.olingo.odata2.api.edm.EdmSimpleTypeKind;
+import org.apache.olingo.odata2.api.edm.FullQualifiedName;
+import org.apache.olingo.odata2.api.exception.ODataException;
+import org.apache.olingo.odata2.core.exception.ODataRuntimeException;
+
+/**
+ *
+ */
+public class AnnotationHelper {
+
+ public static final String DEFAULT_CONTAINER_NAME = "DefaultContainer";
+
+ /**
+ * Compare keys of both instances.
+ *
+ * @param firstInstance
+ * @param secondInstance
+ * @return
+ */
+ public boolean keyMatch(Object firstInstance, Object secondInstance) {
+ if (firstInstance == null || secondInstance == null) {
+ return false;
+ } else if (firstInstance.getClass() != secondInstance.getClass()) {
+ return false;
+ }
+
+ Map<String, Object> firstKeyFields = getValueForAnnotatedFields(firstInstance, EdmKey.class);
+ Map<String, Object> secondKeyFields = getValueForAnnotatedFields(secondInstance, EdmKey.class);
+
+ return keyValuesMatch(firstKeyFields, secondKeyFields);
+ }
+
+ /**
+ * Compare keys of instance with key values in map.
+ *
+ * @param instance
+ * @param keyName2Value
+ * @return
+ */
+ public boolean keyMatch(Object instance, Map<String, Object> keyName2Value) {
+ Map<String, Object> instanceKeyFields = getValueForAnnotatedFields(instance, EdmKey.class);
+ return keyValuesMatch(instanceKeyFields, keyName2Value);
+ }
+
+ private boolean keyValuesMatch(Map<String, Object> firstKeyValues, Map<String, Object> secondKeyValues) {
+ if (firstKeyValues.size() != secondKeyValues.size()) {
+ return false;
+ } else {
+ Set<Map.Entry<String, Object>> entries = firstKeyValues.entrySet();
+ for (Map.Entry<String, Object> entry : entries) {
+ Object firstKey = entry.getValue();
+ Object secondKey = secondKeyValues.get(entry.getKey());
+ if (!isEqual(firstKey, secondKey)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ private boolean isEqual(Object firstKey, Object secondKey) {
+ if (firstKey == null) {
+ if (secondKey == null) {
+ return true;
+ } else {
+ return secondKey.equals(firstKey);
+ }
+ } else {
+ return firstKey.equals(secondKey);
+ }
+ }
+
+ public String extractEntitTypeName(EdmNavigationProperty enp, Class<?> fallbackClass) {
+ Class<?> entityTypeClass = enp.toType();
+ return extractEntityTypeName(entityTypeClass == Object.class ? fallbackClass : entityTypeClass);
+ }
+
+ public String extractEntitTypeName(EdmNavigationProperty enp, Field field) {
+ Class<?> entityTypeClass = enp.toType();
+ if (entityTypeClass == Object.class) {
+ Class<?> toClass = field.getType();
+ return extractEntityTypeName((toClass.isArray() || Collection.class.isAssignableFrom(toClass) ?
+ (Class<?>) ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0] : toClass));
+ } else {
+ return extractEntityTypeName(entityTypeClass);
+ }
+ }
+
+ /**
+ * Returns <code>NULL</code> if given class is not annotated. If annotated the set entity type name is returned and if
+ * no name is set the default name is generated from the simple class name.
+ *
+ * @param annotatedClass
+ * @return
+ */
+ public String extractEntityTypeName(Class<?> annotatedClass) {
+ return extractTypeName(annotatedClass, EdmEntityType.class);
+ }
+
+ public FullQualifiedName extractEntityTypeFqn(EdmEntityType type, Class<?> annotatedClass) {
+ if(type.namespace().isEmpty()) {
+ return new FullQualifiedName(generateNamespace(annotatedClass), extractEntityTypeName(annotatedClass));
+ }
+ return new FullQualifiedName(type.namespace(), extractEntityTypeName(annotatedClass));
+ }
+
+ public FullQualifiedName extractEntityTypeFqn(Class<?> annotatedClass) {
+ EdmEntityType type = annotatedClass.getAnnotation(EdmEntityType.class);
+ if(type == null) {
+ return null;
+ }
+ return extractEntityTypeFqn(type, annotatedClass);
+ }
+
+ public FullQualifiedName extractComplexTypeFqn(Class<?> annotatedClass) {
+ EdmComplexType type = annotatedClass.getAnnotation(EdmComplexType.class);
+ if(type == null) {
+ return null;
+ }
+ return extractComplexTypeFqn(type, annotatedClass);
+ }
+
+ public FullQualifiedName extractComplexTypeFqn(EdmComplexType type, Class<?> annotatedClass) {
+ if(type.namespace().isEmpty()) {
+ return new FullQualifiedName(generateNamespace(annotatedClass), extractComplexTypeName(annotatedClass));
+ }
+ return new FullQualifiedName(type.namespace(), extractComplexTypeName(annotatedClass));
+ }
+
+ public String extractComplexTypeName(Class<?> annotatedClass) {
+ return extractTypeName(annotatedClass, EdmComplexType.class);
+ }
+
+ public String generateNamespace(Class<?> annotatedClass) {
+ String packageName = annotatedClass.getPackage().getName();
+ return packageName;
+ }
+
+ /**
+ *
+ *
+ * @param <T> must be EdmEntityType or EdmComplexType annotation
+ * @param annotatedClass
+ * @param typeAnnotation
+ * @return null if annotatedClass is not annotated or name set via annotation or generated via
+ * {@link #getCanonicalName(java.lang.Class)}
+ */
+ private <T extends Annotation> String extractTypeName(Class<?> annotatedClass, Class<T> typeAnnotation) {
+ if (annotatedClass == Object.class) {
+ return null;
+ }
+ T type = annotatedClass.getAnnotation(typeAnnotation);
+ if (type == null) {
+ return null;
+ }
+
+ String name;
+ if (typeAnnotation == EdmEntityType.class) {
+ name = ((EdmEntityType) type).name();
+ } else if (typeAnnotation == EdmComplexType.class) {
+ name = ((EdmComplexType) type).name();
+ } else {
+ return null;
+ }
+
+ if (name.isEmpty()) {
+ return getCanonicalName(annotatedClass);
+ }
+ return name;
+ }
+
+ /**
+ * Get the set property name from an EdmProperty or EdmNavigationProperty annotation.
+ *
+ * @param field
+ * @return
+ */
+ public String getPropertyNameFromAnnotation(Field field) {
+ EdmProperty property = field.getAnnotation(EdmProperty.class);
+ if (property == null) {
+ EdmNavigationProperty navProperty = field.getAnnotation(EdmNavigationProperty.class);
+ if (navProperty == null) {
+ throw new EdmAnnotationException("Given field '" + field
+ + "' has no EdmProperty or EdmNavigationProperty annotation.");
+ }
+ return navProperty.name();
+ }
+ return property.name();
+ }
+
+ public String getPropertyName(Field field) {
+ String propertyName = getPropertyNameFromAnnotation(field);
+ if (propertyName.isEmpty()) {
+ propertyName = getCanonicalName(field);
+ }
+ return propertyName;
+ }
+
+ public String extractFromRoleName(EdmNavigationProperty enp, Field field) {
+ return getCanonicalRole(field.getDeclaringClass());
+ }
+
+ public String extractToRoleName(EdmNavigationProperty enp, 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());
+ }
+ return role;
+ }
+
+ public String getCanonicalRole(Class<?> fallbackClass) {
+ String toRole = extractEntityTypeName(fallbackClass);
+ return "r_" + toRole;
+ }
+
+ public String extractRelationshipName(EdmNavigationProperty enp, 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;
+ }
+ }
+ return relationshipName;
+ }
+
+ public EdmMultiplicity getMultiplicity(EdmNavigationProperty enp, Field field) {
+ EdmMultiplicity multiplicity = mapMultiplicity(enp.toMultiplicity());
+ final boolean isCollectionType = field.getType().isArray() || Collection.class.isAssignableFrom(field.getType());
+
+ if (multiplicity == EdmMultiplicity.ONE && isCollectionType) {
+ return EdmMultiplicity.MANY;
+ }
+ return multiplicity;
+ }
+
+
+ /**
+ * Set key fields based on values in map.
+ * If an key field is not available or <code>NULL</code> in the map
+ * it will be not set as <code>NULL</code> at the instance object.
+ *
+ * @param instance
+ * @param keys
+ * @return
+ */
+ public <T> T setKeyFields(T instance, Map<String, Object> keys) {
+ List<Field> fields = getAnnotatedFields(instance, EdmKey.class);
+
+ for (Field field : fields) {
+ String propertyName = getPropertyName(field);
+ Object keyValue = keys.get(propertyName);
+ setValueForProperty(instance, propertyName, keyValue);
+ }
+
+ return instance;
+ }
+
+ public static final class ODataAnnotationException extends ODataException {
+ private static final long serialVersionUID = 1L;
+
+ public ODataAnnotationException(String message) {
+ super(message);
+ }
+ }
+
+
+ public class AnnotatedNavInfo {
+ private final Field fromField;
+ private final Field toField;
+ private final EdmNavigationProperty fromNavigation;
+ private final EdmNavigationProperty toNavigation;
+
+ public AnnotatedNavInfo(Field fromField, Field toField, EdmNavigationProperty fromNavigation,
+ EdmNavigationProperty toNavigation) {
+ this.fromField = fromField;
+ this.toField = toField;
+ this.fromNavigation = fromNavigation;
+ this.toNavigation = toNavigation;
+ }
+
+ public Field getFromField() {
+ return fromField;
+ }
+
+ public Field getToField() {
+ return toField;
+ }
+
+ public EdmMultiplicity getFromMultiplicity() {
+ return getMultiplicity(toNavigation, toField);
+ }
+
+ public EdmMultiplicity getToMultiplicity() {
+ return getMultiplicity(fromNavigation, fromField);
+ }
+
+ public boolean isBiDirectional() {
+ return toNavigation != null;
+ }
+ }
+
+ public AnnotatedNavInfo getCommonNavigationInfo(Class<?> sourceClass, Class<?> targetClass) {
+ List<Field> sourceFields = getAnnotatedFields(sourceClass, EdmNavigationProperty.class);
+ List<Field> targetFields = getAnnotatedFields(targetClass, EdmNavigationProperty.class);
+
+ // 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 nothing was found assume none bi-directinal navigation
+ String targetEntityTypeName = extractEntityTypeName(targetClass);
+ for (Field sourceField : sourceFields) {
+ final EdmNavigationProperty sourceNav = sourceField.getAnnotation(EdmNavigationProperty.class);
+ final String navTargetEntityName = extractEntitTypeName(sourceNav, sourceField);
+
+ if (navTargetEntityName.equals(targetEntityTypeName)) {
+ return new AnnotatedNavInfo(sourceField, null, sourceNav, null);
+ }
+ }
+
+ return null;
+ }
+
+ public Class<?> getFieldTypeForProperty(Object instance, String propertyName) throws ODataAnnotationException {
+ if (instance == null) {
+ return null;
+ }
+
+ Field field = getFieldForPropertyName(instance, propertyName, instance.getClass(), true);
+ if (field == null) {
+ throw new ODataAnnotationException("No field for property '" + propertyName
+ + "' found at class '" + instance.getClass() + "'.");
+ }
+ return field.getType();
+ }
+
+ public Object getValueForProperty(Object instance, String propertyName) throws ODataAnnotationException {
+ if (instance == null) {
+ return null;
+ }
+
+ Field field = getFieldForPropertyName(instance, propertyName, instance.getClass(), true);
+ if (field == null) {
+ throw new ODataAnnotationException("No field for property '" + propertyName
+ + "' found at class '" + instance.getClass() + "'.");
+ }
+ return getFieldValue(instance, field);
+ }
+
+ public void setValueForProperty(Object instance, String propertyName, Object propertyValue) {
+ if (instance != null) {
+ Field field = getFieldForPropertyName(instance, propertyName, instance.getClass(), true);
+ if (field != null) {
+ setFieldValue(instance, field, propertyValue);
+ }
+ }
+ }
+
+ private Field getFieldForPropertyName(Object instance, String propertyName,
+ Class<?> resultClass, boolean inherited) {
+ if (instance == null) {
+ return null;
+ }
+
+ Field[] fields = resultClass.getDeclaredFields();
+ for (Field field : fields) {
+ EdmProperty property = field.getAnnotation(EdmProperty.class);
+ if (property != null) {
+ if (property.name().isEmpty() && getCanonicalName(field).equals(propertyName)) {
+ return field;
+ } else if (property.name().equals(propertyName)) {
+ return field;
+ }
+ }
+ }
+
+ Class<?> superClass = resultClass.getSuperclass();
+ if (inherited && superClass != Object.class) {
+ return getFieldForPropertyName(instance, propertyName, superClass, true);
+ }
+
+ return null;
+ }
+
+ public Object getValueForField(Object instance, String fieldName, Class<? extends Annotation> annotation) {
+ if (instance == null) {
+ return null;
+ }
+ return getValueForField(instance, fieldName, instance.getClass(), annotation, true);
+ }
+
+ public Object getValueForField(Object instance, Class<? extends Annotation> annotation) {
+ if (instance == null) {
+ return null;
+ }
+ return getValueForField(instance, instance.getClass(), annotation, true);
+ }
+
+ private Object getValueForField(Object instance, Class<?> resultClass,
+ Class<? extends Annotation> annotation, boolean inherited) {
+ return getValueForField(instance, null, resultClass, annotation, inherited);
+ }
+
+ public Map<String, Object> getValueForAnnotatedFields(Object instance,
+ Class<? extends Annotation> annotation) {
+ return getValueForAnnotatedFields(instance, instance.getClass(), annotation, true);
+ }
+
+ private Map<String, Object> getValueForAnnotatedFields(Object instance, Class<?> resultClass,
+ Class<? extends Annotation> annotation, boolean inherited) {
+ if (instance == null) {
+ return null;
+ }
+
+ Field[] fields = resultClass.getDeclaredFields();
+ Map<String, Object> fieldName2Value = new HashMap<String, Object>();
+
+ for (Field field : fields) {
+ if (field.getAnnotation(annotation) != null) {
+ Object value = getFieldValue(instance, field);
+ final EdmProperty property = field.getAnnotation(EdmProperty.class);
+ final String name = property == null || property.name().isEmpty() ? field.getName() : property.name();
+ fieldName2Value.put(name, value);
+ }
+ }
+
+ Class<?> superClass = resultClass.getSuperclass();
+ if (inherited && superClass != Object.class) {
+ Map<String, Object> tmp = getValueForAnnotatedFields(instance, superClass, annotation, true);
+ fieldName2Value.putAll(tmp);
+ }
+
+ return fieldName2Value;
+ }
+
+ public void setValueForAnnotatedField(Object instance, Class<? extends Annotation> annotation, Object value)
+ throws ODataAnnotationException {
+ List<Field> fields = getAnnotatedFields(instance, annotation);
+
+ if(fields.isEmpty()) {
+ throw new ODataAnnotationException("No field found for annotation '" + annotation
+ + "' on instance '" + instance + "'.");
+ } else if(fields.size() > 1) {
+ throw new ODataAnnotationException("More then one field found for annotation '" + annotation
+ + "' on instance '" + instance + "'.");
+ }
+
+ setFieldValue(instance, fields.get(0), value);
+ }
+
+ public void setValuesToAnnotatedFields(Object instance,
+ Class<? extends Annotation> annotation, Map<String, Object> fieldName2Value) {
+ List<Field> fields = getAnnotatedFields(instance, annotation);
+
+ // XXX: refactore
+ for (Field field : fields) {
+ final String canonicalName = getCanonicalName(field);
+ if (fieldName2Value.containsKey(canonicalName)) {
+ Object value = fieldName2Value.get(canonicalName);
+ setFieldValue(instance, field, value);
+ }
+ }
+ }
+
+ public List<Field> getAnnotatedFields(Object instance, Class<? extends Annotation> annotation) {
+ if (instance == null) {
+ return null;
+ }
+ return getAnnotatedFields(instance.getClass(), annotation, true);
+ }
+
+ public List<Field> getAnnotatedFields(Class<?> fieldClass, Class<? extends Annotation> annotation) {
+ return getAnnotatedFields(fieldClass, annotation, true);
+ }
+
+ /**
+ *
+ * @param instance
+ * @param resultClass
+ * @param annotation
+ * @param inherited
+ * @return
+ */
+ private List<Field> getAnnotatedFields(Class<?> resultClass,
+ Class<? extends Annotation> annotation, boolean inherited) {
+ if (resultClass == null) {
+ return null;
+ }
+
+ Field[] fields = resultClass.getDeclaredFields();
+ List<Field> annotatedFields = new ArrayList<Field>();
+
+ for (Field field : fields) {
+ if (field.getAnnotation(annotation) != null) {
+ annotatedFields.add(field);
+ }
+ }
+
+ Class<?> superClass = resultClass.getSuperclass();
+ if (inherited && superClass != Object.class) {
+ List<Field> tmp = getAnnotatedFields(superClass, annotation, true);
+ annotatedFields.addAll(tmp);
+ }
+
+ return annotatedFields;
+ }
+
+ private Object getValueForField(Object instance, String fieldName, Class<?> resultClass,
+ Class<? extends Annotation> annotation, boolean inherited) {
+ if (instance == null) {
+ return null;
+ }
+
+ Field[] fields = resultClass.getDeclaredFields();
+ for (Field field : fields) {
+ if (field.getAnnotation(annotation) != null
+ && (fieldName == null || field.getName().equals(fieldName))) {
+ return getFieldValue(instance, field);
+ }
+ }
+
+ Class<?> superClass = resultClass.getSuperclass();
+ if (inherited && superClass != Object.class) {
+ return getValueForField(instance, fieldName, superClass, annotation, true);
+ }
+
+ return null;
+ }
+
+ private Object getFieldValue(Object instance, Field field) {
+ try {
+ boolean access = field.isAccessible();
+ field.setAccessible(true);
+ Object value = field.get(instance);
+ field.setAccessible(access);
+ return value;
+ } catch (IllegalArgumentException ex) { // should never happen
+ throw new ODataRuntimeException(ex);
+ } catch (IllegalAccessException ex) { // should never happen
+ throw new ODataRuntimeException(ex);
+ }
+ }
+
+ private void setFieldValue(Object instance, Field field, Object value) {
+ try {
+ Object usedValue = value;
+ if (value != null
+ && field.getType() != value.getClass()
+ && value.getClass() == String.class) {
+ usedValue = convert(field, (String) value);
+ }
+ boolean access = field.isAccessible();
+ field.setAccessible(true);
+ field.set(instance, usedValue);
+ field.setAccessible(access);
+ } catch (IllegalArgumentException ex) { // should never happen
+ throw new ODataRuntimeException(ex);
+ } catch (IllegalAccessException ex) { // should never happen
+ throw new ODataRuntimeException(ex);
+ }
+ }
+
+ public Object convert(Field field, String propertyValue) {
+ Class<?> fieldClass = field.getType();
+ try {
+ EdmProperty property = field.getAnnotation(EdmProperty.class);
+ EdmSimpleTypeKind type = mapTypeKind(property.type());
+ return type.getEdmSimpleTypeInstance().valueOfString(propertyValue,
+ EdmLiteralKind.DEFAULT, null, fieldClass);
+ } catch (EdmSimpleTypeException ex) {
+ throw new ODataRuntimeException("Conversion failed for string property with error: "
+ + ex.getMessage(), ex);
+ }
+ }
+
+ public boolean isEdmAnnotated(Object object) {
+ if (object == null) {
+ return false;
+ }
+ return isEdmAnnotated(object.getClass());
+ }
+
+ public boolean isEdmTypeAnnotated(Class<?> clazz) {
+ boolean isComplexEntity = clazz.getAnnotation(EdmComplexType.class) != null;
+ boolean isEntity = clazz.getAnnotation(EdmEntityType.class) != null;
+ return isComplexEntity || isEntity;
+ }
+
+ public boolean isEdmAnnotated(Class<?> clazz) {
+ if (clazz == null) {
+ return false;
+ } else {
+ final boolean isEntity = null != clazz.getAnnotation(EdmEntityType.class);
+ final boolean isEntitySet = null != clazz.getAnnotation(EdmEntitySet.class);
+ final boolean isComplexEntity = null != clazz.getAnnotation(EdmComplexType.class);
+ return isEntity || isComplexEntity || isEntitySet;
+ }
+ }
+
+ public String getCanonicalName(Field field) {
+ return firstCharToUpperCase(field.getName());
+ }
+
+ public String getCanonicalName(Class<?> clazz) {
+ return firstCharToUpperCase(clazz.getSimpleName());
+ }
+
+ private String firstCharToUpperCase(String content) {
+ if (content == null || content.isEmpty()) {
+ return content;
+ }
+ return content.substring(0, 1).toUpperCase(Locale.ENGLISH) + content.substring(1);
+ }
+
+ public EdmSimpleTypeKind mapTypeKind(org.apache.olingo.odata2.api.annotation.edm.EdmType type) {
+ switch (type) {
+ case BINARY: return EdmSimpleTypeKind.Binary;
+ case BOOLEAN: return EdmSimpleTypeKind.Boolean;
+ case BYTE: return EdmSimpleTypeKind.Byte;
+ case COMPLEX: return EdmSimpleTypeKind.Null;
+ case DATE_TIME: return EdmSimpleTypeKind.DateTime;
+ case DATE_TIME_OFFSET: return EdmSimpleTypeKind.DateTimeOffset;
+ case DECIMAL: return EdmSimpleTypeKind.Decimal;
+ case DOUBLE: return EdmSimpleTypeKind.Double;
+ case GUID: return EdmSimpleTypeKind.Guid;
+ case INT16: return EdmSimpleTypeKind.Int16;
+ case INT32: return EdmSimpleTypeKind.Int32;
+ case INT64: return EdmSimpleTypeKind.Int64;
+ case NULL: return EdmSimpleTypeKind.Null;
+ case SBYTE: return EdmSimpleTypeKind.SByte;
+ case SINGLE: return EdmSimpleTypeKind.Single;
+ case STRING: return EdmSimpleTypeKind.String;
+ case TIME: return EdmSimpleTypeKind.Time;
+ default: throw new ODataRuntimeException("Unknown type '" + type
+ + "' for mapping to EdmSimpleTypeKind.");
+ }
+ }
+
+ public EdmMultiplicity mapMultiplicity(Multiplicity multiplicity) {
+ switch (multiplicity) {
+ case ZERO_OR_ONE: return EdmMultiplicity.ZERO_TO_ONE;
+ case ONE: return EdmMultiplicity.ONE;
+ case MANY: return EdmMultiplicity.MANY;
+ default: throw new ODataRuntimeException("Unknown type '" + multiplicity + "' for mapping to EdmMultiplicity.");
+ }
+ }
+
+ /**
+ *
+ */
+ private static class EdmAnnotationException extends RuntimeException {
+
+ private static final long serialVersionUID = 42L;
+
+ public EdmAnnotationException(String message) {
+ super(message);
+ }
+ }
+
+ public String getCanonicalNamespace(Class<?> aClass) {
+ return generateNamespace(aClass);
+ }
+
+ public String extractContainerName(Class<?> aClass) {
+ EdmEntitySet entitySet = aClass.getAnnotation(EdmEntitySet.class);
+ if(entitySet != null) {
+ String containerName = entitySet.container();
+ if(!containerName.isEmpty()) {
+ return containerName;
+ }
+ }
+ return DEFAULT_CONTAINER_NAME;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/39485c57/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/util/ClassHelper.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/util/ClassHelper.java b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/util/ClassHelper.java
new file mode 100644
index 0000000..5e9fcdb
--- /dev/null
+++ b/odata2-annotation-processor/annotation-processor-core/src/main/java/org/apache/olingo/odata2/core/annotation/util/ClassHelper.java
@@ -0,0 +1,105 @@
+/*******************************************************************************
+ * 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.core.annotation.util;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.io.FilenameFilter;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ *
+ */
+public class ClassHelper {
+
+ private static final File[] EMPTY_FILE_ARRAY = new File[0];
+
+ private static final FilenameFilter CLASSFILE_FILTER = new FilenameFilter() {
+ @Override
+ public boolean accept(File dir, String name) {
+ return name.endsWith(CLASSFILE_ENDING);
+ }
+ public static final String CLASSFILE_ENDING = ".class";
+ };
+
+ private static final FileFilter FOLDER_FILTER = new FileFilter() {
+ @Override
+ public boolean accept(File pathname) {
+ return pathname.isDirectory();
+ }
+ };
+
+ public static final List<Class<?>> loadClasses(String packageToScan, ClassValidator cv) {
+ return loadClasses(packageToScan, CLASSFILE_FILTER, cv);
+ }
+
+
+ public static final List<Class<?>> loadClasses(String packageToScan, FilenameFilter ff, ClassValidator cv) {
+ final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+ String folderToScan = packageToScan.replace(".", "/");
+ URL url = classLoader.getResource(folderToScan);
+ if(url == null) {
+ throw new IllegalArgumentException("No folder to scan found for package '" + packageToScan + "'.");
+ }
+ File folder = new File(url.getFile());
+ File[] classFiles = folder.listFiles(ff);
+ if(classFiles == null) {
+ classFiles = EMPTY_FILE_ARRAY;
+ }
+
+ List<Class<?>> annotatedClasses = new ArrayList<Class<?>>(classFiles.length);
+ for (File file : classFiles) {
+ String name = file.getName();
+ String fqn = packageToScan + "." + name.substring(0, name.length() - 6);
+ try {
+ Class<?> c = classLoader.loadClass(fqn);
+ if (cv.isClassValid(c)) {
+ annotatedClasses.add(c);
+ }
+ } catch (ClassNotFoundException ex) {
+ throw new IllegalArgumentException("Exception during class loading of class '" + fqn +
+ "' with message '" + ex.getMessage() + "'.");
+ }
+ }
+
+ // recursive search
+ File[] subfolders = listSubFolder(folder);
+ for (File file : subfolders) {
+ List<Class<?>> subFolderClazzes = loadClasses(packageToScan + "." + file.getName(), ff, cv);
+ annotatedClasses.addAll(subFolderClazzes);
+ }
+ //
+
+ return annotatedClasses;
+ }
+
+ private static File[] listSubFolder(File folder) {
+ File[] subfolders = folder.listFiles(FOLDER_FILTER);
+ if(subfolders == null) {
+ return EMPTY_FILE_ARRAY;
+ }
+ return subfolders;
+ }
+
+ public interface ClassValidator {
+ boolean isClassValid(Class<?> c);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/39485c57/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/data/AnnotationsInMemoryDsTest.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/data/AnnotationsInMemoryDsTest.java b/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/data/AnnotationsInMemoryDsTest.java
new file mode 100644
index 0000000..04dbefc
--- /dev/null
+++ b/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/data/AnnotationsInMemoryDsTest.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright 2013 The Apache Software Foundation.
+ *
+ * Licensed 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.core.annotation.data;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.olingo.odata2.api.edm.EdmEntitySet;
+import org.apache.olingo.odata2.api.edm.EdmEntityType;
+import org.apache.olingo.odata2.api.edm.FullQualifiedName;
+import org.apache.olingo.odata2.api.edm.provider.EntitySet;
+import org.apache.olingo.odata2.api.exception.ODataException;
+import org.apache.olingo.odata2.core.annotation.edm.AnnotationEdmProvider;
+import org.apache.olingo.odata2.core.annotation.model.Building;
+import org.apache.olingo.odata2.core.annotation.model.ModelSharedConstants;
+import org.apache.olingo.odata2.core.annotation.model.Photo;
+import org.apache.olingo.odata2.core.annotation.util.AnnotationHelper;
+import org.junit.Assert;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+/**
+ *
+ */
+public class AnnotationsInMemoryDsTest {
+
+ private final AnnotationInMemoryDs datasource;
+ private AnnotationEdmProvider edmProvider;
+ private static final String DEFAULT_CONTAINER = ModelSharedConstants.CONTAINER_1;
+
+ public AnnotationsInMemoryDsTest() {
+ datasource = new AnnotationInMemoryDs(Building.class.getPackage().getName(), false);
+ edmProvider = new AnnotationEdmProvider(Building.class.getPackage().getName());
+ }
+
+ @Test
+ public void createSimpleEntity() throws Exception {
+ EdmEntitySet edmEntitySet = createMockedEdmEntitySet("Buildings");
+
+ Building building = new Building();
+ building.setName("Common Building");
+ datasource.createData(edmEntitySet, building);
+
+ Map<String, Object> keys = new HashMap<String, Object>();
+ keys.put("Id", "1");
+
+ Building read = (Building) datasource.readData(edmEntitySet, keys);
+ Assert.assertEquals("Common Building", read.getName());
+ Assert.assertEquals("1", read.getId());
+ }
+
+
+ @Test
+ public void createSimpleEntityWithOwnKey() throws Exception {
+ EdmEntitySet edmEntitySet = createMockedEdmEntitySet("Buildings");
+
+ Building building = new Building();
+ building.setName("Common Building");
+ AnnotationHelper ah = new AnnotationHelper();
+ ah.setValueForProperty(building, "Id", "42");
+ datasource.createData(edmEntitySet, building);
+
+ Map<String, Object> keys = new HashMap<String, Object>();
+ keys.put("Id", "42");
+
+ Building read = (Building) datasource.readData(edmEntitySet, keys);
+ Assert.assertEquals("Common Building", read.getName());
+ Assert.assertEquals("42", read.getId());
+ }
+
+ @Test
+ public void createSimpleEntityWithDuplicateKey() throws Exception {
+ EdmEntitySet edmEntitySet = createMockedEdmEntitySet("Buildings");
+ AnnotationHelper ah = new AnnotationHelper();
+
+ Building building = new Building();
+ building.setName("Common Building");
+ ah.setValueForProperty(building, "Id", "42");
+ datasource.createData(edmEntitySet, building);
+ //
+ Building buildingDuplicate = new Building();
+ buildingDuplicate.setName("Duplicate Building");
+ ah.setValueForProperty(buildingDuplicate, "Id", "42");
+ datasource.createData(edmEntitySet, buildingDuplicate);
+
+ Map<String, Object> keys42 = new HashMap<String, Object>();
+ keys42.put("Id", "42");
+ Building read42 = (Building) datasource.readData(edmEntitySet, keys42);
+ Assert.assertEquals("Common Building", read42.getName());
+ Assert.assertEquals("42", read42.getId());
+
+ Map<String, Object> keys = new HashMap<String, Object>();
+ keys.put("Id", "1");
+ Building read = (Building) datasource.readData(edmEntitySet, keys);
+ Assert.assertEquals("Duplicate Building", read.getName());
+ Assert.assertEquals("1", read.getId());
+}
+
+
+ @Test
+ public void createEntityTwoKeys() throws Exception {
+ EdmEntitySet edmEntitySet = createMockedEdmEntitySet("Photos");
+
+ Photo photo = new Photo();
+ photo.setName("BigPicture");
+ photo.setType("PNG");
+ photo.setImageUri("https://localhost/image.png");
+ photo.setImageType("image/png");
+ datasource.createData(edmEntitySet, photo);
+
+ Map<String, Object> keys = new HashMap<String, Object>();
+ keys.put("ImageFormat", "PNG");
+ keys.put("Name", "BigPicture");
+
+ Photo read = (Photo) datasource.readData(edmEntitySet, keys);
+ Assert.assertEquals("BigPicture", read.getName());
+ Assert.assertEquals("PNG", read.getType());
+ Assert.assertEquals("image/png", read.getImageType());
+ Assert.assertEquals("https://localhost/image.png", read.getImageUri());
+ }
+
+ @Test
+ // @Ignore("Rethink update method")
+ public void createAndUpdateEntityTwoKeys() throws Exception {
+ EdmEntitySet edmEntitySet = createMockedEdmEntitySet("Photos");
+
+ Photo photo = new Photo();
+ final String nameKeyValue = "BigPicture";
+ final String typeKeyValue = "PNG";
+ photo.setName(nameKeyValue);
+ photo.setType(typeKeyValue);
+ photo.setImageUri("https://localhost/image.png");
+ photo.setImageType("image/png");
+ datasource.createData(edmEntitySet, photo);
+
+ Map<String, Object> keys = new HashMap<String, Object>();
+ keys.put("Name", "BigPicture");
+ keys.put("ImageFormat", "PNG");
+
+ Photo read = (Photo) datasource.readData(edmEntitySet, keys);
+ Assert.assertEquals("BigPicture", read.getName());
+ Assert.assertEquals("PNG", read.getType());
+ Assert.assertEquals("image/png", read.getImageType());
+ Assert.assertEquals("https://localhost/image.png", read.getImageUri());
+
+ // update
+ Photo updatedPhoto = new Photo();
+ updatedPhoto.setName(nameKeyValue);
+ updatedPhoto.setType(typeKeyValue);
+ updatedPhoto.setImageUri("https://localhost/image.jpg");
+ updatedPhoto.setImageType("image/jpg");
+ datasource.updateData(edmEntitySet, updatedPhoto);
+
+ Map<String, Object> updatedKeys = new HashMap<String, Object>();
+ updatedKeys.put("Name", nameKeyValue);
+ updatedKeys.put("ImageFormat", typeKeyValue);
+
+ Photo readUpdated = (Photo) datasource.readData(edmEntitySet, updatedKeys);
+ Assert.assertEquals("BigPicture", readUpdated.getName());
+ Assert.assertEquals("PNG", readUpdated.getType());
+ Assert.assertEquals("image/jpg", readUpdated.getImageType());
+ Assert.assertEquals("https://localhost/image.jpg", readUpdated.getImageUri());
+ }
+
+ private EdmEntitySet createMockedEdmEntitySet(String entitySetName) throws ODataException {
+ EntitySet entitySet = edmProvider.getEntitySet(DEFAULT_CONTAINER, entitySetName);
+ FullQualifiedName entityType = entitySet.getEntityType();
+
+ EdmEntitySet edmEntitySet = Mockito.mock(EdmEntitySet.class);
+ Mockito.when(edmEntitySet.getName()).thenReturn(entitySetName);
+ EdmEntityType edmEntityType = Mockito.mock(EdmEntityType.class);
+ Mockito.when(edmEntitySet.getEntityType()).thenReturn(edmEntityType);
+ Mockito.when(edmEntityType.getName()).thenReturn(entityType.getName());
+
+ return edmEntitySet;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/39485c57/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/edm/AnnotationEdmProviderTest.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/edm/AnnotationEdmProviderTest.java b/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/edm/AnnotationEdmProviderTest.java
new file mode 100644
index 0000000..494a090
--- /dev/null
+++ b/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/edm/AnnotationEdmProviderTest.java
@@ -0,0 +1,463 @@
+/*
+ * Copyright 2013 The Apache Software Foundation.
+ *
+ * Licensed 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.core.annotation.edm;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.olingo.odata2.api.annotation.edm.EdmComplexType;
+import org.apache.olingo.odata2.api.annotation.edm.EdmEntitySet;
+import org.apache.olingo.odata2.api.annotation.edm.EdmEntityType;
+import org.apache.olingo.odata2.api.edm.EdmMultiplicity;
+import org.apache.olingo.odata2.api.edm.FullQualifiedName;
+import org.apache.olingo.odata2.api.edm.provider.Association;
+import org.apache.olingo.odata2.api.edm.provider.AssociationEnd;
+import org.apache.olingo.odata2.api.edm.provider.AssociationSet;
+import org.apache.olingo.odata2.api.edm.provider.ComplexType;
+import org.apache.olingo.odata2.api.edm.provider.EntityContainer;
+import org.apache.olingo.odata2.api.edm.provider.EntityContainerInfo;
+import org.apache.olingo.odata2.api.edm.provider.EntitySet;
+import org.apache.olingo.odata2.api.edm.provider.EntityType;
+import org.apache.olingo.odata2.api.edm.provider.FunctionImport;
+import org.apache.olingo.odata2.api.edm.provider.Key;
+import org.apache.olingo.odata2.api.edm.provider.NavigationProperty;
+import org.apache.olingo.odata2.api.edm.provider.Property;
+import org.apache.olingo.odata2.api.edm.provider.PropertyRef;
+import org.apache.olingo.odata2.api.edm.provider.Schema;
+import org.apache.olingo.odata2.api.exception.ODataException;
+import org.apache.olingo.odata2.core.annotation.model.Building;
+import org.apache.olingo.odata2.core.annotation.model.City;
+import org.apache.olingo.odata2.core.annotation.model.Employee;
+import org.apache.olingo.odata2.core.annotation.model.Location;
+import org.apache.olingo.odata2.core.annotation.model.Manager;
+import org.apache.olingo.odata2.core.annotation.model.ModelSharedConstants;
+import org.apache.olingo.odata2.core.annotation.model.Photo;
+import org.apache.olingo.odata2.core.annotation.model.RefBase;
+import org.apache.olingo.odata2.core.annotation.model.Room;
+import org.apache.olingo.odata2.core.annotation.model.Team;
+import org.junit.Test;
+
+/**
+ *
+ */
+public class AnnotationEdmProviderTest {
+
+ @EdmEntityType
+ @EdmEntitySet
+ private static final class GeneratedNamesTestClass {}
+
+ @EdmComplexType
+ private static final class GeneratedNamesComplexTestClass {}
+
+ @EdmEntityType(namespace="MyTestNamespace")
+ @EdmEntitySet(container="MyTestContainer")
+ private static final class DefinedNamesTestClass {}
+
+ private final AnnotationEdmProvider aep;
+ private final Collection<Class<?>> annotatedClasses = new ArrayList<Class<?>>();
+
+ public AnnotationEdmProviderTest() {
+ annotatedClasses.add(RefBase.class);
+ annotatedClasses.add(Building.class);
+ annotatedClasses.add(City.class);
+ annotatedClasses.add(Employee.class);
+ annotatedClasses.add(Location.class);
+ annotatedClasses.add(Manager.class);
+ annotatedClasses.add(Photo.class);
+ annotatedClasses.add(Room.class);
+ annotatedClasses.add(Team.class);
+
+ aep = new AnnotationEdmProvider(annotatedClasses);
+ }
+
+ @Test
+ public void defaultNamespaceGeneration() throws ODataException {
+ Collection<Class<?>> localAnnotatedClasses = new ArrayList<Class<?>>();
+ localAnnotatedClasses.add(GeneratedNamesTestClass.class);
+ AnnotationEdmProvider localAep = new AnnotationEdmProvider(localAnnotatedClasses);
+ // validate
+ EntityType testType = localAep.getEntityType(new FullQualifiedName(
+ GeneratedNamesTestClass.class.getPackage().getName(),
+ GeneratedNamesTestClass.class.getSimpleName()));
+ assertNotNull("Requested entity not found.", testType);
+ assertEquals("GeneratedNamesTestClass", testType.getName());
+ assertNull("This should not have a base type", testType.getBaseType());
+ }
+
+ @Test
+ public void defaultNamespaceGenerationComplexType() throws ODataException {
+ Collection<Class<?>> localAnnotatedClasses = new ArrayList<Class<?>>();
+ localAnnotatedClasses.add(GeneratedNamesComplexTestClass.class);
+ AnnotationEdmProvider localAep = new AnnotationEdmProvider(localAnnotatedClasses);
+ // validate
+ ComplexType testType = localAep.getComplexType(new FullQualifiedName(
+ GeneratedNamesComplexTestClass.class.getPackage().getName(),
+ GeneratedNamesComplexTestClass.class.getSimpleName()));
+ assertNotNull("Requested entity not found.", testType);
+ assertEquals("GeneratedNamesComplexTestClass", testType.getName());
+ assertNull("This should not have a base type", testType.getBaseType());
+ }
+
+ @Test
+ public void defaultContainerNameGeneration() throws ODataException {
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ AnnotationEdmProvider localAep =
+ new AnnotationEdmProvider((Collection) Arrays.asList(GeneratedNamesTestClass.class));
+
+ EntityContainerInfo containerInfo = localAep.getEntityContainerInfo(null);
+ assertNotNull(containerInfo);
+ assertEquals("DefaultContainer", containerInfo.getName());
+ }
+
+
+ @Test
+ public void defaultNamespaceDefined() throws ODataException {
+ Collection<Class<?>> localAnnotatedClasses = new ArrayList<Class<?>>();
+ localAnnotatedClasses.add(DefinedNamesTestClass.class);
+ AnnotationEdmProvider localAep = new AnnotationEdmProvider(localAnnotatedClasses);
+ // validate
+ EntityType testClass = localAep.getEntityType(new FullQualifiedName("MyTestNamespace",
+ DefinedNamesTestClass.class.getSimpleName()));
+ assertNotNull("Requested entity not found.", testClass);
+ assertEquals("DefinedNamesTestClass", testClass.getName());
+ assertNull("This should not have a base type", testClass.getBaseType());
+ }
+
+ @Test
+ public void defaultContainerNameDefined() throws ODataException {
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ AnnotationEdmProvider localAep = new AnnotationEdmProvider((Collection) Arrays.asList(DefinedNamesTestClass.class));
+
+ EntityContainerInfo containerInfo = localAep.getEntityContainerInfo(null);
+ assertNotNull(containerInfo);
+ assertEquals("MyTestContainer", containerInfo.getName());
+ }
+
+ @Test
+ public void loadAnnotatedClassesFromPackage() throws Exception {
+ AnnotationEdmProvider localAep = new AnnotationEdmProvider("org.apache.olingo.odata2.core.annotation.model");
+
+ // validate employee
+ EntityType employee = localAep.getEntityType(new FullQualifiedName(ModelSharedConstants.NAMESPACE_1, "Employee"));
+ assertEquals("Employee", employee.getName());
+ final List<PropertyRef> employeeKeys = employee.getKey().getKeys();
+ assertEquals(1, employeeKeys.size());
+ assertEquals("EmployeeId", employeeKeys.get(0).getName());
+ assertEquals(6, employee.getProperties().size());
+ assertEquals(3, employee.getNavigationProperties().size());
+
+ List<Schema> schemas = localAep.getSchemas();
+ assertEquals(1, schemas.size());
+ EntityContainerInfo info = localAep.getEntityContainerInfo(ModelSharedConstants.CONTAINER_1);
+ assertTrue(info.isDefaultEntityContainer());
+ }
+
+ @Test
+ public void annotationProviderBasic() throws Exception {
+ assertNotNull(aep);
+
+ List<Schema> schemas = aep.getSchemas();
+ assertEquals(1, schemas.size());
+ EntityContainerInfo info = aep.getEntityContainerInfo(ModelSharedConstants.CONTAINER_1);
+ assertTrue(info.isDefaultEntityContainer());
+
+ FunctionImport funImp = aep.getFunctionImport(ModelSharedConstants.CONTAINER_1, "NoImport");
+ assertNull(funImp);
+
+ final FullQualifiedName associationFqn = new FullQualifiedName(
+ ModelSharedConstants.NAMESPACE_1, "NoAssociation");
+ Association noAssociation = aep.getAssociation(associationFqn);
+ assertNull(noAssociation);
+
+ AssociationSet noAssociationSet = aep.getAssociationSet(
+ ModelSharedConstants.CONTAINER_1, associationFqn, "NoSrc", "NoSrcEntity");
+ assertNull(noAssociationSet);
+
+ AssociationSet asBuildingRooms = aep.getAssociationSet(
+ ModelSharedConstants.CONTAINER_1, defaultFqn("BuildingRooms"), "Buildings", "r_Building");
+ assertNotNull(asBuildingRooms);
+ assertEquals("Buildings", asBuildingRooms.getEnd1().getEntitySet());
+ assertEquals("r_Building", asBuildingRooms.getEnd1().getRole());
+ assertEquals("Rooms", asBuildingRooms.getEnd2().getEntitySet());
+ assertEquals("r_Room", asBuildingRooms.getEnd2().getRole());
+ }
+
+ @Test
+ public void annotationProviderGetDefaultContainer() throws Exception {
+ assertNotNull(aep);
+
+ List<Schema> schemas = aep.getSchemas();
+ assertEquals(1, schemas.size());
+ EntityContainerInfo info = aep.getEntityContainerInfo(null);
+ assertTrue(info.isDefaultEntityContainer());
+ assertEquals(ModelSharedConstants.CONTAINER_1, info.getName());
+ }
+
+ @Test
+ public void schemaBasic() throws Exception {
+ assertNotNull(aep);
+
+ List<Schema> schemas = aep.getSchemas();
+ assertEquals(1, schemas.size());
+
+ Schema schema = schemas.get(0);
+ List<EntityContainer> containers = schema.getEntityContainers();
+ assertEquals(1, containers.size());
+ EntityContainer container = containers.get(0);
+ assertEquals(ModelSharedConstants.CONTAINER_1, container.getName());
+ final List<EntitySet> entitySets = container.getEntitySets();
+ assertEquals(6, entitySets.size());
+
+ List<Association> associations = schema.getAssociations();
+ assertEquals(4, associations.size());
+ for (Association association : associations) {
+ assertNotNull(association.getName());
+ validateAssociation(association);
+ }
+ }
+
+ private FullQualifiedName defaultFqn(String name) {
+ return new FullQualifiedName(ModelSharedConstants.NAMESPACE_1, name);
+ }
+
+ private void validateAssociation(Association association) {
+ String name = association.getName();
+ if(name.equals("r_Employee-r_Room")) {
+ validateAssociation(association,
+ "r_Room", EdmMultiplicity.ONE, defaultFqn("Room"),
+ "r_Employee", EdmMultiplicity.MANY, defaultFqn("Employee"));
+ } else if(name.equals("BuildingRooms")) {
+ validateAssociation(association,
+ "r_Building", EdmMultiplicity.ONE, defaultFqn("Building"),
+ "r_Room", EdmMultiplicity.MANY, defaultFqn("Room"));
+ } else if(name.equals("ManagerEmployees")) {
+ validateAssociation(association,
+ "r_Manager", EdmMultiplicity.ONE, defaultFqn("Manager"),
+ "r_Employee", EdmMultiplicity.MANY, defaultFqn("Employee"));
+ } else if(name.equals("TeamEmployees")) {
+ validateAssociation(association,
+ "r_Team", EdmMultiplicity.ONE, defaultFqn("Team"),
+ "r_Employee", EdmMultiplicity.MANY, defaultFqn("Employee"));
+ } else {
+ fail("Got unknown association to validate with name '" + name + "'.");
+ }
+ }
+
+ private void validateAssociation(Association association,
+ String fromRole, EdmMultiplicity fromMulti, FullQualifiedName fromType,
+ String toRole, EdmMultiplicity toMulti, FullQualifiedName toType) {
+
+ AssociationEnd[] ends = new AssociationEnd[]{association.getEnd1(),association.getEnd2()};
+ for (AssociationEnd associationEnd : ends) {
+ if(associationEnd.getRole().equals(fromRole)) {
+ validateAssociationEnd(associationEnd, fromRole, fromMulti, fromType);
+ } else if(associationEnd.getRole().equals(toRole)) {
+ validateAssociationEnd(associationEnd, toRole, toMulti, toType);
+ } else {
+ fail("Unexpected navigation end '" + associationEnd.getRole()
+ + "' for association with name '" + association.getName() + "'.");
+ }
+ }
+ }
+
+ private void validateAssociationEnd(AssociationEnd associationEnd,
+ String role, EdmMultiplicity multiplicity, FullQualifiedName type) {
+ assertEquals(role, associationEnd.getRole());
+ assertEquals(multiplicity, associationEnd.getMultiplicity());
+ assertEquals(type, associationEnd.getType());
+ }
+
+
+ @Test
+ public void entitySetTeams() throws Exception {
+ // validate teams
+ EntitySet teams = aep.getEntitySet(ModelSharedConstants.CONTAINER_1, "Teams");
+ assertEquals(ModelSharedConstants.NAMESPACE_1, teams.getEntityType().getNamespace());
+ assertEquals("Team", teams.getEntityType().getName());
+ }
+
+ @Test
+ public void entityTypeEmployee() throws Exception {
+ // validate employee
+ EntityType employee = aep.getEntityType(new FullQualifiedName(ModelSharedConstants.NAMESPACE_1, "Employee"));
+ assertEquals("Employee", employee.getName());
+ final List<PropertyRef> employeeKeys = employee.getKey().getKeys();
+ assertEquals(1, employeeKeys.size());
+ assertEquals("EmployeeId", employeeKeys.get(0).getName());
+ assertEquals(6, employee.getProperties().size());
+ assertEquals(3, employee.getNavigationProperties().size());
+
+ for (NavigationProperty navigationProperty : employee.getNavigationProperties()) {
+ if (navigationProperty.getName().equals("ne_Manager")) {
+ validateNavProperty(navigationProperty, "ManagerEmployees", "r_Employee", "r_Manager");
+ } else if (navigationProperty.getName().equals("ne_Team")) {
+ validateNavProperty(navigationProperty, "TeamEmployees", "r_Employee", "r_Team");
+ } else if (navigationProperty.getName().equals("ne_Room")) {
+ validateNavProperty(navigationProperty, "r_Employee-r_Room", "r_Employee", "r_Room");
+ } else {
+ fail("Got unexpected navigation property with name '" + navigationProperty.getName() + "'.");
+ }
+ }
+}
+
+ @Test
+ public void entityTypeTeam() throws Exception {
+ // validate team
+ EntityType team = aep.getEntityType(new FullQualifiedName(ModelSharedConstants.NAMESPACE_1, "Team"));
+ assertEquals("Team", team.getName());
+ assertEquals("Base", team.getBaseType().getName());
+ 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");
+ }
+
+ @Test
+ public void entityTypePhotoWithTwoKeyProperties() throws Exception {
+ // validate team
+ EntityType photo = aep.getEntityType(new FullQualifiedName(ModelSharedConstants.NAMESPACE_1, "Photo"));
+ assertEquals("Photo", photo.getName());
+ final List<Property> properties = photo.getProperties();
+ assertEquals(5, properties.size());
+ assertTrue(containsProperty(properties, "Name"));
+ assertTrue(containsProperty(properties, "ImageFormat"));
+ assertTrue(containsProperty(properties, "MimeType"));
+ assertTrue(containsProperty(properties, "ImageUrl"));
+ assertTrue(containsProperty(properties, "Image"));
+ assertFalse(photo.isAbstract());
+ assertTrue(photo.isHasStream());
+
+ Key photoKey = photo.getKey();
+ List<PropertyRef> keyReferences = photoKey.getKeys();
+ assertEquals(2, keyReferences.size());
+ PropertyRef name = getPropertyRef(keyReferences, "Name");
+ assertEquals("Name", name.getName());
+ PropertyRef imageFormat = getPropertyRef(keyReferences, "ImageFormat");
+ assertEquals("ImageFormat", imageFormat.getName());
+
+// assertEquals(0, photo.getNavigationProperties().size());
+ assertNull(photo.getNavigationProperties());
+ }
+
+ @Test
+ public void entityTypeAbstractBaseType() throws Exception {
+ // validate employee
+ EntityType baseType = aep.getEntityType(new FullQualifiedName(ModelSharedConstants.NAMESPACE_1, "Base"));
+ assertEquals("Base", baseType.getName());
+ final List<PropertyRef> keys = baseType.getKey().getKeys();
+ assertEquals(1, keys.size());
+ assertEquals("Id", keys.get(0).getName());
+ assertEquals(2, baseType.getProperties().size());
+ assertTrue(baseType.isAbstract());
+
+ // validate base for team
+ EntityType team = aep.getEntityType(new FullQualifiedName(ModelSharedConstants.NAMESPACE_1, "Team"));
+ assertEquals("Team", team.getName());
+ assertEquals("Base", team.getBaseType().getName());
+ assertEquals(ModelSharedConstants.NAMESPACE_1, team.getBaseType().getNamespace());
+ }
+
+ @Test
+ public void complexTypeLocation() throws Exception {
+ // validate employee
+ EntityType employee = aep.getEntityType(new FullQualifiedName(ModelSharedConstants.NAMESPACE_1, "Employee"));
+ final List<Property> properties = employee.getProperties();
+ Property location = null;
+ for (Property property : properties) {
+ if (property.getName().equals("Location")) {
+ location = property;
+ }
+ }
+ assertNotNull(location);
+ assertEquals("Location", location.getName());
+
+ // validate location complex type
+ ComplexType locationType = aep.getComplexType(
+ new FullQualifiedName(ModelSharedConstants.NAMESPACE_1, "c_Location"));
+ assertEquals("c_Location", locationType.getName());
+ assertEquals(2, locationType.getProperties().size());
+ }
+
+ @Test
+ public void entityTypeRoomWithNavigation() throws Exception {
+ // validate employee
+ EntityType room = aep.getEntityType(new FullQualifiedName(ModelSharedConstants.NAMESPACE_1, "Room"));
+ assertEquals("Room", room.getName());
+ assertEquals("Base", room.getBaseType().getName());
+ assertEquals(2, room.getProperties().size());
+ final List<NavigationProperty> navigationProperties = room.getNavigationProperties();
+ assertEquals(2, navigationProperties.size());
+
+ for (NavigationProperty navigationProperty : navigationProperties) {
+ if(navigationProperty.getName().equals("nr_Employees")) {
+ validateNavProperty(navigationProperty, "r_Employee-r_Room", "r_Room", "r_Employee");
+ } else if(navigationProperty.getName().equals("nr_Building")) {
+ validateNavProperty(navigationProperty, "BuildingRooms", "r_Room", "r_Building");
+ } else {
+ fail("Got unexpected navigation property with name '" + navigationProperty.getName() + "'.");
+ }
+ }
+ }
+
+ private void validateNavProperty(NavigationProperty navigationProperty, String name,
+ String relationship, String fromRole, String toRole) {
+ if(name != null) {
+ assertEquals(name, navigationProperty.getName());
+ }
+ FullQualifiedName fqn = new FullQualifiedName(ModelSharedConstants.NAMESPACE_1, relationship);
+ assertEquals("Wrong relationship for navigation property.", fqn, navigationProperty.getRelationship());
+ assertEquals("Wrong fromRole for navigation property.", fromRole, navigationProperty.getFromRole());
+ assertEquals("Wrong toRole for navigation property.", toRole, navigationProperty.getToRole());
+ }
+
+ private void validateNavProperty(NavigationProperty navigationProperty,
+ String relationship, String fromRole, String toRole) {
+ validateNavProperty(navigationProperty, null, relationship, fromRole, toRole);
+ }
+
+ private boolean containsProperty(List<Property> properties, String propertyName) {
+ return getProperty(properties, propertyName) != null;
+ }
+
+ private Property getProperty(List<Property> properties, String name) {
+ for (Property property : properties) {
+ if(name.equals(property.getName())) {
+ return property;
+ }
+ }
+ return null;
+ }
+
+ private PropertyRef getPropertyRef(List<PropertyRef> properties, String name) {
+ for (PropertyRef property : properties) {
+ if(name.equals(property.getName())) {
+ return property;
+ }
+ }
+ return null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/39485c57/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/model/Building.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/model/Building.java b/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/model/Building.java
new file mode 100644
index 0000000..737b5e2
--- /dev/null
+++ b/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/model/Building.java
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * 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.core.annotation.model;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.olingo.odata2.api.annotation.edm.EdmEntitySet;
+import org.apache.olingo.odata2.api.annotation.edm.EdmEntityType;
+import org.apache.olingo.odata2.api.annotation.edm.EdmKey;
+import org.apache.olingo.odata2.api.annotation.edm.EdmNavigationProperty;
+import org.apache.olingo.odata2.api.annotation.edm.EdmNavigationProperty.Multiplicity;
+import org.apache.olingo.odata2.api.annotation.edm.EdmProperty;
+import org.apache.olingo.odata2.api.annotation.edm.EdmType;
+
+/**
+ *
+ */
+@EdmEntityType(name = "Building", namespace = ModelSharedConstants.NAMESPACE_1)
+@EdmEntitySet(name = "Buildings")
+public class Building {
+ @EdmKey
+ @EdmProperty(type = EdmType.INT32)
+ private String id;
+ @EdmProperty
+ private String name;
+ @EdmProperty(name = "Image", type = EdmType.BINARY)
+ private byte[] image;
+ @EdmNavigationProperty(name = "nb_Rooms", toType = Room.class,
+ association = "BuildingRooms", toMultiplicity = Multiplicity.MANY)
+ private List<Room> rooms = new ArrayList<Room>();
+
+ public Building() {}
+
+ public String getId() {
+ return id;
+ }
+
+ public void setName(final String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setImage(final byte[] byteArray) {
+ image = byteArray;
+ }
+
+ public byte[] getImage() {
+ if (image == null) {
+ return null;
+ } else {
+ return image.clone();
+ }
+ }
+
+ public List<Room> getRooms() {
+ return rooms;
+ }
+
+ @Override
+ public int hashCode() {
+ return id == null ? 0 : id.hashCode();
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ return this == obj
+ || obj != null && getClass() == obj.getClass() && id == ((Building) obj).id;
+ }
+
+ @Override
+ public String toString() {
+ return "{\"Id\":\"" + id + "\",\"Name\":\"" + name + "\",\"Image\":\"" + Arrays.toString(image) + "\"}";
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/39485c57/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/model/City.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/model/City.java b/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/model/City.java
new file mode 100644
index 0000000..7b866a3
--- /dev/null
+++ b/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/model/City.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * 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.core.annotation.model;
+
+import org.apache.olingo.odata2.api.annotation.edm.EdmComplexType;
+import org.apache.olingo.odata2.api.annotation.edm.EdmProperty;
+
+
+/**
+ *
+ */
+@EdmComplexType(name="c_City", namespace = ModelSharedConstants.NAMESPACE_1)
+public class City {
+
+ @EdmProperty
+ private String postalCode;
+ @EdmProperty
+ private String cityName;
+
+ public City(final String postalCode, final String name) {
+ this.postalCode = postalCode;
+ cityName = name;
+ }
+
+ public void setPostalCode(final String postalCode) {
+ this.postalCode = postalCode;
+ }
+
+ public String getPostalCode() {
+ return postalCode;
+ }
+
+ public void setCityName(final String cityName) {
+ this.cityName = cityName;
+ }
+
+ public String getCityName() {
+ return cityName;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s, %s", cityName, postalCode);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/39485c57/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/model/Employee.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/model/Employee.java b/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/model/Employee.java
new file mode 100644
index 0000000..63b8a76
--- /dev/null
+++ b/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/model/Employee.java
@@ -0,0 +1,187 @@
+/*******************************************************************************
+ * 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.core.annotation.model;
+
+import java.text.DateFormat;
+import java.util.Calendar;
+
+import org.apache.olingo.odata2.api.annotation.edm.EdmEntitySet;
+import org.apache.olingo.odata2.api.annotation.edm.EdmEntityType;
+import org.apache.olingo.odata2.api.annotation.edm.EdmKey;
+import org.apache.olingo.odata2.api.annotation.edm.EdmMediaResourceContent;
+import org.apache.olingo.odata2.api.annotation.edm.EdmMediaResourceMimeType;
+import org.apache.olingo.odata2.api.annotation.edm.EdmNavigationProperty;
+import org.apache.olingo.odata2.api.annotation.edm.EdmProperty;
+import org.apache.olingo.odata2.api.annotation.edm.EdmType;
+
+/**
+ *
+ */
+@EdmEntityType(name = "Employee", namespace = ModelSharedConstants.NAMESPACE_1)
+@EdmEntitySet(name = "Employees")
+public class Employee {
+ @EdmKey
+ @EdmProperty(name = "EmployeeId", type = EdmType.STRING)
+ private String employeeId;
+ @EdmProperty(name = "EmployeeName")
+ private String employeeName;
+ @EdmProperty
+ private int age;
+ @EdmNavigationProperty(name = "ne_Manager", association = "ManagerEmployees")
+ private Manager manager;
+ @EdmNavigationProperty(name = "ne_Team", association = "TeamEmployees")
+ private Team team;
+ @EdmNavigationProperty(name = "ne_Room")
+ private Room room;
+ @EdmMediaResourceMimeType
+ private String imageType;
+ @EdmMediaResourceContent
+ private byte[] image;
+ @EdmProperty(name = "ImageUrl")
+ private String imageUrl;
+ @EdmProperty(name = "EntryDate", type = EdmType.DATE_TIME)
+ private Calendar entryDate;
+ @EdmProperty(name = "Location")
+ private Location location;
+
+ public Employee(final String employeeId, final String name) {
+ this.employeeId = employeeId;
+ setEmployeeName(name);
+ }
+
+ public String getId() {
+ return employeeId;
+ }
+
+ public void setEmployeeName(final String employeeName) {
+ this.employeeName = employeeName;
+ }
+
+ public String getEmployeeName() {
+ return employeeName;
+ }
+
+ public void setAge(final int age) {
+ this.age = age;
+ }
+
+ public int getAge() {
+ return age;
+ }
+
+ public void setManager(final Manager manager) {
+ this.manager = manager;
+ }
+
+ public Manager getManager() {
+ return manager;
+ }
+
+ public void setTeam(final Team team) {
+ this.team = team;
+ }
+
+ public Team getTeam() {
+ return team;
+ }
+
+ public void setRoom(final Room room) {
+ this.room = room;
+ }
+
+ public Room getRoom() {
+ return room;
+ }
+
+ public void setImageUri(final String imageUri) {
+ imageUrl = imageUri;
+ }
+
+ public String getImageUri() {
+ return imageUrl;
+ }
+
+ public void setLocation(final Location location) {
+ this.location = location;
+ }
+
+ public Location getLocation() {
+ return location;
+ }
+
+ public void setEntryDate(final Calendar date) {
+ entryDate = date;
+ }
+
+ public Calendar getEntryDate() {
+ return entryDate;
+ }
+
+ public void setImageType(final String imageType) {
+ this.imageType = imageType;
+ }
+
+ public String getImageType() {
+ return imageType;
+ }
+
+ public void setImage(final byte[] image) {
+ this.image = image;
+ }
+
+ public byte[] getImage() {
+ if (image == null) {
+ return null;
+ }
+ return image.clone();
+ }
+
+ @Override
+ public int hashCode() {
+ if (employeeId == null) {
+ return 0;
+ }
+ return employeeId.hashCode();
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ return this == obj
+ || obj != null && getClass() == obj.getClass() && employeeId == ((Employee) obj).employeeId;
+ }
+
+ @Override
+ public String toString() {
+ return "{\"EmployeeId\":\"" + employeeId + "\","
+ + "\"EmployeeName\":\"" + employeeName + "\","
+ + "\"ManagerId\":" + (manager == null ? "null" : "\"" + manager.getId() + "\"") + ","
+ + "\"RoomId\":" + (room == null ? "null" : "\"" + room.getId() + "\"") + ","
+ + "\"TeamId\":" + (team == null ? "null" : "\"" + team.getId() + "\"") + ","
+ + "\"Location\":"
+ + (location == null ? "null" :
+ "{\"City\":" + (location.getCity() == null ? "null" :
+ "{\"PostalCode\":\"" + location.getCity().getPostalCode() + "\","
+ + "\"CityName\":\"" + location.getCity().getCityName() + "\"}") + ","
+ + "\"Country\":\"" + location.getCountry() + "\"}") + ","
+ + "\"Age\":" + age + ","
+ + "\"EntryDate\":"
+ + (entryDate == null ? "null" : "\"" + DateFormat.getInstance().format(entryDate.getTime()) + "\"") + ","
+ + "\"ImageUrl\":\"" + imageUrl + "\"}";
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/39485c57/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/model/Location.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/model/Location.java b/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/model/Location.java
new file mode 100644
index 0000000..7f3f082
--- /dev/null
+++ b/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/model/Location.java
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * 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.core.annotation.model;
+
+import org.apache.olingo.odata2.api.annotation.edm.EdmComplexType;
+import org.apache.olingo.odata2.api.annotation.edm.EdmProperty;
+
+
+/**
+ *
+ */
+@EdmComplexType(name = "c_Location", namespace = ModelSharedConstants.NAMESPACE_1)
+public class Location {
+ @EdmProperty
+ private String country;
+ @EdmProperty
+ private City city;
+
+ public Location(final String country, final String postalCode, final String cityName) {
+ this.country = country;
+ city = new City(postalCode, cityName);
+ }
+
+ public void setCountry(final String country) {
+ this.country = country;
+ }
+
+ public String getCountry() {
+ return country;
+ }
+
+ public void setCity(final City city) {
+ this.city = city;
+ }
+
+ public City getCity() {
+ return city;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s, %s", country, city.toString());
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/39485c57/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/model/Manager.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/model/Manager.java b/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/model/Manager.java
new file mode 100644
index 0000000..e3edbd0
--- /dev/null
+++ b/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/model/Manager.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * 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.core.annotation.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.olingo.odata2.api.annotation.edm.EdmEntitySet;
+import org.apache.olingo.odata2.api.annotation.edm.EdmEntityType;
+import org.apache.olingo.odata2.api.annotation.edm.EdmNavigationProperty;
+import org.apache.olingo.odata2.api.annotation.edm.EdmNavigationProperty.Multiplicity;
+
+/**
+ *
+ */
+@EdmEntityType(name = "Manager", namespace = ModelSharedConstants.NAMESPACE_1)
+@EdmEntitySet(name = "Managers")
+public class Manager extends Employee {
+
+ @EdmNavigationProperty(name = "nm_Employees", association = "ManagerEmployees",
+ toMultiplicity = Multiplicity.MANY)
+ private List<Employee> employees = new ArrayList<Employee>();
+
+ public Manager(final String id, final String name) {
+ super(id, name);
+ }
+
+ public List<Employee> getEmployees() {
+ return employees;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/39485c57/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/model/ModelSharedConstants.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/model/ModelSharedConstants.java b/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/model/ModelSharedConstants.java
new file mode 100644
index 0000000..1d44498
--- /dev/null
+++ b/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/model/ModelSharedConstants.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * 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.core.annotation.model;
+
+public interface ModelSharedConstants {
+
+ String NAMESPACE_1 = "RefScenario";
+ String CONTAINER_1 = "DefaultContainer";
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/39485c57/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/model/Photo.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/model/Photo.java b/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/model/Photo.java
new file mode 100644
index 0000000..520216a
--- /dev/null
+++ b/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/model/Photo.java
@@ -0,0 +1,128 @@
+/*******************************************************************************
+ * 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.core.annotation.model;
+
+import java.util.Arrays;
+
+import org.apache.olingo.odata2.api.annotation.edm.EdmEntitySet;
+import org.apache.olingo.odata2.api.annotation.edm.EdmEntityType;
+import org.apache.olingo.odata2.api.annotation.edm.EdmKey;
+import org.apache.olingo.odata2.api.annotation.edm.EdmMediaResourceContent;
+import org.apache.olingo.odata2.api.annotation.edm.EdmMediaResourceMimeType;
+import org.apache.olingo.odata2.api.annotation.edm.EdmMediaResourceSource;
+import org.apache.olingo.odata2.api.annotation.edm.EdmProperty;
+import org.apache.olingo.odata2.api.annotation.edm.EdmType;
+
+/**
+ *
+ */
+@EdmEntityType(name = "Photo", namespace = ModelSharedConstants.NAMESPACE_1)
+@EdmEntitySet(name = "Photos")
+public class Photo {
+ @EdmProperty
+ @EdmKey
+ private String name;
+ @EdmProperty(name = "ImageFormat")
+ @EdmKey
+ private String type;
+ @EdmProperty
+ @EdmMediaResourceMimeType
+ private String mimeType;
+ @EdmProperty
+ @EdmMediaResourceSource
+ private String imageUrl = "http://localhost/someResource.png";
+ @EdmProperty(type = EdmType.BINARY)
+ @EdmMediaResourceContent
+ private byte[] image = ResourceHelper.generateImage();
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(final String name) {
+ this.name = name;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(final String type) {
+ this.type = type;
+ }
+
+ public String getImageUri() {
+ return imageUrl;
+ }
+
+ public void setImageUri(final String uri) {
+ imageUrl = uri;
+ }
+
+ public byte[] getImage() {
+ return image.clone();
+ }
+
+ public void setImage(final byte[] image) {
+ this.image = image;
+ }
+
+ public String getImageType() {
+ return mimeType;
+ }
+
+ public void setImageType(final String imageType) {
+ this.mimeType = imageType;
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 5;
+ hash = 83 * hash + (this.name != null ? this.name.hashCode() : 0);
+ hash = 83 * hash + (this.type != null ? this.type.hashCode() : 0);
+ return hash;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final Photo other = (Photo) obj;
+ if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
+ return false;
+ }
+ if ((this.type == null) ? (other.type != null) : !this.type.equals(other.type)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "{\"Name\":\"" + name + "\","
+ + "\"Type\":\"" + type + "\","
+ + "\"ImageUrl\":\"" + imageUrl + "\","
+ + "\"Image\":\"" + Arrays.toString(image) + "\","
+ + "\"MimeType\":\"" + mimeType + "\"";
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/39485c57/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/model/RefBase.java
----------------------------------------------------------------------
diff --git a/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/model/RefBase.java b/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/model/RefBase.java
new file mode 100644
index 0000000..6f3002f
--- /dev/null
+++ b/odata2-annotation-processor/annotation-processor-core/src/test/java/org/apache/olingo/odata2/core/annotation/model/RefBase.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2013 The Apache Software Foundation.
+ *
+ * Licensed 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.core.annotation.model;
+
+import org.apache.olingo.odata2.api.annotation.edm.EdmEntityType;
+import org.apache.olingo.odata2.api.annotation.edm.EdmKey;
+import org.apache.olingo.odata2.api.annotation.edm.EdmProperty;
+import org.apache.olingo.odata2.api.annotation.edm.EdmType;
+
+/**
+ *
+ */
+@EdmEntityType(name="Base", namespace=ModelSharedConstants.NAMESPACE_1)
+public abstract class RefBase {
+ @EdmProperty(name="Name")
+ protected String name;
+ @EdmProperty(name="Id", type = EdmType.STRING)
+ @EdmKey
+ protected int id;
+
+ public RefBase(int id, String name) {
+ this.name = name;
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getId() {
+ return Integer.toString(id);
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+}