diff --git a/src/main/java/com/avaje/ebean/BeanState.java b/src/main/java/com/avaje/ebean/BeanState.java index 51e54d940..aaa830995 100644 --- a/src/main/java/com/avaje/ebean/BeanState.java +++ b/src/main/java/com/avaje/ebean/BeanState.java @@ -38,6 +38,33 @@ public interface BeanState { */ void setDisableLazyLoad(boolean disableLazyLoading); + /** + * Set the loaded state of the property given it's name. + * + *
+ * Typically this would be used to set the loaded state of a property + * to false to ensure that the specific property is excluded from a + * stateless update. + *
+ * + *{@code
+ *
+ * // populate a bean via say JSON
+ * User user = ...;
+ *
+ * // set loaded state on the email property to false so that
+ * // the email property is not included in a stateless update
+ * Ebean.getBeanState(user).setPropertyLoaded("email", false);
+ *
+ * user.update();
+ *
+ * }
+ *
+ *
+ * This will throw an IllegalArgumentException if the property is unknown.
+ */
+ void setPropertyLoaded(String propertyName, boolean loaded);
+
/**
* For partially populated beans returns the properties that are loaded on the
* bean.
diff --git a/src/main/java/com/avaje/ebean/Model.java b/src/main/java/com/avaje/ebean/Model.java
index 79366e8c6..49c9f0d63 100644
--- a/src/main/java/com/avaje/ebean/Model.java
+++ b/src/main/java/com/avaje/ebean/Model.java
@@ -1,5 +1,6 @@
package com.avaje.ebean;
+import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebean.text.PathProperties;
import com.avaje.ebean.util.ClassUtil;
import org.jetbrains.annotations.Nullable;
@@ -193,7 +194,31 @@ public abstract class Model {
public void markAsDirty() {
db().markAsDirty(this);
}
-
+
+ /**
+ * Mark the property as unset or 'not loaded'.
+ * + * This would be used to specify a property that we did not wish to include in a stateless update. + *
+ *{@code
+ *
+ * // populate an entity bean from JSON or whatever
+ * User user = ...;
+ *
+ * // mark the email property as 'unset' so that it is not
+ * // included in a 'stateless update'
+ * user.markPropertyUnset("email");
+ *
+ * user.update();
+ *
+ * }
+ *
+ * @param propertyName the name of the property on the bean to be marked as 'unset'
+ */
+ public void markPropertyUnset(String propertyName) {
+ ((EntityBean)this)._ebean_getIntercept().setPropertyLoaded(propertyName, false);
+ }
+
/**
* Insert or update this entity depending on its state.
*
diff --git a/src/main/java/com/avaje/ebean/bean/EntityBeanIntercept.java b/src/main/java/com/avaje/ebean/bean/EntityBeanIntercept.java
index 42d67e7c8..e1e2845a1 100644
--- a/src/main/java/com/avaje/ebean/bean/EntityBeanIntercept.java
+++ b/src/main/java/com/avaje/ebean/bean/EntityBeanIntercept.java
@@ -449,7 +449,18 @@ public final class EntityBeanIntercept implements Serializable {
public int getPropertyLength() {
return owner._ebean_getPropertyNames().length;
}
-
+
+ /**
+ * Set the loaded state of the property given it's name.
+ */
+ public void setPropertyLoaded(String propertyName, boolean loaded) {
+ int position = findProperty(propertyName);
+ if (position == -1) {
+ throw new IllegalArgumentException("Property "+propertyName+" not found");
+ }
+ loadedProps[position] = loaded;
+ }
+
/**
* Set the property to be treated as unloaded. Used for properties initialised in default
* constructor.
diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultBeanState.java b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultBeanState.java
index daa516599..a713b5100 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultBeanState.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultBeanState.java
@@ -1,14 +1,14 @@
package com.avaje.ebeaninternal.server.core;
-import java.beans.PropertyChangeListener;
-import java.util.Map;
-import java.util.Set;
-
import com.avaje.ebean.BeanState;
import com.avaje.ebean.ValuePair;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebean.bean.EntityBeanIntercept;
+import java.beans.PropertyChangeListener;
+import java.util.Map;
+import java.util.Set;
+
/**
* Default implementation of BeanState.
*/
@@ -23,9 +23,13 @@ public class DefaultBeanState implements BeanState {
this.intercept = entityBean._ebean_getIntercept();
}
- public boolean isReference() {
- return intercept.isReference();
- }
+ public void setPropertyLoaded(String propertyName, boolean loaded) {
+ intercept.setPropertyLoaded(propertyName, loaded);
+ }
+
+ public boolean isReference() {
+ return intercept.isReference();
+ }
public boolean isNew() {
return intercept.isNew();
diff --git a/src/test/java/com/avaje/ebean/TestUnsetLoadedProperties.java b/src/test/java/com/avaje/ebean/TestUnsetLoadedProperties.java
index 894b300b4..fa6937e69 100644
--- a/src/test/java/com/avaje/ebean/TestUnsetLoadedProperties.java
+++ b/src/test/java/com/avaje/ebean/TestUnsetLoadedProperties.java
@@ -1,7 +1,6 @@
package com.avaje.ebean;
import com.avaje.ebean.bean.EntityBean;
-import com.avaje.ebean.bean.EntityBeanIntercept;
import com.avaje.tests.model.converstation.User;
import org.avaje.ebeantest.LoggedSqlCollector;
import org.junit.Test;
@@ -9,7 +8,6 @@ import org.junit.Test;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.Assert.assertTrue;
public class TestUnsetLoadedProperties extends BaseTestCase {
@@ -30,22 +28,10 @@ public class TestUnsetLoadedProperties extends BaseTestCase {
user.setEmail("change@junk.com");
- // confirm it's loaded state
- EntityBean eb = (EntityBean)user;
- EntityBeanIntercept ebi = eb._ebean_getIntercept();
-
- int namePosition = ebi.findProperty("name");
- assertTrue(ebi.isLoadedProperty(namePosition));
-
- int emailPosition = ebi.findProperty("email");
- assertTrue(ebi.isLoadedProperty(emailPosition));
-
BeanState beanState = Ebean.getBeanState(user);
assertThat(beanState.getLoadedProps()).containsExactly("id", "name", "email");
- // unset the loaded state for email
- //ebi.setPropertyUnloaded(emailPosition);
- unloadProperty(user, "email");
+ user.markPropertyUnset("email");
assertThat(beanState.getLoadedProps()).containsExactly("id", "name");
@@ -58,16 +44,55 @@ public class TestUnsetLoadedProperties extends BaseTestCase {
}
- private void unloadProperty(Object entityBean, String propertyName) {
+ @Test
+ public void testUnloadVia_EntityBeanIntercept_setPropertyLoaded() {
- EntityBean eb = (EntityBean)entityBean;
- EntityBeanIntercept ebi = eb._ebean_getIntercept();
- int position = ebi.findProperty(propertyName);
- if (position == -1) {
- throw new RuntimeException("Property "+propertyName+" not found on bean "+entityBean.getClass());
- }
- ebi.setPropertyUnloaded(position);
+ // our bean to perform stateless update
+ User user = new User();
+ user.setId(42L);
+ user.setName("name mod");
+ user.setEmail("change@junk.com");
+
+ BeanState beanState = Ebean.getBeanState(user);
+ assertThat(beanState.getLoadedProps()).containsExactly("id", "name", "email");
+
+ // unset the loaded state for email
+ ((EntityBean)user)._ebean_getIntercept().setPropertyLoaded("email", false);
+
+ assertThat(beanState.getLoadedProps()).containsExactly("id", "name");
}
+ @Test
+ public void testUnloadVia_Model_markPropertyUnset() {
+
+ // our bean to perform stateless update
+ User user = new User();
+ user.setId(42L);
+ user.setName("name mod");
+ user.setEmail("change@junk.com");
+
+ BeanState beanState = Ebean.getBeanState(user);
+ assertThat(beanState.getLoadedProps()).containsExactly("id", "name", "email");
+
+
+ user.markPropertyUnset("email");
+ assertThat(beanState.getLoadedProps()).containsExactly("id", "name");
+ }
+
+ @Test
+ public void testUnloadVia_BeanState_setPropertyLoaded() {
+
+ // our bean to perform stateless update
+ User user = new User();
+ user.setId(42L);
+ user.setName("name mod");
+ user.setEmail("change@junk.com");
+
+ BeanState beanState = Ebean.getBeanState(user);
+ assertThat(beanState.getLoadedProps()).containsExactly("id", "name", "email");
+
+ Ebean.getBeanState(user).setPropertyLoaded("email", false);
+ assertThat(beanState.getLoadedProps()).containsExactly("id", "name");
+ }
}