You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by fm...@apache.org on 2014/07/19 18:21:11 UTC

git commit: [OLINGO-366] provides complex lazy loading

Repository: olingo-odata4
Updated Branches:
  refs/heads/master f22cbfda9 -> dfe68e67f


[OLINGO-366] provides complex lazy loading


Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/dfe68e67
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/dfe68e67
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/dfe68e67

Branch: refs/heads/master
Commit: dfe68e67f2b490a8641d26d013c2c05a559567e7
Parents: f22cbfd
Author: fmartelli <fa...@gmail.com>
Authored: Sat Jul 19 18:20:53 2014 +0200
Committer: fmartelli <fa...@gmail.com>
Committed: Sat Jul 19 18:20:53 2014 +0200

----------------------------------------------------------------------
 .../commons/AbstractInvocationHandler.java      |  3 +-
 .../AbstractStructuredInvocationHandler.java    | 14 +++
 .../commons/AnnotatableInvocationHandler.java   |  3 +-
 .../ComplexFactoryInvocationHandler.java        | 92 -------------------
 .../proxy/commons/ComplexInvocationHandler.java | 97 ++++++++++++--------
 .../EntityCollectionInvocationHandler.java      |  2 +-
 .../EntityContainerInvocationHandler.java       |  7 --
 .../proxy/commons/EntityInvocationHandler.java  | 69 ++++++++------
 .../olingo/ext/proxy/utils/CoreUtils.java       | 18 ++--
 .../fit/proxy/v4/APIBasicDesignTestITCase.java  | 45 ++++++++-
 .../fit/proxy/v4/DerivedTypeTestITCase.java     |  1 -
 11 files changed, 166 insertions(+), 185 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/dfe68e67/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractInvocationHandler.java
----------------------------------------------------------------------
diff --git a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractInvocationHandler.java b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractInvocationHandler.java
index 67b3d58..e26be36 100644
--- a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractInvocationHandler.java
+++ b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractInvocationHandler.java
@@ -247,8 +247,7 @@ abstract class AbstractInvocationHandler implements InvocationHandler {
       final CommonODataProperty property = (CommonODataProperty) result;
       return property == null || property.hasNullValue()
               ? null
-              : CoreUtils.getObjectFromODataValue(
-              getClient(), property.getValue(), method.getGenericReturnType(), null);
+              : CoreUtils.getObjectFromODataValue(property.getValue(), method.getGenericReturnType(), service);
     }
   }
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/dfe68e67/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractStructuredInvocationHandler.java
----------------------------------------------------------------------
diff --git a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractStructuredInvocationHandler.java b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractStructuredInvocationHandler.java
index 1e88bfe..2e95e29 100644
--- a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractStructuredInvocationHandler.java
+++ b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractStructuredInvocationHandler.java
@@ -60,6 +60,8 @@ public abstract class AbstractStructuredInvocationHandler extends AbstractInvoca
 
   protected CommonURIBuilder<?> uri;
 
+  protected URI baseURI;
+
   protected final Class<?> typeRef;
 
   protected EntityInvocationHandler entityHandler;
@@ -330,6 +332,18 @@ public abstract class AbstractStructuredInvocationHandler extends AbstractInvoca
     navPropAnnotatableHandlers.put(navPropName, handler);
   }
 
+  public void expand(final String... expand) {
+    this.uri.expand(expand);
+  }
+
+  public void select(final String... select) {
+    this.uri.select(select);
+  }
+
+  public void clearQueryOptions() {
+    this.uri = getClient().newURIBuilder(baseURI.toASCIIString());
+  }
+
   protected abstract void load();
 
   protected abstract void setPropertyValue(final Property property, final Object value);

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/dfe68e67/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AnnotatableInvocationHandler.java
----------------------------------------------------------------------
diff --git a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AnnotatableInvocationHandler.java b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AnnotatableInvocationHandler.java
index a1ab4b2..836abe1 100644
--- a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AnnotatableInvocationHandler.java
+++ b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AnnotatableInvocationHandler.java
@@ -158,8 +158,7 @@ public class AnnotatableInvocationHandler extends AbstractInvocationHandler impl
         }
         res = annotation == null || annotation.hasNullValue()
                 ? null
