diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationFields.java b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationFields.java index 47c5ec721..d50a1d234 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationFields.java +++ b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationFields.java @@ -140,6 +140,21 @@ public class AnnotationFields extends AnnotationParser { if (formula != null) { prop.setSqlFormula(formula.select(), formula.join()); } + + initWhoCreated(prop); + initWhoModified(prop); + } + + private void initWhoModified(DeployBeanProperty prop) { + if (get(prop, WhoModified.class) != null) { + generatedPropFactory.setWhoModified(prop); + } + } + + private void initWhoCreated(DeployBeanProperty prop) { + if (get(prop, WhoCreated.class) != null) { + generatedPropFactory.setWhoCreated(prop); + } } private void readField(DeployBeanProperty prop) { @@ -282,12 +297,8 @@ public class AnnotationFields extends AnnotationParser { generatedPropFactory.setUpdateTimestamp(prop); } - if (get(prop, WhoCreated.class) != null) { - generatedPropFactory.setWhoCreated(prop); - } - if (get(prop, WhoModified.class) != null) { - generatedPropFactory.setWhoModified(prop); - } + initWhoCreated(prop); + initWhoModified(prop); if (get(prop, HistoryExclude.class) != null) { prop.setExcludedFromHistory(); diff --git a/src/main/java/io/ebeaninternal/server/persist/dmlbind/BindableAssocOne.java b/src/main/java/io/ebeaninternal/server/persist/dmlbind/BindableAssocOne.java index 96a6a9285..d7061d0e6 100644 --- a/src/main/java/io/ebeaninternal/server/persist/dmlbind/BindableAssocOne.java +++ b/src/main/java/io/ebeaninternal/server/persist/dmlbind/BindableAssocOne.java @@ -3,8 +3,11 @@ package io.ebeaninternal.server.persist.dmlbind; import io.ebean.bean.EntityBean; import io.ebeaninternal.server.core.PersistRequestBean; import io.ebeaninternal.server.deploy.BeanPropertyAssocOne; +import io.ebeaninternal.server.deploy.generatedproperty.GeneratedProperty; import io.ebeaninternal.server.deploy.id.ImportedId; +import io.ebeaninternal.server.persist.dml.DmlMode; import io.ebeaninternal.server.persist.dml.GenerateDmlRequest; +import org.jetbrains.annotations.Nullable; import java.sql.SQLException; import java.util.List; @@ -17,10 +20,14 @@ public class BindableAssocOne implements Bindable { private final BeanPropertyAssocOne assocOne; private final ImportedId importedId; + private final DmlMode dmlMode; + private final GeneratedProperty generatedProperty; - public BindableAssocOne(BeanPropertyAssocOne assocOne) { + public BindableAssocOne(BeanPropertyAssocOne assocOne, DmlMode mode) { this.assocOne = assocOne; this.importedId = assocOne.getImportedId(); + this.dmlMode = mode; + this.generatedProperty = assocOne.getGeneratedProperty(); } public String toString() { @@ -33,7 +40,9 @@ public class BindableAssocOne implements Bindable { } public void addToUpdate(PersistRequestBean request, List list) { - if (request.isAddToUpdate(assocOne)) { + if (generatedProperty != null && generatedProperty.includeInAllUpdates()) { + list.add(this); + } else if (request.isAddToUpdate(assocOne)) { list.add(this); } } @@ -43,8 +52,41 @@ public class BindableAssocOne implements Bindable { } public void dmlBind(BindableRequest request, EntityBean bean) throws SQLException { + if (generatedProperty != null) { + bindGeneratedProperty(request, bean); + } else { + bindNotGeneratedProperty(request, bean); + } + } + private void bindGeneratedProperty(BindableRequest request, EntityBean bean) throws SQLException { + if (DmlMode.INSERT.equals(dmlMode) && generatedProperty.includeInInsert()) { + bindGeneratedInsert(request, bean); + } else if (DmlMode.UPDATE.equals(dmlMode) && generatedProperty.includeInAllUpdates()) { + bindGeneratedUpdate(request, bean); + } + } + + private void bindGeneratedUpdate(BindableRequest request, EntityBean bean) throws SQLException { + Object objectValue = generatedProperty.getUpdateValue(assocOne, bean, request.now()); + EntityBean generatedValue = castToEntityBean(objectValue); + assocOne.setValueChanged(bean, generatedValue); + registerDeferred(request, bean, generatedValue); + } + + private void bindGeneratedInsert(BindableRequest request, EntityBean bean) throws SQLException { + Object objectValue = generatedProperty.getInsertValue(assocOne, bean, request.now()); + EntityBean generatedValue = castToEntityBean(objectValue); + assocOne.setValue(bean, generatedValue); + registerDeferred(request, bean, generatedValue); + } + + private void bindNotGeneratedProperty(BindableRequest request, EntityBean bean) throws SQLException { EntityBean assocBean = (EntityBean) assocOne.getValue(bean); + registerDeferred(request, bean, assocBean); + } + + private void registerDeferred(BindableRequest request, EntityBean bean, EntityBean assocBean) throws SQLException { Object boundValue = importedId.bind(request, assocBean); if (boundValue == null && assocBean != null) { // this is the scenario for a derived foreign key @@ -55,4 +97,15 @@ public class BindableAssocOne implements Bindable { } } + @Nullable + private EntityBean castToEntityBean(Object objectValue) { + EntityBean generatedValue; + if (objectValue instanceof EntityBean || objectValue == null) { + generatedValue = (EntityBean) objectValue; + } else { + throw new IllegalStateException("Bean " + objectValue.getClass() + " is not enhanced?"); + } + return generatedValue; + } + } diff --git a/src/main/java/io/ebeaninternal/server/persist/dmlbind/FactoryAssocOnes.java b/src/main/java/io/ebeaninternal/server/persist/dmlbind/FactoryAssocOnes.java index 78b0c558d..d150c0df5 100644 --- a/src/main/java/io/ebeaninternal/server/persist/dmlbind/FactoryAssocOnes.java +++ b/src/main/java/io/ebeaninternal/server/persist/dmlbind/FactoryAssocOnes.java @@ -35,7 +35,7 @@ public class FactoryAssocOnes { } break; } - list.add(new BindableAssocOne(one)); + list.add(new BindableAssocOne(one, mode)); } } } diff --git a/src/test/java/io/ebean/MyCurrentUserProvider.java b/src/test/java/io/ebean/MyCurrentUserProvider.java index f4c2d9a0c..3f2c316a0 100644 --- a/src/test/java/io/ebean/MyCurrentUserProvider.java +++ b/src/test/java/io/ebean/MyCurrentUserProvider.java @@ -12,7 +12,7 @@ public class MyCurrentUserProvider implements CurrentUserProvider { /** * Do not do this yourself - this is for testing purposes. */ - private static String userId = DEFAULT; + private static Object userId = DEFAULT; @Override @@ -21,7 +21,7 @@ public class MyCurrentUserProvider implements CurrentUserProvider { return userId; } - public static void setUserId(String value) { + public static void setUser(Object value) { userId = value; } diff --git a/src/test/java/org/tests/generated/TestGeneratedWho.java b/src/test/java/org/tests/generated/TestGeneratedWho.java index 2a19c9b43..9adb3bb5a 100644 --- a/src/test/java/org/tests/generated/TestGeneratedWho.java +++ b/src/test/java/org/tests/generated/TestGeneratedWho.java @@ -5,9 +5,12 @@ import io.ebean.Ebean; import io.ebean.MyCurrentUserProvider; import org.tests.model.EWhoProps; import org.junit.Test; +import org.tests.model.generated.User; +import org.tests.model.generated.WhoPropsOneToMany; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; public class TestGeneratedWho extends BaseTestCase { @@ -17,7 +20,7 @@ public class TestGeneratedWho extends BaseTestCase { EWhoProps bean = new EWhoProps(); bean.setName("one"); - MyCurrentUserProvider.setUserId("INSERT_WHO_1"); + MyCurrentUserProvider.setUser("INSERT_WHO_1"); Ebean.save(bean); assertEquals("one", bean.getName()); @@ -26,7 +29,7 @@ public class TestGeneratedWho extends BaseTestCase { assertNotNull(bean.getWhenCreated()); assertNotNull(bean.getWhenModified()); - MyCurrentUserProvider.setUserId("UPDATE_WHO_1"); + MyCurrentUserProvider.setUser("UPDATE_WHO_1"); bean.setName("two"); Ebean.save(bean); @@ -34,7 +37,7 @@ public class TestGeneratedWho extends BaseTestCase { assertEquals("INSERT_WHO_1", bean.getWhoCreated()); assertEquals("UPDATE_WHO_1", bean.getWhoModified()); - MyCurrentUserProvider.setUserId("UPDATE_WHO_2"); + MyCurrentUserProvider.setUser("UPDATE_WHO_2"); bean.setName("three"); Ebean.save(bean); @@ -43,4 +46,60 @@ public class TestGeneratedWho extends BaseTestCase { MyCurrentUserProvider.resetToDefault(); } + + @Test + public void insertOneToManyWhoCreated() { + User creator = new User("jack"); + User maintainer01 = new User("jill"); + User maintainer02 = new User("joe"); + Ebean.save(creator); + Ebean.save(maintainer01); + Ebean.save(maintainer02); + + WhoPropsOneToMany bean = new WhoPropsOneToMany(); + bean.setName("one"); + + MyCurrentUserProvider.setUser(creator); + Ebean.save(bean); + + assertNotNull(bean.getWhoCreated()); + assertEquals(creator.getId(), bean.getWhoCreated().getId()); + assertEquals(creator.getId(), bean.getWhoModified().getId()); + + MyCurrentUserProvider.setUser(maintainer01); + bean.setName("two"); + Ebean.save(bean); + + assertEquals("two", bean.getName()); + assertEquals(creator.getId(), bean.getWhoCreated().getId()); + assertEquals(maintainer01.getId(), bean.getWhoModified().getId()); + + MyCurrentUserProvider.setUser(maintainer02); + bean.setName("three"); + Ebean.save(bean); + + assertEquals(creator.getId(), bean.getWhoCreated().getId()); + assertEquals(maintainer02.getId(), bean.getWhoModified().getId()); + + MyCurrentUserProvider.resetToDefault(); + } + + @Test + public void insertNullIntoOneToManyWhoCreated() { + User creator = new User("jack"); + Ebean.save(creator); + + WhoPropsOneToMany bean = new WhoPropsOneToMany(); + bean.setName("one"); + bean.setWhoCreated(creator); + bean.setWhoModified(creator); + + MyCurrentUserProvider.setUser(null); + Ebean.save(bean); + + assertNull(bean.getWhoCreated()); + assertNull(bean.getWhoModified()); + + MyCurrentUserProvider.resetToDefault(); + } } diff --git a/src/test/java/org/tests/model/generated/User.java b/src/test/java/org/tests/model/generated/User.java new file mode 100644 index 000000000..be1336f44 --- /dev/null +++ b/src/test/java/org/tests/model/generated/User.java @@ -0,0 +1,39 @@ +package org.tests.model.generated; + +import javax.persistence.*; + +/** + * @author Vilmos Nagy + */ +@Entity +@Table(name = "g_user") +public class User { + + @Id + final Long id; + + @Version + final Long version; + + @Basic + final String username; + + public User(String username) { + this.id = null; + this.version = null; + this.username = username; + } + + public Long getId() { + return id; + } + + public Long getVersion() { + return version; + } + + public String getUsername() { + return username; + } + +} diff --git a/src/test/java/org/tests/model/generated/WhoPropsOneToMany.java b/src/test/java/org/tests/model/generated/WhoPropsOneToMany.java new file mode 100644 index 000000000..a18dee653 --- /dev/null +++ b/src/test/java/org/tests/model/generated/WhoPropsOneToMany.java @@ -0,0 +1,96 @@ +package org.tests.model.generated; + +import io.ebean.annotation.WhenCreated; +import io.ebean.annotation.WhenModified; +import io.ebean.annotation.WhoCreated; +import io.ebean.annotation.WhoModified; + +import javax.persistence.*; +import java.sql.Timestamp; + +/** + * @author Vilmos Nagy + */ +@Entity +@Table(name = "g_who_props_otm") +public class WhoPropsOneToMany { + + @Id + Long id; + + @Version + Long version; + + @WhenCreated + Timestamp whenCreated; + + @WhenModified + Timestamp whenModified; + + @ManyToOne + @WhoCreated + User whoCreated; + + @ManyToOne + @WhoModified + User whoModified; + + @Basic + String name; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getVersion() { + return version; + } + + public void setVersion(Long version) { + this.version = version; + } + + public Timestamp getWhenCreated() { + return whenCreated; + } + + public void setWhenCreated(Timestamp whenCreated) { + this.whenCreated = whenCreated; + } + + public Timestamp getWhenModified() { + return whenModified; + } + + public void setWhenModified(Timestamp whenModified) { + this.whenModified = whenModified; + } + + public User getWhoCreated() { + return whoCreated; + } + + public void setWhoCreated(User whoCreated) { + this.whoCreated = whoCreated; + } + + public User getWhoModified() { + return whoModified; + } + + public void setWhoModified(User whoModified) { + this.whoModified = whoModified; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +}