You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by ch...@apache.org on 2016/02/29 10:47:35 UTC
olingo-odata4 git commit: OLINGO-848: getting a property of an entity
flags the entity as changed
Repository: olingo-odata4
Updated Branches:
refs/heads/master 40ff7be0f -> c7e663049
OLINGO-848: getting a property of an entity flags the entity as changed
Signed-off-by: Christian Amend <ch...@sap.com>
Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/c7e66304
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/c7e66304
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/c7e66304
Branch: refs/heads/master
Commit: c7e6630492d34f615990fb747ed76868b9046aba
Parents: 40ff7be
Author: Frederik Zimmer <fr...@partake.de>
Authored: Fri Feb 26 17:36:13 2016 +0100
Committer: Christian Amend <ch...@sap.com>
Committed: Mon Feb 29 10:40:14 2016 +0100
----------------------------------------------------------------------
.../AbstractCollectionInvocationHandler.java | 9 -
.../AbstractStructuredInvocationHandler.java | 98 +++++++---
.../proxy/commons/ComplexInvocationHandler.java | 7 +-
.../proxy/commons/EntityInvocationHandler.java | 14 +-
.../NonTransactionalPersistenceManagerImpl.java | 28 ++-
.../TransactionalPersistenceManagerImpl.java | 22 ++-
.../fit/proxy/ChangeDetectionTestITCase.java | 188 +++++++++++++++++++
7 files changed, 305 insertions(+), 61 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/c7e66304/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractCollectionInvocationHandler.java
----------------------------------------------------------------------
diff --git a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractCollectionInvocationHandler.java b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractCollectionInvocationHandler.java
index dd10b75..e465722 100644
--- a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractCollectionInvocationHandler.java
+++ b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractCollectionInvocationHandler.java
@@ -64,8 +64,6 @@ public abstract class AbstractCollectionInvocationHandler<T extends Serializable
private final Map<Class<? extends AbstractTerm>, Object> annotationsByTerm =
new HashMap<Class<? extends AbstractTerm>, Object>();
- private boolean changed = false;
-
public AbstractCollectionInvocationHandler(
final AbstractService<?> service,
final Collection<T> items,
@@ -174,7 +172,6 @@ public abstract class AbstractCollectionInvocationHandler<T extends Serializable
service.getContext().entityContext().attachNew(handler);
}
}
- changed = true;
return items.add(element);
}
@@ -186,7 +183,6 @@ public abstract class AbstractCollectionInvocationHandler<T extends Serializable
return false;
}
- changed = true;
return referenceItems.add(id.toASCIIString());
}
@@ -243,7 +239,6 @@ public abstract class AbstractCollectionInvocationHandler<T extends Serializable
@Override
public boolean addAll(final Collection<? extends T> collection) {
- changed = true;
return items.addAll(collection);
}
@@ -324,8 +319,4 @@ public abstract class AbstractCollectionInvocationHandler<T extends Serializable
this.uri = this.baseURI == null ? null : getClient().newURIBuilder(baseURI.toASCIIString());
this.nextPageURI = null;
}
-
- public boolean isChanged() {
- return changed;
- }
}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/c7e66304/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 a448186..6f2527c 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
@@ -93,10 +93,6 @@ public abstract class AbstractStructuredInvocationHandler extends AbstractInvoca
protected final Map<NavigationProperty, Object> linkCache = new HashMap<NavigationProperty, Object>();
- protected int propertiesTag = 0;
-
- protected int linksTag = 0;
-
protected final Map<String, EdmStreamValue> streamedPropertyChanges = new HashMap<String, EdmStreamValue>();
protected final Map<String, EdmStreamValue> streamedPropertyCache = new HashMap<String, EdmStreamValue>();
@@ -386,7 +382,6 @@ public abstract class AbstractStructuredInvocationHandler extends AbstractInvoca
}
if (res != null) {
- addPropertyChanges(name, res);
propertyCache.put(name, res);
}
@@ -526,7 +521,79 @@ public abstract class AbstractStructuredInvocationHandler extends AbstractInvoca
}
public Map<String, Object> getPropertyChanges() {
- return propertyChanges;
+ Map<String, Object> changedProperties = new HashMap<String, Object>();
+ changedProperties.putAll(propertyChanges);
+
+ for (Map.Entry<String, Object> propertyCacheEntry : propertyCache.entrySet()) {
+ if (hasCachedPropertyChanged(propertyCacheEntry.getValue())) {
+ changedProperties.put(propertyCacheEntry.getKey(), propertyCacheEntry.getValue());
+ }
+ }
+
+ return changedProperties;
+ }
+
+ protected boolean hasCachedPropertyChanged(final Object cachedValue) {
+ AbstractStructuredInvocationHandler structuredInvocationHandler = getStructuredInvocationHandler(cachedValue);
+ if (structuredInvocationHandler != null) {
+ return structuredInvocationHandler.isChanged();
+ }
+
+ return false;
+ }
+
+ public boolean isChanged() {
+ return !linkChanges.isEmpty()
+ || hasPropertyChanges();
+ }
+
+ protected boolean hasPropertyChanges() {
+ return !propertyChanges.isEmpty() || hasDeepPropertyChanges();
+ }
+
+ protected boolean hasDeepPropertyChanges() {
+ for (Object propertyValue : propertyCache.values()) {
+ if (hasCachedPropertyChanged(propertyValue)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public void applyChanges() {
+ streamedPropertyCache.putAll(streamedPropertyChanges);
+ streamedPropertyChanges.clear();
+ propertyCache.putAll(propertyChanges);
+ propertyChanges.clear();
+ linkCache.putAll(linkChanges);
+ linkChanges.clear();
+
+ applyChangesOnChildren();
+ }
+
+ protected void applyChangesOnChildren() {
+ for (Object propertyValue : propertyCache.values()) {
+ applyChanges(propertyValue);
+ }
+ }
+
+ protected void applyChanges(final Object cachedValue) {
+ AbstractStructuredInvocationHandler structuredInvocationHandler = getStructuredInvocationHandler(cachedValue);
+ if (structuredInvocationHandler != null) {
+ structuredInvocationHandler.applyChanges();
+ }
+ }
+
+ protected AbstractStructuredInvocationHandler getStructuredInvocationHandler(final Object value) {
+ if (value != null && Proxy.isProxyClass(value.getClass())) {
+ InvocationHandler invocationHandler = Proxy.getInvocationHandler(value);
+ if (invocationHandler instanceof AbstractStructuredInvocationHandler) {
+ return (AbstractStructuredInvocationHandler) invocationHandler;
+ }
+ }
+
+ return null;
}
public Collection<String> readAdditionalPropertyNames() {
@@ -567,14 +634,11 @@ public abstract class AbstractStructuredInvocationHandler extends AbstractInvoca
}
protected void addPropertyChanges(final String name, final Object value) {
- final int checkpoint = propertyChanges.hashCode();
- updatePropertiesTag(checkpoint);
+ propertyCache.remove(name);
propertyChanges.put(name, value);
}
protected void addLinkChanges(final NavigationProperty navProp, final Object value) {
- final int checkpoint = linkChanges.hashCode();
- updateLinksTag(checkpoint);
linkChanges.put(navProp, value);
if (linkCache.containsKey(navProp)) {
@@ -582,18 +646,6 @@ public abstract class AbstractStructuredInvocationHandler extends AbstractInvoca
}
}
- protected void updatePropertiesTag(final int checkpoint) {
- if (propertiesTag == 0 || checkpoint == propertiesTag) {
- propertiesTag = propertyChanges.hashCode();
- }
- }
-
- protected void updateLinksTag(final int checkpoint) {
- if (linksTag == 0 || checkpoint == linksTag) {
- linksTag = linkChanges.hashCode();
- }
- }
-
public Map<String, EdmStreamValue> getStreamedPropertyChanges() {
return streamedPropertyChanges;
}
@@ -642,8 +694,6 @@ public abstract class AbstractStructuredInvocationHandler extends AbstractInvoca
protected abstract void load();
- public abstract boolean isChanged();
-
protected abstract <T extends ClientProperty> List<T> getInternalProperties();
protected abstract ClientProperty getInternalProperty(final String name);
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/c7e66304/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 1e2197c..aac32ac 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
@@ -27,10 +27,10 @@ import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
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.URIBuilder;
import org.apache.olingo.client.api.domain.ClientComplexValue;
import org.apache.olingo.client.api.domain.ClientLinked;
import org.apache.olingo.client.api.domain.ClientProperty;
+import org.apache.olingo.client.api.uri.URIBuilder;
import org.apache.olingo.commons.api.edm.FullQualifiedName;
import org.apache.olingo.ext.proxy.AbstractService;
import org.apache.olingo.ext.proxy.api.annotations.ComplexType;
@@ -145,11 +145,6 @@ public class ComplexInvocationHandler extends AbstractStructuredInvocationHandle
}
@Override
- public boolean isChanged() {
- return getEntityHandler() == null ? false : getEntityHandler().isChanged();
- }
-
- @Override
protected void load() {
try {
if (this.uri != null) {
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/c7e66304/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 e993140..2fea9bd 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
@@ -229,13 +229,12 @@ public class EntityInvocationHandler extends AbstractStructuredInvocationHandler
this.streamedPropertyChanges.clear();
this.streamedPropertyCache.clear();
this.propertyChanges.clear();
+ this.propertyCache.clear();
this.linkChanges.clear();
this.linkCache.clear();
- this.propertiesTag = 0;
- this.linksTag = 0;
this.annotations.clear();
}
-
+
public EntityUUID getUUID() {
return uuid;
}
@@ -301,11 +300,10 @@ public class EntityInvocationHandler extends AbstractStructuredInvocationHandler
return isChanged(true);
}
- public boolean isChanged(final boolean deep) {
- return this.linkChanges.hashCode() != this.linksTag
- || this.propertyChanges.hashCode() != this.propertiesTag
- || (deep && (this.stream != null
- || !this.streamedPropertyChanges.isEmpty()));
+ public boolean isChanged(final boolean considerStreamProperties) {
+ return super.isChanged()
+ || (considerStreamProperties && (stream != null
+ || !streamedPropertyChanges.isEmpty()));
}
public void uploadStream(final EdmStreamValue stream) {
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/c7e66304/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/NonTransactionalPersistenceManagerImpl.java
----------------------------------------------------------------------
diff --git a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/NonTransactionalPersistenceManagerImpl.java b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/NonTransactionalPersistenceManagerImpl.java
index 91f8cbe..b123d1e 100644
--- a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/NonTransactionalPersistenceManagerImpl.java
+++ b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/NonTransactionalPersistenceManagerImpl.java
@@ -74,15 +74,27 @@ public class NonTransactionalPersistenceManagerImpl extends AbstractPersistenceM
}
if (entry.getValue() != null
- && response instanceof ODataEntityCreateResponse && response.getStatusCode() == 201) {
- entry.getValue().setEntity(((ODataEntityCreateResponse<?>) response).getBody());
- responses.put(index, entry.getValue().getEntityURI());
- LOG.debug("Upgrade created object '{}'", entry.getValue());
+ && response instanceof ODataEntityCreateResponse && (response.getStatusCode() == 201 || response
+ .getStatusCode() == 204)) {
+ if (response.getStatusCode() == 201) {
+ entry.getValue().setEntity(((ODataEntityCreateResponse<?>) response).getBody());
+ responses.put(index, entry.getValue().getEntityURI());
+ LOG.debug("Upgrade created object '{}'", entry.getValue());
+ } else {
+ entry.getValue().applyChanges();
+ responses.put(index, null);
+ }
} else if (entry.getValue() != null
- && response instanceof ODataEntityUpdateResponse && response.getStatusCode() == 200) {
- entry.getValue().setEntity(((ODataEntityUpdateResponse<?>) response).getBody());
- responses.put(index, entry.getValue().getEntityURI());
- LOG.debug("Upgrade updated object '{}'", entry.getValue());
+ && response instanceof ODataEntityUpdateResponse && (response.getStatusCode() == 200 || response
+ .getStatusCode() == 204)) {
+ if (response.getStatusCode() == 200) {
+ entry.getValue().setEntity(((ODataEntityUpdateResponse<?>) response).getBody());
+ responses.put(index, entry.getValue().getEntityURI());
+ LOG.debug("Upgrade updated object '{}'", entry.getValue());
+ } else {
+ entry.getValue().applyChanges();
+ responses.put(index, null);
+ }
} else {
responses.put(index, null);
}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/c7e66304/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/TransactionalPersistenceManagerImpl.java
----------------------------------------------------------------------
diff --git a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/TransactionalPersistenceManagerImpl.java b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/TransactionalPersistenceManagerImpl.java
index e43a4e1..e24796e 100644
--- a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/TransactionalPersistenceManagerImpl.java
+++ b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/TransactionalPersistenceManagerImpl.java
@@ -116,12 +116,22 @@ public class TransactionalPersistenceManagerImpl extends AbstractPersistenceMana
final EntityInvocationHandler handler = items.get(changesetItemId);
if (handler != null) {
- if (res instanceof ODataEntityCreateResponse && res.getStatusCode() == 201) {
- handler.setEntity(((ODataEntityCreateResponse<?>) res).getBody());
- LOG.debug("Upgrade created object '{}'", handler);
- } else if (res instanceof ODataEntityUpdateResponse && res.getStatusCode() == 200) {
- handler.setEntity(((ODataEntityUpdateResponse<?>) res).getBody());
- LOG.debug("Upgrade updated object '{}'", handler);
+ if (res instanceof ODataEntityCreateResponse && (res.getStatusCode() == 201 || res
+ .getStatusCode() == 204)) {
+ if (res.getStatusCode() == 201) {
+ handler.setEntity(((ODataEntityCreateResponse<?>) res).getBody());
+ LOG.debug("Upgrade created object '{}'", handler);
+ } else {
+ handler.applyChanges();
+ }
+ } else if (res instanceof ODataEntityUpdateResponse && (res.getStatusCode() == 200 || res
+ .getStatusCode() == 204)) {
+ if (res.getStatusCode() == 201) {
+ handler.setEntity(((ODataEntityUpdateResponse<?>) res).getBody());
+ LOG.debug("Upgrade updated object '{}'", handler);
+ } else {
+ handler.applyChanges();
+ }
}
}
}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/c7e66304/fit/src/test/java/org/apache/olingo/fit/proxy/ChangeDetectionTestITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/proxy/ChangeDetectionTestITCase.java b/fit/src/test/java/org/apache/olingo/fit/proxy/ChangeDetectionTestITCase.java
new file mode 100644
index 0000000..33897e7
--- /dev/null
+++ b/fit/src/test/java/org/apache/olingo/fit/proxy/ChangeDetectionTestITCase.java
@@ -0,0 +1,188 @@
+/*
+ * 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.fit.proxy;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.lang.reflect.Proxy;
+import java.sql.Timestamp;
+import java.util.Calendar;
+
+import org.apache.commons.lang3.RandomUtils;
+import org.apache.olingo.ext.proxy.api.ComplexType;
+import org.apache.olingo.ext.proxy.api.EntityCollection;
+import org.apache.olingo.ext.proxy.api.EntityType;
+import org.apache.olingo.ext.proxy.commons.ComplexInvocationHandler;
+import org.apache.olingo.ext.proxy.commons.EntityCollectionInvocationHandler;
+import org.apache.olingo.ext.proxy.commons.EntityInvocationHandler;
+// CHECKSTYLE:OFF (Maven checkstyle)
+import org.apache.olingo.fit.proxy.staticservice.microsoft.test.odata.services.odatawcfservice.InMemoryEntities;
+import org.apache.olingo.fit.proxy.staticservice.microsoft.test.odata.services.odatawcfservice.types.Account;
+import org.apache.olingo.fit.proxy.staticservice.microsoft.test.odata.services.odatawcfservice.types.Address;
+import org.apache.olingo.fit.proxy.staticservice.microsoft.test.odata.services.odatawcfservice.types.Customer;
+import org.apache.olingo.fit.proxy.staticservice.microsoft.test.odata.services.odatawcfservice.types.Order;
+import org.apache.olingo.fit.proxy.staticservice.microsoft.test.odata.services.odatawcfservice.types.OrderCollection;
+import org.apache.olingo.fit.proxy.staticservice.microsoft.test.odata.services.odatawcfservice.types.PaymentInstrument;
+import org.apache.olingo.fit.proxy.staticservice.microsoft.test.odata.services.odatawcfservice.types.PaymentInstrumentCollection;
+// CHECKSTYLE:ON (Maven checkstyle)
+import org.junit.Test;
+
+public class ChangeDetectionTestITCase extends AbstractTestITCase {
+
+ @Test
+ public void entityUnchangedOnGetProperty() {
+ final Customer customer = getContainer().getCustomers().getByKey(1).load();
+ assertFalse(isChanged(customer));
+
+ customer.getLastName();
+
+ assertFalse(isChanged(customer));
+ }
+
+ @Test
+ public void entityChangedOnSetProperty() {
+ final Customer customer = getContainer().getCustomers().getByKey(1).load();
+ assertFalse(isChanged(customer));
+
+ customer.setLastName("Test");
+
+ assertTrue(isChanged(customer));
+
+ getContainer().flush();
+ assertFalse(isChanged(customer));
+ }
+
+ @Test
+ public void entityUnchangedOnGetComplexProperty() {
+ final Customer customer = getContainer().getCustomers().getByKey(1).load();
+ assertFalse(isChanged(customer));
+
+ final Address homeAddress = customer.getHomeAddress();
+ assertFalse(isChanged(customer));
+
+ homeAddress.getCity();
+ assertFalse(isChanged(homeAddress));
+ assertFalse(isChanged(customer));
+ }
+
+ @Test
+ public void entityChangedOnSetComplexProperty() {
+ final Customer customer = getContainer().getCustomers().getByKey(2).load();
+ assertFalse(isChanged(customer));
+
+ final Address newAdress = getContainer().newComplexInstance(Address.class);
+ customer.setHomeAddress(newAdress);
+
+ assertTrue(isChanged(customer));
+
+ getContainer().flush();
+ assertFalse(isChanged(customer));
+ }
+
+ @Test
+ public void entityChangedOnSetPropertyOfComplexProperty() {
+ final Customer customer = getContainer().getCustomers().getByKey(1).load();
+ assertFalse(isChanged(customer));
+
+ final Address homeAddress = customer.getHomeAddress();
+ homeAddress.setCity("Test");
+
+ assertTrue(isChanged(customer));
+
+ getContainer().flush();
+ assertFalse(isChanged(customer));
+ }
+
+ @Test
+ public void entityUnchangedOnGetNavigationProperty() {
+ final Customer customer = getContainer().getCustomers().getByKey(1).load();
+ assertFalse(isChanged(customer));
+
+ customer.getOrders();
+
+ assertFalse(isChanged(customer));
+ }
+
+ @Test
+ public void entityChangedOnAddNavigationProperty() {
+ final Account account = getContainer().getAccounts().getByKey(101).load();
+ assertFalse(isChanged(account));
+
+ final PaymentInstrumentCollection instruments = account.getMyPaymentInstruments().execute();
+ assertFalse(isChanged(account));
+
+ final PaymentInstrument instrument = getContainer().newEntityInstance(PaymentInstrument.class);
+ final int id = RandomUtils.nextInt(101999, 105000);
+ instrument.setPaymentInstrumentID(id);
+ instrument.setFriendlyName("New one");
+ instrument.setCreatedDate(new Timestamp(Calendar.getInstance().getTimeInMillis()));
+ instruments.add(instrument);
+
+ assertTrue(isChanged(instrument));
+ assertFalse(isChanged(account));
+
+ getContainer().flush();
+ assertFalse(isChanged(instrument));
+ }
+
+ @Test
+ public void entityCollectionUnchangedOnGet() {
+ final Customer customer = getContainer().getCustomers().getByKey(1).load();
+ assertFalse(isChanged(customer));
+
+ final OrderCollection orders = customer.getOrders().execute();
+ assertFalse(isChanged(customer));
+
+ for (Order order : orders) {
+ assertFalse(isChanged(order));
+ order.getOrderDate();
+ assertFalse(isChanged(order));
+ }
+
+ assertFalse(isChanged(customer));
+ }
+
+ protected InMemoryEntities getContainer() {
+ return container;
+ }
+
+ protected boolean isChanged(final EntityType<?> entity) {
+ EntityInvocationHandler invocationHandler = getInvocationHandler(entity);
+ return invocationHandler.isChanged();
+ }
+
+ protected boolean isChanged(final ComplexType<?> complex) {
+ ComplexInvocationHandler invocationHandler = getInvocationHandler(complex);
+ return invocationHandler.isChanged();
+ }
+
+ protected EntityInvocationHandler getInvocationHandler(final EntityType<?> entity) {
+ return (EntityInvocationHandler) Proxy.getInvocationHandler(entity);
+ }
+
+ protected ComplexInvocationHandler getInvocationHandler(final ComplexType<?> complex) {
+ return (ComplexInvocationHandler) Proxy.getInvocationHandler(complex);
+ }
+
+ protected EntityCollectionInvocationHandler<?> getInvocationHandler(
+ final EntityCollection<?, ?, ?> complex) {
+ return (EntityCollectionInvocationHandler<?>) Proxy.getInvocationHandler(complex);
+ }
+}