diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/generatedproperty/GeneratedInsertJavaTime.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/generatedproperty/GeneratedInsertJavaTime.java new file mode 100644 index 000000000..97c1bf8aa --- /dev/null +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/generatedproperty/GeneratedInsertJavaTime.java @@ -0,0 +1,78 @@ +package com.avaje.ebeaninternal.server.deploy.generatedproperty; + +import com.avaje.ebean.bean.EntityBean; +import com.avaje.ebeaninternal.server.deploy.BeanProperty; + +import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import java.time.ZonedDateTime; + +/** + * Support java.time types as GeneratedProperty. + */ +public class GeneratedInsertJavaTime { + + public static abstract class Base implements GeneratedProperty { + + @Override + public boolean includeInUpdate() { + return false; + } + + @Override + public boolean includeInAllUpdates() { + return false; + } + + @Override + public boolean includeInInsert() { + return true; + } + + @Override + public boolean isDDLNotNullable() { + return true; + } + + @Override + public Object getUpdateValue(BeanProperty prop, EntityBean bean) { + return prop.getValue(bean); + } + } + + /** + * LocalDateTime support. + */ + public static class LocalDT extends Base { + + @Override + public Object getInsertValue(BeanProperty prop, EntityBean bean) { + return LocalDateTime.now(); + } + } + + /** + * OffsetDateTime support. + */ + public static class OffsetDT extends Base { + + @Override + public Object getInsertValue(BeanProperty prop, EntityBean bean) { + return OffsetDateTime.now(); + } + + } + + /** + * ZonedDateTime support. + */ + public static class ZonedDT extends Base { + + @Override + public Object getInsertValue(BeanProperty prop, EntityBean bean) { + return ZonedDateTime.now(); + } + + } + +} diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/generatedproperty/GeneratedUpdateJavaTime.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/generatedproperty/GeneratedUpdateJavaTime.java new file mode 100644 index 000000000..08909c245 --- /dev/null +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/generatedproperty/GeneratedUpdateJavaTime.java @@ -0,0 +1,86 @@ +package com.avaje.ebeaninternal.server.deploy.generatedproperty; + +import com.avaje.ebean.bean.EntityBean; +import com.avaje.ebeaninternal.server.deploy.BeanProperty; + +import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import java.time.ZonedDateTime; + +/** + * Support java.time DateTime types as GeneratedProperty. + */ +public class GeneratedUpdateJavaTime { + + public static abstract class Base implements GeneratedProperty { + + @Override + public boolean includeInUpdate() { + return true; + } + + @Override + public boolean includeInAllUpdates() { + return true; + } + + @Override + public boolean includeInInsert() { + return true; + } + + @Override + public boolean isDDLNotNullable() { + return true; + } + } + + /** + * LocalDateTime support. + */ + public static class LocalDT extends Base { + + @Override + public Object getInsertValue(BeanProperty prop, EntityBean bean) { + return LocalDateTime.now(); + } + + @Override + public Object getUpdateValue(BeanProperty prop, EntityBean bean) { + return LocalDateTime.now(); + } + } + + /** + * OffsetDateTime support. + */ + public static class OffsetDT extends Base { + + @Override + public Object getInsertValue(BeanProperty prop, EntityBean bean) { + return OffsetDateTime.now(); + } + + @Override + public Object getUpdateValue(BeanProperty prop, EntityBean bean) { + return OffsetDateTime.now(); + } + } + + /** + * ZonedDateTime support. + */ + public static class ZonedDT extends Base { + + @Override + public Object getInsertValue(BeanProperty prop, EntityBean bean) { + return ZonedDateTime.now(); + } + + @Override + public Object getUpdateValue(BeanProperty prop, EntityBean bean) { + return ZonedDateTime.now(); + } + } + +} diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/generatedproperty/InsertTimestampFactory.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/generatedproperty/InsertTimestampFactory.java index 2c50fba1b..94a7d60e4 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/generatedproperty/InsertTimestampFactory.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/generatedproperty/InsertTimestampFactory.java @@ -1,9 +1,15 @@ package com.avaje.ebeaninternal.server.deploy.generatedproperty; import java.sql.Timestamp; +import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import java.time.ZonedDateTime; +import java.util.HashMap; +import java.util.Map; import javax.persistence.PersistenceException; +import com.avaje.ebeaninternal.api.ClassUtil; import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty; /** @@ -11,12 +17,23 @@ import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty; */ public class InsertTimestampFactory { - final GeneratedInsertTimestamp timestamp = new GeneratedInsertTimestamp(); - - final GeneratedInsertDate utilDate = new GeneratedInsertDate(); - final GeneratedInsertLong longTime = new GeneratedInsertLong(); + Map, GeneratedProperty> map = new HashMap, GeneratedProperty>(); + + public InsertTimestampFactory() { + map.put(Timestamp.class, new GeneratedInsertTimestamp()); + map.put(java.util.Date.class, new GeneratedInsertDate()); + map.put(Long.class, longTime); + map.put(long.class, longTime); + + if (ClassUtil.isPresent("java.time.LocalDate", this.getClass())) { + map.put(LocalDateTime.class, new GeneratedInsertJavaTime.LocalDT()); + map.put(OffsetDateTime.class, new GeneratedInsertJavaTime.OffsetDT()); + map.put(ZonedDateTime.class, new GeneratedInsertJavaTime.ZonedDT()); + } + } + public void setInsertTimestamp(DeployBeanProperty property) { property.setGeneratedProperty(createInsertTimestamp(property)); @@ -28,20 +45,12 @@ public class InsertTimestampFactory { public GeneratedProperty createInsertTimestamp(DeployBeanProperty property) { Class propType = property.getPropertyType(); - if (propType.equals(Timestamp.class)) { - return timestamp; - } - if (propType.equals(java.util.Date.class)) { - return utilDate; - } - if (propType.equals(Long.class) || propType.equals(long.class)) { - return longTime; - } - - //TODO: Support JODA Time objects ... perhaps others? - - String msg = "Generated Insert Timestamp not supported on "+propType.getName(); - throw new PersistenceException(msg); + GeneratedProperty generatedProperty = map.get(propType); + if (generatedProperty != null) { + return generatedProperty; + } + + throw new PersistenceException("Generated Insert Timestamp not supported on "+propType.getName()); } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/generatedproperty/UpdateTimestampFactory.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/generatedproperty/UpdateTimestampFactory.java index 0606d628b..cf5add732 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/generatedproperty/UpdateTimestampFactory.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/generatedproperty/UpdateTimestampFactory.java @@ -1,9 +1,15 @@ package com.avaje.ebeaninternal.server.deploy.generatedproperty; import java.sql.Timestamp; +import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import java.time.ZonedDateTime; +import java.util.HashMap; +import java.util.Map; import javax.persistence.PersistenceException; +import com.avaje.ebeaninternal.api.ClassUtil; import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty; /** @@ -11,12 +17,23 @@ import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty; */ public class UpdateTimestampFactory { - final GeneratedUpdateTimestamp timestamp = new GeneratedUpdateTimestamp(); - - final GeneratedUpdateDate utilDate = new GeneratedUpdateDate(); - final GeneratedUpdateLong longTime = new GeneratedUpdateLong(); + Map, GeneratedProperty> map = new HashMap, GeneratedProperty>(); + + public UpdateTimestampFactory() { + map.put(Timestamp.class, new GeneratedUpdateTimestamp()); + map.put(java.util.Date.class, new GeneratedUpdateDate()); + map.put(Long.class, longTime); + map.put(long.class, longTime); + + if (ClassUtil.isPresent("java.time.LocalDate", this.getClass())) { + map.put(LocalDateTime.class, new GeneratedUpdateJavaTime.LocalDT()); + map.put(OffsetDateTime.class, new GeneratedUpdateJavaTime.OffsetDT()); + map.put(ZonedDateTime.class, new GeneratedUpdateJavaTime.ZonedDT()); + } + } + public void setUpdateTimestamp(DeployBeanProperty property) { property.setGeneratedProperty(createUpdateTimestamp(property)); @@ -25,23 +42,15 @@ public class UpdateTimestampFactory { /** * Create the update GeneratedProperty depending on the property type. */ - private GeneratedProperty createUpdateTimestamp(DeployBeanProperty property) { - - Class propType = property.getPropertyType(); - if (propType.equals(Timestamp.class)) { - return timestamp; - } - if (propType.equals(java.util.Date.class)) { - return utilDate; - } - if (propType.equals(Long.class) || propType.equals(long.class)) { - return longTime; - } - - //TODO: Support JODA Time objects ... perhaps others? - - String msg = "Generated update Timestamp not supported on "+propType.getName(); - throw new PersistenceException(msg); + protected GeneratedProperty createUpdateTimestamp(DeployBeanProperty property) { + + Class propType = property.getPropertyType(); + GeneratedProperty generatedProperty = map.get(propType); + if (generatedProperty != null) { + return generatedProperty; + } + + throw new PersistenceException("Generated update Timestamp not supported on "+propType.getName()); } } diff --git a/src/test/java/com/avaje/ebeaninternal/server/deploy/generatedproperty/InsertTimestampFactoryTest.java b/src/test/java/com/avaje/ebeaninternal/server/deploy/generatedproperty/InsertTimestampFactoryTest.java new file mode 100644 index 000000000..8aca43860 --- /dev/null +++ b/src/test/java/com/avaje/ebeaninternal/server/deploy/generatedproperty/InsertTimestampFactoryTest.java @@ -0,0 +1,56 @@ +package com.avaje.ebeaninternal.server.deploy.generatedproperty; + +import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty; +import org.junit.Test; + +import java.sql.Timestamp; +import java.time.LocalDateTime; +import java.time.OffsetDateTime; + +import static org.junit.Assert.*; + +public class InsertTimestampFactoryTest { + + InsertTimestampFactory factory = new InsertTimestampFactory(); + + @Test + public void test_createdTimestamp_LocalDateTime() { + + DeployBeanProperty prop = new DeployBeanProperty(null, LocalDateTime.class, null, null); + + GeneratedProperty insertTimestamp = factory.createInsertTimestamp(prop); + Object value = insertTimestamp.getInsertValue(null, null); + assertTrue(value instanceof LocalDateTime); + } + + @Test + public void test_createdTimestamp_OffsetDateTime() { + + DeployBeanProperty prop = new DeployBeanProperty(null, OffsetDateTime.class, null, null); + + GeneratedProperty insertTimestamp = factory.createInsertTimestamp(prop); + Object value = insertTimestamp.getInsertValue(null, null); + assertTrue(value instanceof OffsetDateTime); + } + + @Test + public void test_createdTimestamp_Timestamp() { + + DeployBeanProperty prop = new DeployBeanProperty(null, Timestamp.class, null, null); + + GeneratedProperty insertTimestamp = factory.createInsertTimestamp(prop); + Object value = insertTimestamp.getInsertValue(null, null); + assertTrue(value instanceof Timestamp); + } + + @Test + public void test_createdTimestamp_utilDate() { + + DeployBeanProperty prop = new DeployBeanProperty(null, java.util.Date.class, null, null); + + GeneratedProperty insertTimestamp = factory.createInsertTimestamp(prop); + Object value = insertTimestamp.getInsertValue(null, null); + assertTrue(value instanceof java.util.Date); + } + +} \ No newline at end of file diff --git a/src/test/java/com/avaje/ebeaninternal/server/deploy/generatedproperty/UpdateTimestampFactoryTest.java b/src/test/java/com/avaje/ebeaninternal/server/deploy/generatedproperty/UpdateTimestampFactoryTest.java new file mode 100644 index 000000000..f861efe63 --- /dev/null +++ b/src/test/java/com/avaje/ebeaninternal/server/deploy/generatedproperty/UpdateTimestampFactoryTest.java @@ -0,0 +1,56 @@ +package com.avaje.ebeaninternal.server.deploy.generatedproperty; + +import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty; +import org.junit.Test; + +import java.sql.Timestamp; +import java.time.LocalDateTime; +import java.time.OffsetDateTime; + +import static org.junit.Assert.*; + +public class UpdateTimestampFactoryTest { + + + UpdateTimestampFactory factory = new UpdateTimestampFactory(); + + @Test + public void test_createdTimestamp_LocalDateTime() { + + DeployBeanProperty prop = new DeployBeanProperty(null, LocalDateTime.class, null, null); + + GeneratedProperty generatedProperty = factory.createUpdateTimestamp(prop); + Object value = generatedProperty.getInsertValue(null, null); + assertTrue(value instanceof LocalDateTime); + } + + @Test + public void test_createdTimestamp_OffsetDateTime() { + + DeployBeanProperty prop = new DeployBeanProperty(null, OffsetDateTime.class, null, null); + + GeneratedProperty generatedProperty = factory.createUpdateTimestamp(prop); + Object value = generatedProperty.getInsertValue(null, null); + assertTrue(value instanceof OffsetDateTime); + } + + @Test + public void test_createdTimestamp_Timestamp() { + + DeployBeanProperty prop = new DeployBeanProperty(null, Timestamp.class, null, null); + + GeneratedProperty generatedProperty = factory.createUpdateTimestamp(prop); + Object value = generatedProperty.getInsertValue(null, null); + assertTrue(value instanceof Timestamp); + } + + @Test + public void test_createdTimestamp_utilDate() { + + DeployBeanProperty prop = new DeployBeanProperty(null, java.util.Date.class, null, null); + + GeneratedProperty generatedProperty = factory.createUpdateTimestamp(prop); + Object value = generatedProperty.getInsertValue(null, null); + assertTrue(value instanceof java.util.Date); + } +} \ No newline at end of file diff --git a/src/test/java/com/avaje/tests/generated/TestGeneratedProperties.java b/src/test/java/com/avaje/tests/generated/TestGeneratedProperties.java new file mode 100644 index 000000000..a27858dd5 --- /dev/null +++ b/src/test/java/com/avaje/tests/generated/TestGeneratedProperties.java @@ -0,0 +1,37 @@ +package com.avaje.tests.generated; + +import com.avaje.ebean.BaseTestCase; +import com.avaje.ebean.Ebean; +import com.avaje.tests.model.EGenProps; +import org.junit.Test; + +import static org.junit.Assert.assertNotNull; + +public class TestGeneratedProperties extends BaseTestCase { + + @Test + public void test_insert() { + + EGenProps bean = new EGenProps(); + bean.setName("inserting"); + Ebean.save(bean); + + assertNotNull(bean.getId()); + assertNotNull(bean.getVersion()); + assertNotNull(bean.getTsCreated()); + assertNotNull(bean.getTsUpdated()); + assertNotNull(bean.getLdtCreated()); + assertNotNull(bean.getLdtUpdated()); + assertNotNull(bean.getOdtCreated()); + assertNotNull(bean.getOdtUpdated()); + assertNotNull(bean.getZdtCreated()); + assertNotNull(bean.getZdtUpdated()); + assertNotNull(bean.getLongCreated()); + assertNotNull(bean.getLongUpdated()); + + bean.setName("updating..."); + Ebean.save(bean); + + Ebean.delete(bean); + } +} diff --git a/src/test/java/com/avaje/tests/model/EGenProps.java b/src/test/java/com/avaje/tests/model/EGenProps.java new file mode 100644 index 000000000..579af2754 --- /dev/null +++ b/src/test/java/com/avaje/tests/model/EGenProps.java @@ -0,0 +1,158 @@ +package com.avaje.tests.model; + +import com.avaje.ebean.annotation.CreatedTimestamp; +import com.avaje.ebean.annotation.UpdatedTimestamp; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Version; +import java.sql.Timestamp; +import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import java.time.ZonedDateTime; + +@Entity +public class EGenProps { + + @Id + Long id; + + String name; + + @Version + Long version; + + @CreatedTimestamp + Timestamp tsCreated; + + @UpdatedTimestamp + Timestamp tsUpdated; + + @CreatedTimestamp + LocalDateTime ldtCreated; + + @UpdatedTimestamp + LocalDateTime ldtUpdated; + + @CreatedTimestamp + OffsetDateTime odtCreated; + + @UpdatedTimestamp + OffsetDateTime odtUpdated; + + @CreatedTimestamp + ZonedDateTime zdtCreated; + + @UpdatedTimestamp + ZonedDateTime zdtUpdated; + + @CreatedTimestamp + long longCreated; + + @UpdatedTimestamp + long longUpdated; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Long getVersion() { + return version; + } + + public void setVersion(Long version) { + this.version = version; + } + + public Timestamp getTsCreated() { + return tsCreated; + } + + public void setTsCreated(Timestamp tsCreated) { + this.tsCreated = tsCreated; + } + + public Timestamp getTsUpdated() { + return tsUpdated; + } + + public void setTsUpdated(Timestamp tsUpdated) { + this.tsUpdated = tsUpdated; + } + + public LocalDateTime getLdtCreated() { + return ldtCreated; + } + + public void setLdtCreated(LocalDateTime ldtCreated) { + this.ldtCreated = ldtCreated; + } + + public LocalDateTime getLdtUpdated() { + return ldtUpdated; + } + + public void setLdtUpdated(LocalDateTime ldtUpdated) { + this.ldtUpdated = ldtUpdated; + } + + public OffsetDateTime getOdtCreated() { + return odtCreated; + } + + public void setOdtCreated(OffsetDateTime odtCreated) { + this.odtCreated = odtCreated; + } + + public OffsetDateTime getOdtUpdated() { + return odtUpdated; + } + + public void setOdtUpdated(OffsetDateTime odtUpdated) { + this.odtUpdated = odtUpdated; + } + + public ZonedDateTime getZdtCreated() { + return zdtCreated; + } + + public void setZdtCreated(ZonedDateTime zdtCreated) { + this.zdtCreated = zdtCreated; + } + + public ZonedDateTime getZdtUpdated() { + return zdtUpdated; + } + + public void setZdtUpdated(ZonedDateTime zdtUpdated) { + this.zdtUpdated = zdtUpdated; + } + + public long getLongCreated() { + return longCreated; + } + + public void setLongCreated(long longCreated) { + this.longCreated = longCreated; + } + + public long getLongUpdated() { + return longUpdated; + } + + public void setLongUpdated(long longUpdated) { + this.longUpdated = longUpdated; + } +}