-                : CoreUtils.getObjectFromODataValue(
-                getClient(), annotation.getValue(), null, targetHandler.getEntityHandler());
+                : CoreUtils.getObjectFromODataValue(annotation.getValue(), null, targetHandler.service);
         if (res != null) {
           annotations.put(term, res);
         }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/dfe68e67/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/ComplexFactoryInvocationHandler.java
----------------------------------------------------------------------
diff --git a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/ComplexFactoryInvocationHandler.java b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/ComplexFactoryInvocationHandler.java
deleted file mode 100644
index 6359459..0000000
--- a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/ComplexFactoryInvocationHandler.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * 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.ext.proxy.commons;
-
-import org.apache.olingo.ext.proxy.api.OperationExecutor;
-import org.apache.olingo.ext.proxy.api.annotations.Property;
-import org.apache.olingo.ext.proxy.utils.ClassUtils;
-
-import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
-import org.apache.olingo.ext.proxy.Service;
-
-class ComplexFactoryInvocationHandler extends AbstractInvocationHandler implements OperationExecutor {
-
-  private static final long serialVersionUID = 2629912294765040027L;
-
-  private final EntityInvocationHandler entityHandler;
-
-  private final AbstractStructuredInvocationHandler invokerHandler;
-
-  static ComplexFactoryInvocationHandler getInstance(
-          final Service<?> service,
-          final EntityInvocationHandler entityHandler,
-          final AbstractStructuredInvocationHandler targetHandler) {
-
-    return new ComplexFactoryInvocationHandler(service, entityHandler, targetHandler);
-  }
-
-  static ComplexFactoryInvocationHandler getInstance(
-          final EntityInvocationHandler entityHandler,
-          final AbstractStructuredInvocationHandler targetHandler) {
-
-    return new ComplexFactoryInvocationHandler(
-            targetHandler == null
-            ? entityHandler == null
-            ? null
-            : entityHandler.service
-            : targetHandler.service,
-            entityHandler,
-            targetHandler);
-  }
-
-  private ComplexFactoryInvocationHandler(
-          final Service<?> service,
-          final EntityInvocationHandler entityHandler,
-          final AbstractStructuredInvocationHandler targetHandler) {
-
-    super(service);
-    this.invokerHandler = targetHandler;
-    this.entityHandler = entityHandler;
-  }
-
-  @Override
-  public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
-    if (isSelfMethod(method, args)) {
-      return invokeSelfMethod(method, args);
-    } else if (method.getName().startsWith("new")) {
-      final Method getter = proxy.getClass().getInterfaces()[0].getMethod(method.getName());
-      final Property property = ClassUtils.getAnnotation(Property.class, getter);
-      if (property == null) {
-        throw new UnsupportedOperationException("Unsupported method " + method.getName());
-      }
-
-      return Proxy.newProxyInstance(
-              Thread.currentThread().getContextClassLoader(),
-              new Class<?>[] {method.getReturnType()},
-              entityHandler == null
-              ? ComplexInvocationHandler.getInstance(
-              getClient(), property.name(), method.getReturnType(), service)
-              : ComplexInvocationHandler.getInstance(
-              getClient(), property.name(), method.getReturnType(), entityHandler));
-    } else {
-      throw new NoSuchMethodException(method.getName());
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/dfe68e67/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/ComplexInvocationHandler.java
----------------------------------------------------------------------
diff --git a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/ComplexInvocationHandler.java b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/ComplexInvocationHandler.java
index ba3108e..c2781c7 100644
--- a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/ComplexInvocationHandler.java
+++ b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/ComplexInvocationHandler.java
@@ -20,7 +20,6 @@ package org.apache.olingo.ext.proxy.commons;
 
 import org.apache.commons.lang3.tuple.ImmutablePair;
 import org.apache.commons.lang3.tuple.Pair;
-import org.apache.olingo.client.api.CommonEdmEnabledODataClient;
 import org.apache.olingo.commons.api.domain.CommonODataProperty;
 import org.apache.olingo.commons.api.domain.ODataComplexValue;
 import org.apache.olingo.commons.api.domain.ODataLinked;
@@ -42,11 +41,14 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.Set;
+import org.apache.olingo.client.api.communication.request.retrieve.ODataPropertyRequest;
+import org.apache.olingo.client.api.communication.response.ODataRetrieveResponse;
+import org.apache.olingo.client.api.uri.CommonURIBuilder;
 
 public class ComplexInvocationHandler extends AbstractStructuredInvocationHandler {
 
   private static Pair<ODataComplexValue<? extends CommonODataProperty>, Class<?>> init(
-          final CommonEdmEnabledODataClient<?> client,
+          final Service<?> service,
           final Class<?> reference) {
 
     final Class<?> complexTypeRef;
@@ -65,76 +67,78 @@ public class ComplexInvocationHandler extends AbstractStructuredInvocationHandle
             new FullQualifiedName(ClassUtils.getNamespace(complexTypeRef), annotation.name());
 
     final ODataComplexValue<? extends CommonODataProperty> complex =
-            client.getObjectFactory().newComplexValue(typeName.toString());
+            service.getClient().getObjectFactory().newComplexValue(typeName.toString());
 
     return new ImmutablePair<ODataComplexValue<? extends CommonODataProperty>, Class<?>>(complex, complexTypeRef);
   }
 
   public static ComplexInvocationHandler getInstance(
-          final CommonEdmEnabledODataClient<?> client,
           final String propertyName,
           final Class<?> reference,
           final EntityInvocationHandler handler) {
 
-    final Pair<ODataComplexValue<? extends CommonODataProperty>, Class<?>> init = init(client, reference);
-    return new ComplexInvocationHandler(client, init.getLeft(), init.getRight(), handler);
+    final Pair<ODataComplexValue<? extends CommonODataProperty>, Class<?>> init = init(handler.service, reference);
+    return new ComplexInvocationHandler(init.getLeft(), init.getRight(), handler);
   }
 
   public static ComplexInvocationHandler getInstance(
-          final CommonEdmEnabledODataClient<?> client,
-          final String propertyName,
+          final ODataComplexValue<?> complex,
           final Class<?> reference,
           final Service<?> service) {
 
-    final Pair<ODataComplexValue<? extends CommonODataProperty>, Class<?>> init = init(client, reference);
-    return new ComplexInvocationHandler(client, init.getLeft(), init.getRight(), service);
+    return new ComplexInvocationHandler(complex, reference, service);
   }
 
   public static ComplexInvocationHandler getInstance(
-          final CommonEdmEnabledODataClient<?> client,
-          final ODataComplexValue<?> complex,
           final Class<?> typeRef,
-          final EntityInvocationHandler handler) {
-
-    return new ComplexInvocationHandler(client, complex, typeRef, handler);
+          final Service<?> service) {
+    final Pair<ODataComplexValue<? extends CommonODataProperty>, Class<?>> init = init(service, typeRef);
+    return new ComplexInvocationHandler(init.getLeft(), init.getRight(), service);
   }
-  private final CommonEdmEnabledODataClient<?> client;
 
-  private ComplexInvocationHandler(
-          final CommonEdmEnabledODataClient<?> client,
-          final ODataComplexValue<?> complex,
-          final Class<?> typeRef,
-          final EntityInvocationHandler handler) {
+  public static ComplexInvocationHandler getInstance(
+          final Class<?> reference,
+          final Service<?> service,
+          final CommonURIBuilder<?> uri) {
+    final Pair<ODataComplexValue<? extends CommonODataProperty>, Class<?>> init = init(service, reference);
+    return new ComplexInvocationHandler(init.getLeft(), init.getRight(), service, uri);
+  }
 
-    super(typeRef, complex, handler);
-    this.client = client;
+  public static ComplexInvocationHandler getInstance(
+          final ODataComplexValue<? extends CommonODataProperty> complex,
+          final Class<?> reference,
+          final Service<?> service,
+          final CommonURIBuilder<?> uri) {
+    return new ComplexInvocationHandler(complex, reference, service, uri);
   }
 
   private ComplexInvocationHandler(
-          final CommonEdmEnabledODataClient<?> client,
-          final ODataComplexValue<?> complex,
+          final ODataComplexValue<? extends CommonODataProperty> complex,
           final Class<?> typeRef,
-          final Service<?> service) {
+          final Service<?> service,
+          final CommonURIBuilder<?> uri) {
 
     super(typeRef, complex, service);
-    this.client = client;
+    this.uri = uri;
+    this.baseURI = this.uri.build();
   }
 
-  public static ComplexInvocationHandler getInstance(
+  private ComplexInvocationHandler(
+          final ODataComplexValue<? extends CommonODataProperty> complex,
           final Class<?> typeRef,
-          final Service<?> service) {
-    final Pair<ODataComplexValue<? extends CommonODataProperty>, Class<?>> init = init(service.getClient(), typeRef);
-    return new ComplexInvocationHandler(init.getLeft(), init.getRight(), service);
+          final EntityInvocationHandler handler) {
+
+    super(typeRef, complex, handler);
+    this.uri = null;
   }
 
   private ComplexInvocationHandler(
-          final ODataComplexValue<?> complex,
+          final ODataComplexValue<? extends CommonODataProperty> complex,
           final Class<?> typeRef,
           final Service<?> service) {
 
-    super(typeRef, service);
-    this.internal = complex;
-    this.client = service.getClient();
+    super(typeRef, complex, service);
+    this.uri = null;
   }
 
   @SuppressWarnings("unchecked")
@@ -148,7 +152,7 @@ public class ComplexInvocationHandler extends AbstractStructuredInvocationHandle
       final CommonODataProperty property = getComplex().get(name);
       return property == null || property.hasNullValue()
               ? null
-              : CoreUtils.getObjectFromODataValue(client, property.getValue(), type, getEntityHandler());
+              : CoreUtils.getObjectFromODataValue(property.getValue(), type, service);
     } catch (Exception e) {
       throw new IllegalArgumentException("Error getting value for property '" + name + "'", e);
     }
@@ -180,9 +184,9 @@ public class ComplexInvocationHandler extends AbstractStructuredInvocationHandle
     final FullQualifiedName fqn =
             new FullQualifiedName(ClassUtils.getNamespace(typeRef), typeRef.getAnnotation(ComplexType.class).name());
 
-    final EdmElement edmProperty = client.getCachedEdm().getComplexType(fqn).getProperty(property.name());
+    final EdmElement edmProperty = getClient().getCachedEdm().getComplexType(fqn).getProperty(property.name());
 
-    final EdmTypeInfo type = new EdmTypeInfo.Builder().setEdm(client.getCachedEdm()).setTypeExpression(
+    final EdmTypeInfo type = new EdmTypeInfo.Builder().setEdm(getClient().getCachedEdm()).setTypeExpression(
             edmProperty.isCollection() ? "Collection(" + property.type() + ")" : property.type()).build();
 
     setPropertyValue(property.name(), type, value);
@@ -199,7 +203,7 @@ public class ComplexInvocationHandler extends AbstractStructuredInvocationHandle
       toBeAdded = value;
     }
 
-    client.getBinder().add(getComplex(), CoreUtils.getODataProperty(client, name, type, toBeAdded));
+    getClient().getBinder().add(getComplex(), CoreUtils.getODataProperty(getClient(), name, type, toBeAdded));
 
     if (getEntityHandler() != null && !getContext().entityContext().isAttached(getEntityHandler())) {
       getContext().entityContext().attach(getEntityHandler(), AttachedEntityStatus.CHANGED);
@@ -242,5 +246,20 @@ public class ComplexInvocationHandler extends AbstractStructuredInvocationHandle
 
   @Override
   protected void load() {
+    try {
+      if (this.uri != null) {
+        final ODataPropertyRequest<CommonODataProperty> req =
+                getClient().getRetrieveRequestFactory().getPropertyRequest(uri.build());
+
+        final ODataRetrieveResponse<CommonODataProperty> res = req.execute();
+        this.internal = res.getBody().getValue();
+      }
+    } catch (IllegalArgumentException e) {
+      LOG.warn("Complex at '" + uri + "' not found", e);
+      throw e;
+    } catch (Exception e) {
+      LOG.warn("Error retrieving complex '" + uri + "'", e);
+      throw new IllegalArgumentException("Error retrieving " + typeRef.getSimpleName(), e);
+    }
   }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/dfe68e67/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/EntityCollectionInvocationHandler.java
----------------------------------------------------------------------
diff --git a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/EntityCollectionInvocationHandler.java b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/EntityCollectionInvocationHandler.java
index fe8cfa8..7b74b33 100644
--- a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/EntityCollectionInvocationHandler.java
+++ b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/EntityCollectionInvocationHandler.java
@@ -231,7 +231,7 @@ public class EntityCollectionInvocationHandler<T extends StructuredType>
         }
         res = annotation == null || annotation.hasNullValue()
                 ? null
-                : CoreUtils.getObjectFromODataValue(getClient(), annotation.getValue(), null, null);
+                : CoreUtils.getObjectFromODataValue(annotation.getValue(), null, service);
         if (res != null) {
           annotationsByTerm.put(term, res);
         }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/dfe68e67/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/EntityContainerInvocationHandler.java
----------------------------------------------------------------------
diff --git a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/EntityContainerInvocationHandler.java b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/EntityContainerInvocationHandler.java
index 68a8801..3a15f17 100644
--- a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/EntityContainerInvocationHandler.java
+++ b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/EntityContainerInvocationHandler.java
@@ -86,13 +86,6 @@ public final class EntityContainerInvocationHandler extends AbstractInvocationHa
               Thread.currentThread().getContextClassLoader(),
               new Class<?>[] {returnType},
               OperationInvocationHandler.getInstance(this));
-    } else if ("complexFactory".equals(method.getName()) && ArrayUtils.isEmpty(args)) {
-      final Class<?> returnType = method.getReturnType();
-
-      return Proxy.newProxyInstance(
-              Thread.currentThread().getContextClassLoader(),
-              new Class<?>[] {returnType},
-              ComplexFactoryInvocationHandler.getInstance(service, null, null));
     } else {
       final Class<?> returnType = method.getReturnType();
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/dfe68e67/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/EntityInvocationHandler.java
----------------------------------------------------------------------
diff --git a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/EntityInvocationHandler.java b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/EntityInvocationHandler.java
index 11b8b61..fdcb862 100644
--- a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/EntityInvocationHandler.java
+++ b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/EntityInvocationHandler.java
@@ -51,7 +51,6 @@ import java.io.InputStream;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Method;
-import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Proxy;
 import java.lang.reflect.Type;
 import java.net.URI;
@@ -63,18 +62,18 @@ import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeSet;
+import org.apache.olingo.ext.proxy.api.annotations.ComplexType;
+import org.apache.olingo.ext.proxy.utils.ClassUtils;
 
 public class EntityInvocationHandler extends AbstractStructuredInvocationHandler implements Annotatable {
 
   private static final long serialVersionUID = 2629912294765040037L;
 
-  private URI baseURI;
-
   protected final Map<String, Object> propertyChanges = new HashMap<String, Object>();
 
   protected final Map<NavigationProperty, Object> linkChanges = new HashMap<NavigationProperty, Object>();
 
-  protected final Map<NavigationProperty, Object> linkChache = new HashMap<NavigationProperty, Object>();
+  protected final Map<NavigationProperty, Object> linkCache = new HashMap<NavigationProperty, Object>();
 
   protected int propertiesTag = 0;
 
@@ -235,7 +234,7 @@ public class EntityInvocationHandler extends AbstractStructuredInvocationHandler
     this.streamedPropertyChanges.clear();
     this.propertyChanges.clear();
     this.linkChanges.clear();
-    this.linkChache.clear();
+    this.linkCache.clear();
     this.propertiesTag = 0;
     this.linksTag = 0;
     this.annotations.clear();
@@ -313,7 +312,9 @@ public class EntityInvocationHandler extends AbstractStructuredInvocationHandler
   @Override
   protected Object getPropertyValue(final String name, final Type type) {
     try {
-      if (!(type instanceof ParameterizedType) && (Class<?>) type == InputStream.class) {
+      Class<?> ref = ClassUtils.getTypeClass(type);
+
+      if (ref == InputStream.class) {
         return getStreamedProperty(name);
       } else {
         final CommonODataProperty property = getEntity().getProperty(name);
@@ -321,13 +322,37 @@ public class EntityInvocationHandler extends AbstractStructuredInvocationHandler
         Object res;
         if (propertyChanges.containsKey(name)) {
           res = propertyChanges.get(name);
+        } else if (ref != null && ClassUtils.getTypeClass(type).isAnnotationPresent(ComplexType.class)) {
+
+          final ComplexInvocationHandler complexHandler;
+          if (property == null || property.hasNullValue()) {
+            complexHandler = ComplexInvocationHandler.getInstance(
+                    ref,
+                    service,
+                    getClient().newURIBuilder(baseURI.toASCIIString()).appendPropertySegment(name));
+          } else {
+            ref = CoreUtils.getComplexTypeRef(property.getValue()); // handle derived types
+            complexHandler = ComplexInvocationHandler.getInstance(
+                    property.getValue().asComplex(),
+                    ref,
+                    service,
+                    getClient().newURIBuilder(baseURI.toASCIIString()).appendPropertySegment(name));
+          }
+
+          complexHandler.setEntityHandler(this);
+
+          res = Proxy.newProxyInstance(
+                  Thread.currentThread().getContextClassLoader(),
+                  new Class<?>[] {ref}, complexHandler);
+
+          addPropertyChanges(name, res);
         } else {
           res = property == null || property.hasNullValue()
                   ? null
-                  : CoreUtils.getObjectFromODataValue(getClient(), property.getValue(), type, this);
+                  : CoreUtils.getObjectFromODataValue(property.getValue(), type, service);
 
           if (res != null) {
-            cacheProperty(name, res);
+            addPropertyChanges(name, res);
           }
         }
 
@@ -367,7 +392,7 @@ public class EntityInvocationHandler extends AbstractStructuredInvocationHandler
     if (EdmPrimitiveTypeKind.Stream.getFullQualifiedName().toString().equalsIgnoreCase(property.type())) {
       setStreamedProperty(property, (InputStream) value);
     } else {
-      propertyChanges.put(property.name(), value);
+      addPropertyChanges(property.name(), value);
 
       if (value != null) {
         Collection<?> coll;
@@ -468,8 +493,8 @@ public class EntityInvocationHandler extends AbstractStructuredInvocationHandler
 
     if (linkChanges.containsKey(property)) {
       navPropValue = linkChanges.get(property);
-    } else if (linkChache.containsKey(property)) {
-      navPropValue = linkChache.get(property);
+    } else if (linkCache.containsKey(property)) {
+      navPropValue = linkCache.get(property);
     } else {
       navPropValue = retrieveNavigationProperty(property, getter);
     }
@@ -487,7 +512,7 @@ public class EntityInvocationHandler extends AbstractStructuredInvocationHandler
     attach(AttachedEntityStatus.CHANGED);
   }
 
-  protected void cacheProperty(final String name, final Object value) {
+  protected void addPropertyChanges(final String name, final Object value) {
     final int checkpoint = propertyChanges.hashCode();
     propertyChanges.put(name, value);
     updatePropertiesTag(checkpoint);
@@ -499,13 +524,13 @@ public class EntityInvocationHandler extends AbstractStructuredInvocationHandler
     linkChanges.put(navProp, value);
     updateLinksTag(checkpoint);
 
-    if (linkChache.containsKey(navProp)) {
-      linkChache.remove(navProp);
+    if (linkCache.containsKey(navProp)) {
+      linkCache.remove(navProp);
     }
   }
 
   protected void cacheLink(final NavigationProperty navProp, final Object value) {
-    linkChache.put(navProp, value);
+    linkCache.put(navProp, value);
   }
 
   @Override
@@ -558,7 +583,7 @@ public class EntityInvocationHandler extends AbstractStructuredInvocationHandler
         }
         res = annotation == null || annotation.hasNullValue()
                 ? null
-                : CoreUtils.getObjectFromODataValue(getClient(), annotation.getValue(), null, this);
+                : CoreUtils.getObjectFromODataValue(annotation.getValue(), null, service);
         if (res != null) {
           annotations.put(term, res);
         }
@@ -640,18 +665,6 @@ public class EntityInvocationHandler extends AbstractStructuredInvocationHandler
     return map;
   }
 
-  public void expand(final String... expand) {
-    this.uri.expand(expand);
-  }
-
-  public void select(final String... select) {
-    this.uri.select(select);
-  }
-
-  public void clearQueryOptions() {
-    this.uri = getClient().newURIBuilder(baseURI.toASCIIString());
-  }
-
   @Override
   public String toString() {
     return uuid.toString();

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/dfe68e67/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/utils/CoreUtils.java
----------------------------------------------------------------------
diff --git a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/utils/CoreUtils.java b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/utils/CoreUtils.java
index c9effa9..30ecea0 100644
--- a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/utils/CoreUtils.java
+++ b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/utils/CoreUtils.java
@@ -73,6 +73,7 @@ import java.util.Map;
 import org.apache.olingo.client.api.uri.CommonURIBuilder;
 import org.apache.olingo.commons.api.edm.Edm;
 import org.apache.olingo.commons.api.edm.EdmEntityContainer;
+import org.apache.olingo.ext.proxy.Service;
 import org.apache.olingo.ext.proxy.api.annotations.NavigationProperty;
 
 public final class CoreUtils {
@@ -459,8 +460,7 @@ public final class CoreUtils {
               final Object complex = Proxy.newProxyInstance(
                       Thread.currentThread().getContextClassLoader(),
                       new Class<?>[] {getter.getReturnType()},
-                      ComplexInvocationHandler.getInstance(
-                      client, property.getName(), getter.getReturnType(), typeHandler));
+                      ComplexInvocationHandler.getInstance(property.getName(), getter.getReturnType(), typeHandler));
 
               populate(client, typeHandler, complex, Property.class, property.getValue().asComplex().iterator());
               setPropertyValue(bean, getter, complex);
@@ -484,8 +484,7 @@ public final class CoreUtils {
                   final Object collItem = Proxy.newProxyInstance(
                           Thread.currentThread().getContextClassLoader(),
                           new Class<?>[] {collItemClass},
-                          ComplexInvocationHandler.getInstance(
-                          client, property.getName(), collItemClass, typeHandler));
+                          ComplexInvocationHandler.getInstance(property.getName(), collItemClass, typeHandler));
 
                   populate(client, typeHandler, collItem, Property.class, value.asComplex().iterator());
                   collection.add(collItem);
@@ -501,10 +500,9 @@ public final class CoreUtils {
   }
 
   public static Object getObjectFromODataValue(
-          final CommonEdmEnabledODataClient<?> client,
           final ODataValue value,
           final Type typeRef,
-          final EntityInvocationHandler entityHandler)
+          final Service<?> service)
           throws InstantiationException, IllegalAccessException {
 
     Class<?> internalRef;
@@ -528,8 +526,7 @@ public final class CoreUtils {
       res = Proxy.newProxyInstance(
               Thread.currentThread().getContextClassLoader(),
               new Class<?>[] {internalRef},
-              ComplexInvocationHandler.getInstance(
-              client, value.asComplex(), internalRef, entityHandler));
+              ComplexInvocationHandler.getInstance(value.asComplex(), internalRef, service));
     } else if (value.isCollection()) {
       final ArrayList<Object> collection = new ArrayList<Object>();
 
@@ -543,8 +540,7 @@ public final class CoreUtils {
           final Object collItem = Proxy.newProxyInstance(
                   Thread.currentThread().getContextClassLoader(),
                   new Class<?>[] {internalRef},
-                  ComplexInvocationHandler.getInstance(
-                  client, itemValue.asComplex(), internalRef, entityHandler));
+                  ComplexInvocationHandler.getInstance(itemValue.asComplex(), internalRef, service));
 
           collection.add(collItem);
         }
@@ -601,7 +597,7 @@ public final class CoreUtils {
     return getTypeRef(value, "META-INF/" + Constants.PROXY_ENUM_CLASS_LIST, EnumType.class);
   }
 
-  private static Class<?> getComplexTypeRef(final ODataValue value) {
+  public static Class<?> getComplexTypeRef(final ODataValue value) {
     return getTypeRef(value, "META-INF/" + Constants.PROXY_COMPLEX_CLASS_LIST, ComplexType.class);
   }
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/dfe68e67/fit/src/test/java/org/apache/olingo/fit/proxy/v4/APIBasicDesignTestITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/proxy/v4/APIBasicDesignTestITCase.java b/fit/src/test/java/org/apache/olingo/fit/proxy/v4/APIBasicDesignTestITCase.java
index 69bcfc2..2d7292f 100644
--- a/fit/src/test/java/org/apache/olingo/fit/proxy/v4/APIBasicDesignTestITCase.java
+++ b/fit/src/test/java/org/apache/olingo/fit/proxy/v4/APIBasicDesignTestITCase.java
@@ -25,15 +25,15 @@ import org.apache.olingo.fit.proxy.v4.staticservice.microsoft.test.odata.service
 import org.apache.olingo.fit.proxy.v4.staticservice.microsoft.test.odata.services.odatawcfservice.types.Customer;
 import org.apache.olingo.fit.proxy.v4.staticservice.microsoft.test.odata.services.odatawcfservice.types.Order;
 import org.apache.olingo.fit.proxy.v4.staticservice.microsoft.test.odata.services.odatawcfservice.types.PersonCollection;
-import org.junit.Test;
+import org.apache.olingo.fit.proxy.v4.staticservice.microsoft.test.odata.services.odatawcfservice.types.Address;
 
 import java.math.BigDecimal;
 import java.sql.Timestamp;
 import java.util.Arrays;
 import java.util.Calendar;
 import java.util.TimeZone;
-import static org.apache.olingo.fit.proxy.v4.AbstractTestITCase.service;
 
+import org.junit.Test;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -65,6 +65,47 @@ public class APIBasicDesignTestITCase extends AbstractTestITCase {
   }
 
   @Test
+  public void readAndCheckForComplex() {
+    Customer customer = container.getCustomers().getByKey(1); // no http request
+    Address homeAddress = customer.getHomeAddress();
+    assertNotNull(homeAddress);
+    assertNull(homeAddress.getCity());
+    assertNull(homeAddress.getPostalCode());
+    assertNull(homeAddress.getStreet());
+
+    homeAddress.load(); // HTTP request at complex loading
+    assertEquals("London", homeAddress.getCity());
+    assertEquals("98052", homeAddress.getPostalCode());
+    assertEquals("1 Microsoft Way", homeAddress.getStreet());
+
+    getService().getContext().detachAll();
+
+    homeAddress = container.getCustomers().getByKey(1).load().getHomeAddress(); // HTTP request at entity loading
+    assertEquals("London", homeAddress.getCity());
+    assertEquals("98052", homeAddress.getPostalCode());
+    assertEquals("1 Microsoft Way", homeAddress.getStreet());
+
+    getService().getContext().detachAll();
+
+    customer = container.getOrders().getByKey(8).getCustomerForOrder();
+    homeAddress = customer.getHomeAddress().select("City", "PostalCode").expand("SomethingElse"); // no HTTP request
+    assertNotNull(homeAddress);
+    assertNull(homeAddress.getCity());
+    assertNull(homeAddress.getPostalCode());
+    assertNull(homeAddress.getStreet());
+
+    try {
+      homeAddress.load();
+      fail();
+    } catch (Exception e) {
+      // Generated URL 
+      // "<serviceroot>/Orders(8)/CustomerForOrder/HomeAddress?$select=City,PostalCode&$expand=SomethingElse"
+      // curently unsupported by test service server
+      homeAddress.clearQueryOptions();
+    }
+  }
+
+  @Test
   public void readWholeEntitySet() {
     PersonCollection person = getContainer().getPeople().execute();
     assertEquals(5, person.size(), 0);

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/dfe68e67/fit/src/test/java/org/apache/olingo/fit/proxy/v4/DerivedTypeTestITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/proxy/v4/DerivedTypeTestITCase.java b/fit/src/test/java/org/apache/olingo/fit/proxy/v4/DerivedTypeTestITCase.java
index c6920b0..c9cd262 100644
--- a/fit/src/test/java/org/apache/olingo/fit/proxy/v4/DerivedTypeTestITCase.java
+++ b/fit/src/test/java/org/apache/olingo/fit/proxy/v4/DerivedTypeTestITCase.java
@@ -16,7 +16,6 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
 package org.apache.olingo.fit.proxy.v4;
 
 //CHECKSTYLE:OFF (Maven checkstyle)