From 33ab7eb7a5057e86f66c74e2d7bffcee115ca75a Mon Sep 17 00:00:00 2001 From: rbygrave Date: Thu, 13 Nov 2014 23:13:51 +1300 Subject: [PATCH 01/10] Add ScalarTypeLocalDate --- .../server/type/DefaultTypeManager.java | 11 ++++ .../server/type/ScalarTypeLocalDate.java | 56 +++++++++++++++++ .../server/type/ScalarTypeLocalDateTime.java | 44 +++++++++++++ .../server/type/ScalarTypeOffsetDateTime.java | 43 +++++++++++++ .../server/type/ScalarTypeLocalDateTest.java | 50 +++++++++++++++ .../type/ScalarTypeLocalDateTimeTest.java | 58 +++++++++++++++++ .../type/ScalarTypeOffsetDateTimeTest.java | 62 +++++++++++++++++++ 7 files changed, 324 insertions(+) create mode 100644 src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalDate.java create mode 100644 src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalDateTime.java create mode 100644 src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeOffsetDateTime.java create mode 100644 src/test/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalDateTest.java create mode 100644 src/test/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalDateTimeTest.java create mode 100644 src/test/java/com/avaje/ebeaninternal/server/type/ScalarTypeOffsetDateTimeTest.java diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/DefaultTypeManager.java b/src/main/java/com/avaje/ebeaninternal/server/type/DefaultTypeManager.java index 9eed017de..bbff03a0c 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/DefaultTypeManager.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/DefaultTypeManager.java @@ -10,6 +10,7 @@ import java.sql.Date; import java.sql.Time; import java.sql.Timestamp; import java.sql.Types; +import java.time.OffsetDateTime; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; @@ -146,6 +147,7 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable { this.extraTypeFactory = new DefaultTypeFactory(config); initialiseStandard(clobType, blobType, config.isUuidStoreAsBinary()); + initialiseJavaTimeTypes(); initialiseJodaTypes(); if (bootupClasses != null) { @@ -602,6 +604,15 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable { return propParamTypes[1]; } + protected void initialiseJavaTimeTypes() { + if (ClassUtil.isPresent("java.time.LocalDate", this.getClass())) { + logger.debug("Registering java.time data types"); + typeMap.put(java.time.LocalDate.class, new ScalarTypeLocalDate()); + typeMap.put(java.time.LocalDateTime.class, new ScalarTypeLocalDateTime()); + typeMap.put(OffsetDateTime.class, new ScalarTypeOffsetDateTime()); + } + } + /** * Detect if Joda classes are in the classpath and if so register the Joda * data types. diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalDate.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalDate.java new file mode 100644 index 000000000..58685ff8c --- /dev/null +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalDate.java @@ -0,0 +1,56 @@ +package com.avaje.ebeaninternal.server.type; + +import com.avaje.ebeaninternal.server.core.BasicTypeConverter; + +import java.sql.Date; +import java.sql.Timestamp; +import java.sql.Types; +import java.time.LocalDate; + +/** + * ScalarType for java.time.LocalDate. This maps to a JDBC Date. + */ +public class ScalarTypeLocalDate extends ScalarTypeBaseDate { + + public ScalarTypeLocalDate() { + super(LocalDate.class, false, Types.DATE); + } + + @Override + public long convertToMillis(Object value) { + return convertToDate((LocalDate) value).toInstant().toEpochMilli(); + } + + @Override + public LocalDate convertFromDate(Date ts) { + return ts.toLocalDate(); + } + + @Override + public Date convertToDate(LocalDate t) { + return Date.valueOf(t); + } + + @Override + public Object toJdbcType(Object value) { + if (value instanceof LocalDate) { + return Date.valueOf((LocalDate) value); + } + return BasicTypeConverter.toDate(value); + } + + @Override + public LocalDate toBeanType(Object value) { + if (value instanceof java.sql.Date) { + return ((java.sql.Date) value).toLocalDate(); + } + return (LocalDate) value; + } + + @Override + public LocalDate parseDateTime(long systemTimeMillis) { + return new Timestamp(systemTimeMillis).toLocalDateTime().toLocalDate(); + } + + +} diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalDateTime.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalDateTime.java new file mode 100644 index 000000000..3a937910b --- /dev/null +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalDateTime.java @@ -0,0 +1,44 @@ +package com.avaje.ebeaninternal.server.type; + +import java.sql.Timestamp; +import java.sql.Types; +import java.time.*; + +/** + * ScalarType for java.sql.Timestamp. + */ +public class ScalarTypeLocalDateTime extends ScalarTypeBaseDateTime { + + public ScalarTypeLocalDateTime() { + super(LocalDateTime.class, true, Types.TIMESTAMP); + } + + @Override + public long convertToMillis(Object value) { + return ((LocalDateTime) value).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(); + } + + @Override + public LocalDateTime convertFromTimestamp(Timestamp ts) { + return ts.toLocalDateTime(); + } + + @Override + public Timestamp convertToTimestamp(LocalDateTime t) { + + ZonedDateTime zonedDateTime = t.atZone(ZoneId.systemDefault()); + return Timestamp.from(zonedDateTime.toInstant()); + } + + @Override + public Object toJdbcType(Object value) { + if (value instanceof Timestamp) return value; + return convertToTimestamp((LocalDateTime)value); + } + + @Override + public LocalDateTime toBeanType(Object value) { + if (value instanceof LocalDateTime) return (LocalDateTime)value; + return convertFromTimestamp((Timestamp)value); + } +} diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeOffsetDateTime.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeOffsetDateTime.java new file mode 100644 index 000000000..8fc004792 --- /dev/null +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeOffsetDateTime.java @@ -0,0 +1,43 @@ +package com.avaje.ebeaninternal.server.type; + +import java.sql.Timestamp; +import java.sql.Types; +import java.time.OffsetDateTime; +import java.time.ZoneId; + +/** + * ScalarType for java.sql.Timestamp. + */ +public class ScalarTypeOffsetDateTime extends ScalarTypeBaseDateTime { + + public ScalarTypeOffsetDateTime() { + super(OffsetDateTime.class, true, Types.TIMESTAMP); + } + + @Override + public long convertToMillis(Object value) { + return ((OffsetDateTime) value).toInstant().toEpochMilli(); + } + + @Override + public OffsetDateTime convertFromTimestamp(Timestamp ts) { + return OffsetDateTime.ofInstant(ts.toInstant(), ZoneId.systemDefault()); + } + + @Override + public Timestamp convertToTimestamp(OffsetDateTime t) { + return Timestamp.from(t.toInstant()); + } + + @Override + public Object toJdbcType(Object value) { + if (value instanceof Timestamp) return value; + return convertToTimestamp((OffsetDateTime)value); + } + + @Override + public OffsetDateTime toBeanType(Object value) { + if (value instanceof OffsetDateTime) return (OffsetDateTime) value; + return convertFromTimestamp((Timestamp)value); + } +} diff --git a/src/test/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalDateTest.java b/src/test/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalDateTest.java new file mode 100644 index 000000000..73b48161e --- /dev/null +++ b/src/test/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalDateTest.java @@ -0,0 +1,50 @@ +package com.avaje.ebeaninternal.server.type; + +import org.junit.Test; + +import java.time.LocalDate; + +import static org.junit.Assert.*; + +public class ScalarTypeLocalDateTest { + + ScalarTypeLocalDate type = new ScalarTypeLocalDate(); + + @Test + public void testConvertToMillis() throws Exception { + + LocalDate date = LocalDate.of(2014, 5, 20); + long millis = type.convertToMillis(date); + + System.out.println(date); + + LocalDate parseDate = type.parseDateTime(millis); + + assertEquals(date, parseDate); + } + + @Test + public void testConvertFromDate() throws Exception { + + } + + @Test + public void testConvertToDate() throws Exception { + + } + + @Test + public void testToJdbcType() throws Exception { + + } + + @Test + public void testToBeanType() throws Exception { + + } + + @Test + public void testParseDateTime() throws Exception { + + } +} \ No newline at end of file diff --git a/src/test/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalDateTimeTest.java b/src/test/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalDateTimeTest.java new file mode 100644 index 000000000..492ee9b42 --- /dev/null +++ b/src/test/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalDateTimeTest.java @@ -0,0 +1,58 @@ +package com.avaje.ebeaninternal.server.type; + +import org.junit.Test; + +import java.sql.Timestamp; +import java.time.LocalDateTime; + +import static org.junit.Assert.*; + +public class ScalarTypeLocalDateTimeTest { + + ScalarTypeLocalDateTime type = new ScalarTypeLocalDateTime(); + + // warm up + LocalDateTime warmUp = LocalDateTime.now(); + + @Test + public void testConvertToMillis() throws Exception { + + warmUp.hashCode(); + + long now = System.currentTimeMillis(); + long toMillis = type.convertToMillis( LocalDateTime.now()); + + assertTrue(toMillis - now < 10); + } + + @Test + public void testConvertFromTimestamp() throws Exception { + + Timestamp now = new Timestamp(System.currentTimeMillis()); + + LocalDateTime localDateTime = type.convertFromTimestamp(now); + Timestamp timestamp = type.convertToTimestamp(localDateTime); + + assertEquals(now, timestamp); + } + + + @Test + public void testToJdbcType() throws Exception { + + Object jdbcType = type.toJdbcType(LocalDateTime.now()); + assertTrue(jdbcType instanceof Timestamp); + } + + @Test + public void testToBeanType() throws Exception { + + Timestamp timestamp = new Timestamp(System.currentTimeMillis()); + LocalDateTime localDateTime = type.toBeanType(timestamp); + + assertNotNull(localDateTime); + + Timestamp timestamp1 = type.convertToTimestamp(localDateTime); + assertEquals(timestamp, timestamp1); + } +} \ No newline at end of file diff --git a/src/test/java/com/avaje/ebeaninternal/server/type/ScalarTypeOffsetDateTimeTest.java b/src/test/java/com/avaje/ebeaninternal/server/type/ScalarTypeOffsetDateTimeTest.java new file mode 100644 index 000000000..50e0a5565 --- /dev/null +++ b/src/test/java/com/avaje/ebeaninternal/server/type/ScalarTypeOffsetDateTimeTest.java @@ -0,0 +1,62 @@ +package com.avaje.ebeaninternal.server.type; + +import org.junit.Test; + +import java.sql.Timestamp; +import java.time.LocalDateTime; +import java.time.OffsetDateTime; + +import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; + +public class ScalarTypeOffsetDateTimeTest { + + + ScalarTypeOffsetDateTime type = new ScalarTypeOffsetDateTime(); + + OffsetDateTime warmUp = OffsetDateTime.now(); + + @Test + public void testConvertToMillis() throws Exception { + + warmUp.hashCode(); + + long now = System.currentTimeMillis(); + long toMillis = type.convertToMillis( OffsetDateTime.now()); + + assertTrue(toMillis - now < 10); + + } + + @Test + public void testConvertFromTimestamp() throws Exception { + + Timestamp now = new Timestamp(System.currentTimeMillis()); + + OffsetDateTime localDateTime = type.convertFromTimestamp(now); + Timestamp timestamp = type.convertToTimestamp(localDateTime); + + assertEquals(now, timestamp); + } + + + @Test + public void testToJdbcType() throws Exception { + + Object jdbcType = type.toJdbcType(OffsetDateTime.now()); + assertTrue(jdbcType instanceof Timestamp); + } + + @Test + public void testToBeanType() throws Exception { + + Timestamp timestamp = new Timestamp(System.currentTimeMillis()); + OffsetDateTime localDateTime = type.toBeanType(timestamp); + + assertNotNull(localDateTime); + + Timestamp timestamp1 = type.convertToTimestamp(localDateTime); + assertEquals(timestamp, timestamp1); + + } +} \ No newline at end of file From 641385aab5749fd073c9811caea95ac7224abb8c Mon Sep 17 00:00:00 2001 From: rbygrave Date: Fri, 14 Nov 2014 01:01:32 +1300 Subject: [PATCH 02/10] ScalarTypeLocalDate update - some test ordering issues --- pom.xml | 2 +- .../server/type/ScalarTypeLocalDate.java | 6 +- .../server/type/ScalarTypeLocalDateTest.java | 26 ++++--- .../tests/basic/TestBeanReferenceRefresh.java | 8 ++- .../com/avaje/tests/basic/TestInheritRef.java | 67 +++++++++++-------- .../tests/cache/TestQueryCacheCountry.java | 15 +++-- .../joins/TestDisjunctWhereOuterJoin.java | 67 ++++++++++--------- 7 files changed, 113 insertions(+), 78 deletions(-) diff --git a/pom.xml b/pom.xml index cc87439f7..862022012 100644 --- a/pom.xml +++ b/pom.xml @@ -182,7 +182,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.1 + 3.2 1.6 1.6 diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalDate.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalDate.java index 58685ff8c..d69073fee 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalDate.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalDate.java @@ -6,6 +6,8 @@ import java.sql.Date; import java.sql.Timestamp; import java.sql.Types; import java.time.LocalDate; +import java.time.ZoneId; +import java.time.ZonedDateTime; /** * ScalarType for java.time.LocalDate. This maps to a JDBC Date. @@ -18,7 +20,9 @@ public class ScalarTypeLocalDate extends ScalarTypeBaseDate { @Override public long convertToMillis(Object value) { - return convertToDate((LocalDate) value).toInstant().toEpochMilli(); + LocalDate localDate = (LocalDate) value; + ZonedDateTime zonedDateTime = localDate.atStartOfDay(ZoneId.systemDefault()); + return zonedDateTime.toInstant().toEpochMilli(); } @Override diff --git a/src/test/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalDateTest.java b/src/test/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalDateTest.java index 73b48161e..f1e0a0082 100644 --- a/src/test/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalDateTest.java +++ b/src/test/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalDateTest.java @@ -2,6 +2,7 @@ package com.avaje.ebeaninternal.server.type; import org.junit.Test; +import java.sql.Date; import java.time.LocalDate; import static org.junit.Assert.*; @@ -19,32 +20,39 @@ public class ScalarTypeLocalDateTest { System.out.println(date); LocalDate parseDate = type.parseDateTime(millis); - assertEquals(date, parseDate); } @Test public void testConvertFromDate() throws Exception { + LocalDate localDate = LocalDate.now(); + Date date = Date.valueOf(localDate); + + LocalDate localDate1 = type.convertFromDate(date); + assertEquals(localDate, localDate1); + + Date date1 = type.convertToDate(localDate); + assertEquals(date, date1); } - @Test - public void testConvertToDate() throws Exception { - - } @Test public void testToJdbcType() throws Exception { + LocalDate localDate = LocalDate.now(); + Object o = type.toJdbcType(localDate); + assertTrue(o instanceof Date); } @Test public void testToBeanType() throws Exception { + LocalDate localDate = LocalDate.now(); + Date date = Date.valueOf(localDate); + + LocalDate localDate1 = type.toBeanType(date); + assertEquals(localDate, localDate1); } - @Test - public void testParseDateTime() throws Exception { - - } } \ No newline at end of file diff --git a/src/test/java/com/avaje/tests/basic/TestBeanReferenceRefresh.java b/src/test/java/com/avaje/tests/basic/TestBeanReferenceRefresh.java index 98daf7776..1f85d168a 100644 --- a/src/test/java/com/avaje/tests/basic/TestBeanReferenceRefresh.java +++ b/src/test/java/com/avaje/tests/basic/TestBeanReferenceRefresh.java @@ -2,6 +2,7 @@ package com.avaje.tests.basic; import java.sql.Date; +import com.avaje.ebean.cache.ServerCache; import org.junit.Assert; import org.junit.Test; @@ -18,8 +19,11 @@ public class TestBeanReferenceRefresh extends BaseTestCase { public void testMe() { ResetBasicData.reset(); - - Order order = Ebean.getReference(Order.class, 1); + + ServerCache beanCache = Ebean.getServerCacheManager().getBeanCache(Order.class); + beanCache.clear(); + + Order order = Ebean.getReference(Order.class, 1); Assert.assertTrue(Ebean.getBeanState(order).isReference()); diff --git a/src/test/java/com/avaje/tests/basic/TestInheritRef.java b/src/test/java/com/avaje/tests/basic/TestInheritRef.java index 2604d61c8..368d7c2c8 100644 --- a/src/test/java/com/avaje/tests/basic/TestInheritRef.java +++ b/src/test/java/com/avaje/tests/basic/TestInheritRef.java @@ -15,32 +15,45 @@ public class TestInheritRef extends BaseTestCase { @Test public void testAssocOne() { - - Ebean.createUpdate(Vehicle.class, "delete from vehicle"); - Car c = new Car(); - c.setLicenseNumber("C6788"); - c.setDriver("CarDriver"); - Ebean.save(c); - - Truck t = new Truck(); - t.setLicenseNumber("T1098"); - t.setCapacity(20D); - Ebean.save(t); - - List list = Ebean.find(Vehicle.class) - .setAutofetch(false) - .findList(); - - Assert.assertTrue(list.size() > 0); - for (Vehicle vehicle : list) { - if (vehicle instanceof Truck){ - Truck truck = (Truck)vehicle; - Assert.assertTrue(truck.getLicenseNumber().equals("T1098")); - Assert.assertTrue(truck.getCapacity() == 20D); - - } - } - - } + Ebean.beginTransaction(); + try { + Ebean.createUpdate(Vehicle.class, "delete from vehicle"); + + Car c = new Car(); + c.setLicenseNumber("C6788"); + c.setDriver("CarDriver"); + Ebean.save(c); + + Truck t = new Truck(); + t.setLicenseNumber("T1098BBX"); + t.setCapacity(20D); + Ebean.save(t); + + List list = Ebean.find(Vehicle.class) + .setAutofetch(false) + .findList(); + + Assert.assertTrue(list.size() > 0); + + Truck foundTruck = null; + int found = 0; + + for (Vehicle vehicle : list) { + if (vehicle instanceof Truck) { + Truck truck = (Truck) vehicle; + if ("T1098BBX".equals(truck.getLicenseNumber())) { + found++; + foundTruck = truck; + } + } + } + + Assert.assertEquals(1, found); + Assert.assertTrue(foundTruck.getCapacity() == 20D); + + } finally { + Ebean.rollbackTransaction(); + } + } } diff --git a/src/test/java/com/avaje/tests/cache/TestQueryCacheCountry.java b/src/test/java/com/avaje/tests/cache/TestQueryCacheCountry.java index d56c38cdf..c1350529c 100644 --- a/src/test/java/com/avaje/tests/cache/TestQueryCacheCountry.java +++ b/src/test/java/com/avaje/tests/cache/TestQueryCacheCountry.java @@ -19,17 +19,20 @@ public class TestQueryCacheCountry extends BaseTestCase { ResetBasicData.reset(); - ServerCache cache = Ebean.getServerCacheManager().getQueryCache(Country.class); - cache.clear(); + ServerCache queryCache = Ebean.getServerCacheManager().getQueryCache(Country.class); + queryCache.clear(); - Assert.assertEquals(0, cache.getStatistics(false).getSize()); + ServerCache beanCache = Ebean.getServerCacheManager().getBeanCache(Country.class); + beanCache.clear(); + + Assert.assertEquals(0, queryCache.getStatistics(false).getSize()); List countryList0 = Ebean.find(Country.class) .setUseQueryCache(true) .order().asc("name") .findList(); - Assert.assertEquals(1, cache.getStatistics(false).getSize()); + Assert.assertEquals(1, queryCache.getStatistics(false).getSize()); Assert.assertTrue(countryList0.size() > 0); List countryList1 = Ebean.find(Country.class) @@ -37,7 +40,7 @@ public class TestQueryCacheCountry extends BaseTestCase { .order().asc("name") .findList(); - ServerCacheStatistics statistics = cache.getStatistics(false); + ServerCacheStatistics statistics = queryCache.getStatistics(false); Assert.assertEquals(1, statistics.getSize()); Assert.assertEquals(1, statistics.getHitCount()); Assert.assertSame(countryList1, countryList0); @@ -46,7 +49,7 @@ public class TestQueryCacheCountry extends BaseTestCase { nz.setName("New Zealandia"); Ebean.save(nz); - statistics = cache.getStatistics(false); + statistics = queryCache.getStatistics(false); Assert.assertEquals(0, statistics.getSize()); List countryList2 = Ebean.find(Country.class) diff --git a/src/test/java/com/avaje/tests/query/joins/TestDisjunctWhereOuterJoin.java b/src/test/java/com/avaje/tests/query/joins/TestDisjunctWhereOuterJoin.java index d46361f2d..797c71051 100644 --- a/src/test/java/com/avaje/tests/query/joins/TestDisjunctWhereOuterJoin.java +++ b/src/test/java/com/avaje/tests/query/joins/TestDisjunctWhereOuterJoin.java @@ -17,49 +17,52 @@ public class TestDisjunctWhereOuterJoin extends BaseTestCase { public void test() { Ebean.beginTransaction(); + try { - MRole r1 = new MRole(); - r1.setRoleName("role1"); - Ebean.save(r1); + MRole r1 = new MRole(); + r1.setRoleName("role1B"); + Ebean.save(r1); - MRole r2 = new MRole(); - r2.setRoleName("role2special"); - Ebean.save(r2); + MRole r2 = new MRole(); + r2.setRoleName("role2specialB"); + Ebean.save(r2); - MRole r3 = new MRole(); - r3.setRoleName("role3"); - Ebean.save(r3); + MRole r3 = new MRole(); + r3.setRoleName("role3B"); + Ebean.save(r3); - MUser u0 = new MUser(); - u0.setUserName("user0"); - u0.addRole(r1); - u0.addRole(r2); + MUser u0 = new MUser(); + u0.setUserName("user0B"); + u0.addRole(r1); + u0.addRole(r2); - Ebean.save(u0); + Ebean.save(u0); - MUser u1 = new MUser(); - u1.setUserName("user1"); - u1.addRole(r1); + MUser u1 = new MUser(); + u1.setUserName("user1B"); + u1.addRole(r1); - Ebean.save(u1); + Ebean.save(u1); - Ebean.commitTransaction(); - - Query query = Ebean.find(MUser.class) - .where().disjunction() - .eq("roles.roleName", "role2special") // user0 - .eq("roles.roleName", "role3") // nobody - .endJunction().query(); + Query query = Ebean.find(MUser.class) + .where().disjunction() + .eq("roles.roleName", "role2specialB") // user0 + .eq("roles.roleName", "role3B") // nobody + .endJunction().query(); - List list = query.findList(); - Assert.assertSame(1, list.size()); // list should contain user0 - System.out.println(list); + List list = query.findList(); + Assert.assertSame(1, list.size()); // list should contain user0 + System.out.println(list); - String sql = query.getGeneratedSql(); - Assert.assertTrue(sql.indexOf("select distinct") > -1); - Assert.assertTrue(sql.indexOf("outer join mrole ") > -1); - Assert.assertTrue(sql.indexOf(".role_name = ?") > -1); + String sql = query.getGeneratedSql(); + Assert.assertTrue(sql.indexOf("select distinct") > -1); + Assert.assertTrue(sql.indexOf("outer join mrole ") > -1); + Assert.assertTrue(sql.indexOf(".role_name = ?") > -1); + + } finally { + Ebean.rollbackTransaction(); + } } } From 4a882b537c3c5fffe49c01a4b4a69dc3fba300fd Mon Sep 17 00:00:00 2001 From: rbygrave Date: Fri, 14 Nov 2014 21:26:32 +1300 Subject: [PATCH 03/10] #197 - Add Query findEach() findEachWhile() ... as better method names for findVisit(). More consistent with forEach() methods --- .../java/com/avaje/ebean/EbeanServer.java | 24 ++++++ .../java/com/avaje/ebean/ExpressionList.java | 22 ++++- src/main/java/com/avaje/ebean/Model.java | 31 +++++++ src/main/java/com/avaje/ebean/Query.java | 82 +++++++++++++++---- .../com/avaje/ebean/QueryEachConsumer.java | 41 ++++++++++ .../avaje/ebean/QueryEachWhileConsumer.java | 45 ++++++++++ .../server/core/DefaultServer.java | 73 +++++++---------- .../server/core/OrmQueryRequest.java | 28 ++++++- .../server/core/SpiOrmQueryRequest.java | 14 +++- .../server/expression/JunctionExpression.java | 10 +++ .../server/querydefn/DefaultOrmQuery.java | 26 +++--- .../util/DefaultExpressionList.java | 24 +++--- .../avaje/tests/query/TestQueryFindEach.java | 67 +++++++++++++++ .../tests/query/TestQueryFindEachWhile.java | 69 ++++++++++++++++ 14 files changed, 461 insertions(+), 95 deletions(-) create mode 100644 src/main/java/com/avaje/ebean/QueryEachConsumer.java create mode 100644 src/main/java/com/avaje/ebean/QueryEachWhileConsumer.java create mode 100644 src/test/java/com/avaje/tests/query/TestQueryFindEach.java create mode 100644 src/test/java/com/avaje/tests/query/TestQueryFindEachWhile.java diff --git a/src/main/java/com/avaje/ebean/EbeanServer.java b/src/main/java/com/avaje/ebean/EbeanServer.java index 64bdcbed2..e730a4b35 100644 --- a/src/main/java/com/avaje/ebean/EbeanServer.java +++ b/src/main/java/com/avaje/ebean/EbeanServer.java @@ -457,6 +457,30 @@ public interface EbeanServer { * Execute the query visiting the results. This is similar to findIterate in * that not all the result beans need to be held in memory at the same time * and as such is go for processing large queries. + * + * @see Query#findEach(QueryEachConsumer) + */ + public void findEach(Query query, QueryEachConsumer consumer, Transaction transaction); + + /** + * Execute the query visiting the results. This is similar to findIterate in + * that not all the result beans need to be held in memory at the same time + * and as such is go for processing large queries. + * + * @see Query#findEachWhile(QueryEachWhileConsumer) + */ + public void findEachWhile(Query query, QueryEachWhileConsumer consumer, Transaction transaction); + + /** + * Deprecated in favor of #findEachWhile which is functionally exactly the same + * but has a much better name. + *

+ * Execute the query visiting the results. This is similar to findIterate in + * that not all the result beans need to be held in memory at the same time + * and as such is go for processing large queries. + *

+ * + * @deprecated */ public void findVisit(Query query, QueryResultVisitor visitor, Transaction transaction); diff --git a/src/main/java/com/avaje/ebean/ExpressionList.java b/src/main/java/com/avaje/ebean/ExpressionList.java index dee737d88..b991e3553 100644 --- a/src/main/java/com/avaje/ebean/ExpressionList.java +++ b/src/main/java/com/avaje/ebean/ExpressionList.java @@ -102,9 +102,25 @@ public interface ExpressionList extends Serializable { public QueryIterator findIterate(); /** - * Execute the query visiting the results. - * - * @see Query#findVisit(QueryResultVisitor) + * Execute the query process the beans one at a time. + * + * @see Query#findEach(QueryEachConsumer) + */ + public void findEach(QueryEachConsumer consumer); + + /** + * Execute the query processing the beans one at a time with the ability to + * stop processing before reading all the beans. + * + * @see Query#findEachWhile(QueryEachWhileConsumer) + */ + public void findEachWhile(QueryEachWhileConsumer consumer); + + /** + * Deprecated in favor of #findEachWhile which is functionally exactly the same + * but has a much better name. + * + * @deprecated */ public void findVisit(QueryResultVisitor visitor); diff --git a/src/main/java/com/avaje/ebean/Model.java b/src/main/java/com/avaje/ebean/Model.java index d57311474..0dfc9d44f 100644 --- a/src/main/java/com/avaje/ebean/Model.java +++ b/src/main/java/com/avaje/ebean/Model.java @@ -328,6 +328,37 @@ public abstract class Model { return query().findIds(); } + /** + * Execute the query consuming each bean one at a time. + *

+ * This is generally used to process large queries where unlike findList + * you do not want to hold all the results in memory at once but instead + * process them one at a time (requiring far less memory). + *

+ * Equivalent to {@link Query#findEach(QueryEachConsumer)} + */ + public void findEach(QueryEachConsumer consumer) { + query().findEach(consumer); + } + + /** + * Execute the query consuming each bean one at a time. + *

+ * This is similar to #findEach except that you return boolean + * true to continue processing beans and return false to stop + * processing early. + *

+ *

+ * This is generally used to process large queries where unlike findList + * you do not want to hold all the results in memory at once but instead + * process them one at a time (requiring far less memory). + *

+ * Equivalent to {@link Query#findEachWhile(QueryEachWhileConsumer)} + */ + public void findEachWhile(QueryEachWhileConsumer consumer) { + query().findEachWhile(consumer); + } + /** * Retrieves all entities of the given type. *

diff --git a/src/main/java/com/avaje/ebean/Query.java b/src/main/java/com/avaje/ebean/Query.java index 8110ac2cc..96fb71093 100644 --- a/src/main/java/com/avaje/ebean/Query.java +++ b/src/main/java/com/avaje/ebean/Query.java @@ -446,37 +446,89 @@ public interface Query extends Serializable { */ public QueryIterator findIterate(); + /** + * This is deprecated in favor of #findEachWhile. + *

+ * This is functionally exactly the same as #findEachWhile. It is + * replaced by findEachWhile because the method name is much better. + *

+ * + * @param visitor + * the visitor used to process the queried beans. + * + * @deprecated + */ + public void findVisit(QueryResultVisitor visitor); + + /** + * Execute the query processing the beans one at a time. + *

+ * This method is appropriate to process very large query results as the + * beans are consumed one at a time and do not need to be held in memory + * (unlike #findList #findSet etc) + *

+ *

+ * Compared with #findEachWhile this will always process all the beans where as + * #findEachWhile provides a way to stop processing the query result early before + * all the beans have been read. + *

+ *

+ * This method is functionally equivalent to findIterate() but instead of using an + * iterator uses the QueryEachConsumer (SAM) interface which is better suited to use + * with Java8 closures. + *

+ * + *
+   *
+   * Query<Customer> query = server.find(Customer.class)
+   *     .where().gt("id", 0)
+   *     .orderBy("id")
+   *     .setMaxRows(2);
+   *
+   * query.findVisit((Customer customer) -> {
+   *
+   *     // do something with customer
+   *     System.out.println("-- visit " + customer);
+   * });
+   * 
+ * + * @param consumer + * the consumer used to process the queried beans. + */ + public void findEach(QueryEachConsumer consumer); + /** * Execute the query using callbacks to a visitor to process the resulting * beans one at a time. *

- * Similar to findIterate() this query method does not require all the result - * beans to be all held in memory at once and as such is useful for processing - * large queries. + * This method is functionally equivalent to findIterate() but instead of using an + * iterator uses the QueryEachWhileConsumer (SAM) interface which is better suited to use + * with Java8 closures. *

- * + + * *
-   * 
+   *
    * Query<Customer> query = server.find(Customer.class)
    *     .fetch("contacts", new FetchConfig().query(2))
    *     .where().gt("id", 0)
    *     .orderBy("id")
    *     .setMaxRows(2);
-   * 
-   * query.findVisit(new QueryResultVisitor<Customer>() {
-   * 
-   *   public boolean accept(Customer customer) {
+   *
+   * query.findEachWhile((Customer customer) -> {
+   *
    *     // do something with customer
    *     System.out.println("-- visit " + customer);
-   *     return true;
-   *   }
+   *
+   *     // return true to continue processing or false to stop
+   *     return (customer.getId() < 40);
    * });
    * 
- * - * @param visitor - * the visitor used to process the queried beans. + * + * @param consumer + * the consumer used to process the queried beans. */ - public void findVisit(QueryResultVisitor visitor); + public void findEachWhile(QueryEachWhileConsumer consumer); /** * Execute the query returning the list of objects. diff --git a/src/main/java/com/avaje/ebean/QueryEachConsumer.java b/src/main/java/com/avaje/ebean/QueryEachConsumer.java new file mode 100644 index 000000000..7e9761426 --- /dev/null +++ b/src/main/java/com/avaje/ebean/QueryEachConsumer.java @@ -0,0 +1,41 @@ +package com.avaje.ebean; + +/** + * Used to process a query result one bean at a time via a callback to this + * visitor. + *

+ * If you wish to stop further processing return false from the accept method. + *

+ *

+ * Unlike findList() and findSet() using a QueryResultVisitor does not require + * all the beans in the query result to be held in memory at once. This makes + * QueryResultVisitor useful for processing large queries. + *

+ * + *
+ *
+ * Query<Customer> query = server.find(Customer.class)
+ *     .where().gt("id", 0)
+ *     .orderBy("id")
+ *     .setMaxRows(2);
+ *
+ * query.findVisit((Customer customer) -> {
+ *
+ *     // do something with customer
+ *     System.out.println("-- visit " + customer);
+ * });
+ * 
+ * + * @param + * the type of entity bean being queried. + */ +public interface QueryEachConsumer { + + /** + * Process the bean. + * + * @param bean + * the entity bean to process + */ + public void accept(T bean); +} diff --git a/src/main/java/com/avaje/ebean/QueryEachWhileConsumer.java b/src/main/java/com/avaje/ebean/QueryEachWhileConsumer.java new file mode 100644 index 000000000..1b503099c --- /dev/null +++ b/src/main/java/com/avaje/ebean/QueryEachWhileConsumer.java @@ -0,0 +1,45 @@ +package com.avaje.ebean; + +/** + * Used to process a query result one bean at a time via a callback to this + * visitor. + *

+ * If you wish to stop further processing return false from the accept method. + *

+ *

+ * Unlike findList() and findSet() using a QueryResultVisitor does not require + * all the beans in the query result to be held in memory at once. This makes + * QueryResultVisitor useful for processing large queries. + *

+ *

+ *

+ *
+ * Query<Customer> query = server.find(Customer.class)
+ *     .fetch("contacts", new FetchConfig().query(2))
+ *     .where().gt("id", 0)
+ *     .orderBy("id")
+ *     .setMaxRows(2);
+ *
+ * query.findEachWhile((Customer customer) -> {
+ *
+ *     // do something with customer
+ *     System.out.println("-- visit " + customer);
+ *
+ *     // return true to continue processing or false to stop
+ *     return (customer.getId() < 40);
+ * });
+ * 
+ * + * @param the type of entity bean being queried. + */ +public interface QueryEachWhileConsumer { + + /** + * Process the bean and return true if you want to continue processing more + * beans. Return false if you want to stop processing further. + * + * @param bean the entity bean to process + * @return true to continue processing more beans or false to stop. + */ + public boolean accept(T bean); +} diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java index b3810aaa5..03172c75d 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java +++ b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java @@ -17,36 +17,10 @@ import javax.management.MBeanServer; import javax.management.ObjectName; import javax.persistence.PersistenceException; +import com.avaje.ebean.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.avaje.ebean.AdminAutofetch; -import com.avaje.ebean.BackgroundExecutor; -import com.avaje.ebean.BeanState; -import com.avaje.ebean.CallableSql; -import com.avaje.ebean.Ebean; -import com.avaje.ebean.ExpressionFactory; -import com.avaje.ebean.Filter; -import com.avaje.ebean.FutureIds; -import com.avaje.ebean.FutureList; -import com.avaje.ebean.FutureRowCount; -import com.avaje.ebean.PagedList; -import com.avaje.ebean.PagingList; -import com.avaje.ebean.Query; -import com.avaje.ebean.QueryIterator; -import com.avaje.ebean.QueryResultVisitor; -import com.avaje.ebean.SqlFutureList; -import com.avaje.ebean.SqlQuery; -import com.avaje.ebean.SqlRow; -import com.avaje.ebean.SqlUpdate; -import com.avaje.ebean.Transaction; -import com.avaje.ebean.TxCallable; -import com.avaje.ebean.TxIsolation; -import com.avaje.ebean.TxRunnable; -import com.avaje.ebean.TxScope; -import com.avaje.ebean.TxType; -import com.avaje.ebean.Update; -import com.avaje.ebean.ValuePair; import com.avaje.ebean.bean.BeanCollection; import com.avaje.ebean.bean.CallStack; import com.avaje.ebean.bean.EntityBean; @@ -273,17 +247,14 @@ public final class DefaultServer implements SpiEbeanServer { List spiPlugins = new ArrayList(); - final Iterator plugins = ServiceLoader.load(SpiEbeanPlugin.class).iterator(); - - while (plugins.hasNext()) { - SpiEbeanPlugin plugin = plugins.next(); + for (SpiEbeanPlugin plugin : ServiceLoader.load(SpiEbeanPlugin.class)) { spiPlugins.add(plugin); plugin.setup(this, this.getDatabasePlatform(), config.getServerConfig()); if (plugin instanceof DdlGenerator) { // backwards compatible - ddlGenerator = (DdlGenerator)plugin; - } + ddlGenerator = (DdlGenerator) plugin; + } } if (ddlGenerator == null) { @@ -1413,12 +1384,27 @@ public final class DefaultServer implements SpiEbeanServer { SpiOrmQueryRequest request = createQueryRequest(Type.LIST, query, t); - try { - request.initTransIfRequired(); - request.findVisit(visitor); - } finally { - // do nothing - findVisit garuntee's cleanup of the transaction if required - } + request.initTransIfRequired(); + request.findVisit(visitor); + // no try finally - findVisit guarantee's cleanup of the transaction if required + } + + public void findEach(Query query, QueryEachConsumer consumer, Transaction t) { + + SpiOrmQueryRequest request = createQueryRequest(Type.LIST, query, t); + + request.initTransIfRequired(); + request.findEach(consumer); + // no try finally - findVisit guarantee's cleanup of the transaction if required + } + + public void findEachWhile(Query query, QueryEachWhileConsumer consumer, Transaction t) { + + SpiOrmQueryRequest request = createQueryRequest(Type.LIST, query, t); + + request.initTransIfRequired(); + request.findEachWhile(consumer); + // no try finally - findVisit guarantee's cleanup of the transaction if required } public QueryIterator findIterate(Query query, Transaction t) { @@ -1542,7 +1528,7 @@ public final class DefaultServer implements SpiEbeanServer { @Override public void markAsDirty(Object bean) { - if (bean instanceof EntityBean == false) { + if (!(bean instanceof EntityBean)) { throw new IllegalArgumentException("This bean is not an EntityBean?"); } // mark the bean as dirty (so that an update will not get skipped) @@ -1650,7 +1636,7 @@ public final class DefaultServer implements SpiEbeanServer { if (bean == null) { throw new IllegalArgumentException(Message.msg("bean.isnull")); } - if (bean instanceof EntityBean == false) { + if (!(bean instanceof EntityBean)) { throw new IllegalArgumentException("Was expecting an EntityBean but got a "+bean.getClass()); } return (EntityBean)bean; @@ -1959,10 +1945,7 @@ public final class DefaultServer implements SpiEbeanServer { public boolean isSupportedType(java.lang.reflect.Type genericType) { TypeInfo typeInfo = ParamTypeHelper.getTypeInfo(genericType); - if (typeInfo == null) { - return false; - } - return getBeanDescriptor(typeInfo.getBeanType()) != null; + return typeInfo != null && getBeanDescriptor(typeInfo.getBeanType()) != null; } public Object getBeanId(Object bean) { diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/OrmQueryRequest.java b/src/main/java/com/avaje/ebeaninternal/server/core/OrmQueryRequest.java index e64eacd8d..b3b701f38 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/core/OrmQueryRequest.java +++ b/src/main/java/com/avaje/ebeaninternal/server/core/OrmQueryRequest.java @@ -6,9 +6,7 @@ import java.util.Set; import javax.persistence.PersistenceException; -import com.avaje.ebean.QueryIterator; -import com.avaje.ebean.QueryResultVisitor; -import com.avaje.ebean.RawSql; +import com.avaje.ebean.*; import com.avaje.ebean.bean.BeanCollection; import com.avaje.ebean.bean.PersistenceContext; import com.avaje.ebean.event.BeanFinder; @@ -234,6 +232,30 @@ public final class OrmQueryRequest extends BeanRequest implements BeanQueryRe return idList.getIdList(); } + public void findEach(QueryEachConsumer consumer) { + QueryIterator it = queryEngine.findIterate(this); + try { + while (it.hasNext()) { + consumer.accept(it.next()); + } + } finally { + it.close(); + } + } + + public void findEachWhile(QueryEachWhileConsumer consumer) { + QueryIterator it = queryEngine.findIterate(this); + try { + while (it.hasNext()) { + if (!consumer.accept(it.next())) { + break; + } + } + } finally { + it.close(); + } + } + public void findVisit(QueryResultVisitor visitor) { QueryIterator it = queryEngine.findIterate(this); try { diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/SpiOrmQueryRequest.java b/src/main/java/com/avaje/ebeaninternal/server/core/SpiOrmQueryRequest.java index 8837a516d..52c5e1508 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/core/SpiOrmQueryRequest.java +++ b/src/main/java/com/avaje/ebeaninternal/server/core/SpiOrmQueryRequest.java @@ -4,6 +4,8 @@ import java.util.List; import java.util.Map; import java.util.Set; +import com.avaje.ebean.QueryEachConsumer; +import com.avaje.ebean.QueryEachWhileConsumer; import com.avaje.ebean.QueryIterator; import com.avaje.ebean.QueryResultVisitor; import com.avaje.ebean.bean.BeanCollection; @@ -65,7 +67,17 @@ public interface SpiOrmQueryRequest { */ public void findVisit(QueryResultVisitor visitor); - /** + /** + * Execute the find returning a QueryIterator and visitor pattern. + */ + public void findEach(QueryEachConsumer consumer); + + /** + * Execute the find returning a QueryIterator and visitor pattern. + */ + public void findEachWhile(QueryEachWhileConsumer consumer); + + /** * Execute the find returning a QueryIterator. */ public QueryIterator findIterate(); diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java b/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java index 6bb654df3..4edaca7b9 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java @@ -218,6 +218,16 @@ abstract class JunctionExpression implements Junction, SpiExpression, Expr return exprList.findIds(); } + @Override + public void findEach(QueryEachConsumer consumer) { + exprList.findEach(consumer); + } + + @Override + public void findEachWhile(QueryEachWhileConsumer consumer) { + exprList.findEachWhile(consumer); + } + public void findVisit(QueryResultVisitor visitor) { exprList.findVisit(visitor); } diff --git a/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java b/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java index 607cdc0f5..de67a9949 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java +++ b/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java @@ -8,22 +8,8 @@ import java.util.Set; import javax.persistence.PersistenceException; -import com.avaje.ebean.EbeanServer; -import com.avaje.ebean.Expression; -import com.avaje.ebean.ExpressionFactory; -import com.avaje.ebean.ExpressionList; -import com.avaje.ebean.FetchConfig; -import com.avaje.ebean.FutureIds; -import com.avaje.ebean.FutureList; -import com.avaje.ebean.FutureRowCount; -import com.avaje.ebean.OrderBy; +import com.avaje.ebean.*; import com.avaje.ebean.OrderBy.Property; -import com.avaje.ebean.PagedList; -import com.avaje.ebean.PagingList; -import com.avaje.ebean.Query; -import com.avaje.ebean.QueryIterator; -import com.avaje.ebean.QueryResultVisitor; -import com.avaje.ebean.RawSql; import com.avaje.ebean.bean.BeanCollectionTouched; import com.avaje.ebean.bean.CallStack; import com.avaje.ebean.bean.EntityBean; @@ -911,6 +897,16 @@ public class DefaultOrmQuery implements SpiQuery { server.findVisit(this, visitor, null); } + @Override + public void findEachWhile(QueryEachWhileConsumer consumer) { + server.findEachWhile(this, consumer, null); + } + + @Override + public void findEach(QueryEachConsumer consumer) { + server.findEach(this, consumer, null); + } + public QueryIterator findIterate() { return server.findIterate(this, null); } diff --git a/src/main/java/com/avaje/ebeaninternal/util/DefaultExpressionList.java b/src/main/java/com/avaje/ebeaninternal/util/DefaultExpressionList.java index 467fd9aae..44c81522a 100644 --- a/src/main/java/com/avaje/ebeaninternal/util/DefaultExpressionList.java +++ b/src/main/java/com/avaje/ebeaninternal/util/DefaultExpressionList.java @@ -6,19 +6,7 @@ import java.util.List; import java.util.Map; import java.util.Set; -import com.avaje.ebean.Expression; -import com.avaje.ebean.ExpressionFactory; -import com.avaje.ebean.ExpressionList; -import com.avaje.ebean.FutureIds; -import com.avaje.ebean.FutureList; -import com.avaje.ebean.FutureRowCount; -import com.avaje.ebean.Junction; -import com.avaje.ebean.OrderBy; -import com.avaje.ebean.PagedList; -import com.avaje.ebean.PagingList; -import com.avaje.ebean.Query; -import com.avaje.ebean.QueryIterator; -import com.avaje.ebean.QueryResultVisitor; +import com.avaje.ebean.*; import com.avaje.ebean.event.BeanQueryRequest; import com.avaje.ebean.text.PathProperties; import com.avaje.ebeaninternal.api.HashQueryPlanBuilder; @@ -172,6 +160,16 @@ public class DefaultExpressionList implements SpiExpressionList { return query.findIds(); } + @Override + public void findEach(QueryEachConsumer consumer) { + query.findEach(consumer); + } + + @Override + public void findEachWhile(QueryEachWhileConsumer consumer) { + query.findEachWhile(consumer); + } + public void findVisit(QueryResultVisitor visitor) { query.findVisit(visitor); } diff --git a/src/test/java/com/avaje/tests/query/TestQueryFindEach.java b/src/test/java/com/avaje/tests/query/TestQueryFindEach.java new file mode 100644 index 000000000..113e37218 --- /dev/null +++ b/src/test/java/com/avaje/tests/query/TestQueryFindEach.java @@ -0,0 +1,67 @@ +package com.avaje.tests.query; + +import com.avaje.ebean.*; +import com.avaje.tests.model.basic.Customer; +import com.avaje.tests.model.basic.ResetBasicData; +import org.junit.Assert; +import org.junit.Test; + +import java.util.concurrent.atomic.AtomicInteger; + +public class TestQueryFindEach extends BaseTestCase { + + @Test + public void test() { + + ResetBasicData.reset(); + + EbeanServer server = Ebean.getServer(null); + + Query query + = server.find(Customer.class) + .setAutofetch(false) + .fetch("contacts", new FetchConfig().query(2)).where().gt("id", 0).orderBy("id") + .setMaxRows(2); + + final AtomicInteger counter = new AtomicInteger(0); + + query.findEach(new QueryEachConsumer() { + + public void accept(Customer customer) { + counter.incrementAndGet(); + customer.getName(); + } + }); + + Assert.assertEquals(2, counter.get()); + } + + /** + * Test the behaviour when an exception is thrown inside the findVisit(). + */ + @Test(expected=IllegalStateException.class) + public void testVisitThrowingException() { + + ResetBasicData.reset(); + + EbeanServer server = Ebean.getServer(null); + + Query query = server.find(Customer.class).setAutofetch(false) + .fetch("contacts", new FetchConfig().query(2)).where().gt("id", 0).orderBy("id") + .setMaxRows(2); + + final AtomicInteger counter = new AtomicInteger(0); + + query.findEach(new QueryEachConsumer() { + + public void accept(Customer customer) { + counter.incrementAndGet(); + if (counter.intValue() > 0) { + throw new IllegalStateException("cause a failure"); + } + } + }); + + Assert.assertFalse("Never get here - exception thrown", true); + } +} diff --git a/src/test/java/com/avaje/tests/query/TestQueryFindEachWhile.java b/src/test/java/com/avaje/tests/query/TestQueryFindEachWhile.java new file mode 100644 index 000000000..a305fc974 --- /dev/null +++ b/src/test/java/com/avaje/tests/query/TestQueryFindEachWhile.java @@ -0,0 +1,69 @@ +package com.avaje.tests.query; + +import com.avaje.ebean.*; +import com.avaje.tests.model.basic.Customer; +import com.avaje.tests.model.basic.ResetBasicData; +import org.junit.Assert; +import org.junit.Test; + +import java.util.concurrent.atomic.AtomicInteger; + +public class TestQueryFindEachWhile extends BaseTestCase { + + @Test + public void test() { + + ResetBasicData.reset(); + + EbeanServer server = Ebean.getServer(null); + + Query query + = server.find(Customer.class) + .setAutofetch(false) + .fetch("contacts", new FetchConfig().query(2)).where().gt("id", 0).orderBy("id") + .setMaxRows(2); + + final AtomicInteger counter = new AtomicInteger(0); + + query.findEachWhile(new QueryEachWhileConsumer< Customer > () { + + public boolean accept(Customer customer) { + counter.incrementAndGet(); + customer.getName(); + return true; + } + }); + + Assert.assertEquals(2, counter.get()); + } + + /** + * Test the behaviour when an exception is thrown inside the findVisit(). + */ + @Test(expected=IllegalStateException.class) + public void testVisitThrowingException() { + + ResetBasicData.reset(); + + EbeanServer server = Ebean.getServer(null); + + Query query = server.find(Customer.class).setAutofetch(false) + .fetch("contacts", new FetchConfig().query(2)).where().gt("id", 0).orderBy("id") + .setMaxRows(2); + + final AtomicInteger counter = new AtomicInteger(0); + + query.findEachWhile(new QueryEachWhileConsumer() { + + public boolean accept(Customer customer) { + counter.incrementAndGet(); + if (counter.intValue() > 0) { + throw new IllegalStateException("cause a failure"); + } + return true; + } + }); + + Assert.assertFalse("Never get here - exception thrown", true); + } +} From 7f30dc7b1e92e750239e08f98e0a893020cddc5d Mon Sep 17 00:00:00 2001 From: rbygrave Date: Mon, 17 Nov 2014 00:05:20 +1300 Subject: [PATCH 04/10] WIP Java8 types - ScalarTypeDuration etc --- .../com/avaje/ebean/config/JsonConfig.java | 29 +++ .../com/avaje/ebean/config/ServerConfig.java | 26 +++ .../server/deploy/BeanProperty.java | 124 +------------ .../server/deploy/BeanPropertyAssocMany.java | 6 - .../server/deploy/BeanPropertyAssocOne.java | 8 - .../server/el/ElPropertyChain.java | 2 +- .../server/type/DateTimeJsonParser.java | 4 + .../server/type/DecimalUtils.java | 89 +++++++++ .../server/type/DefaultTypeFactory.java | 23 +-- .../server/type/DefaultTypeManager.java | 56 +++--- .../ebeaninternal/server/type/ScalarType.java | 28 +-- .../server/type/ScalarTypeBaseDate.java | 13 +- .../server/type/ScalarTypeBaseDateTime.java | 110 ++++++++--- .../server/type/ScalarTypeBaseVarchar.java | 12 +- .../server/type/ScalarTypeBigDecimal.java | 112 ++++++------ .../server/type/ScalarTypeBoolean.java | 16 +- .../server/type/ScalarTypeByte.java | 14 +- .../server/type/ScalarTypeBytesBase.java | 11 +- .../server/type/ScalarTypeBytesEncrypted.java | 35 ++-- .../server/type/ScalarTypeCalendar.java | 34 +++- .../server/type/ScalarTypeCharArray.java | 4 +- .../server/type/ScalarTypeDouble.java | 18 +- .../server/type/ScalarTypeDuration.java | 104 +++++++++++ .../type/ScalarTypeDurationWithNanos.java | 82 +++++++++ .../type/ScalarTypeEncryptedWrapper.java | 12 +- .../server/type/ScalarTypeEnumStandard.java | 2 +- .../server/type/ScalarTypeFloat.java | 13 +- .../server/type/ScalarTypeInstant.java | 59 ++++++ .../server/type/ScalarTypeInteger.java | 25 ++- .../server/type/ScalarTypeJodaDateTime.java | 25 ++- .../server/type/ScalarTypeJodaLocalDate.java | 2 +- .../type/ScalarTypeJodaLocalDateTime.java | 31 +++- .../server/type/ScalarTypeJodaLocalTime.java | 13 +- .../server/type/ScalarTypeLocalDate.java | 2 +- .../server/type/ScalarTypeLocalDateTime.java | 29 ++- .../server/type/ScalarTypeLocalTime.java | 100 ++++++++++ .../server/type/ScalarTypeLong.java | 18 +- .../type/ScalarTypeLongToTimestamp.java | 6 +- .../server/type/ScalarTypeMathBigInteger.java | 15 +- .../server/type/ScalarTypeOffsetDateTime.java | 26 ++- .../server/type/ScalarTypePostgresHstore.java | 27 ++- .../server/type/ScalarTypeShort.java | 16 +- .../server/type/ScalarTypeString.java | 11 +- .../server/type/ScalarTypeTime.java | 11 +- .../server/type/ScalarTypeTimestamp.java | 27 ++- .../server/type/ScalarTypeUUIDBinary.java | 15 +- .../server/type/ScalarTypeUtilDate.java | 171 ++++++++++-------- .../server/type/ScalarTypeWrapper.java | 28 ++- .../server/type/ScalarTypeYear.java | 99 ++++++++++ .../server/type/DecimalUtilsTest.java | 44 +++++ .../server/type/ScalarTypeDurationTest.java | 121 +++++++++++++ .../type/ScalarTypeDurationWithNanosTest.java | 121 +++++++++++++ .../server/type/ScalarTypeInstantTest.java | 125 +++++++++++++ .../server/type/ScalarTypeLocalDateTest.java | 2 +- .../type/ScalarTypeLocalDateTimeTest.java | 18 +- .../server/type/ScalarTypeLocalTimeTest.java | 119 ++++++++++++ .../type/ScalarTypeOffsetDateTimeTest.java | 6 +- .../type/ScalarTypePostgresHstoreTest.java | 2 +- .../server/type/ScalarTypeYearTest.java | 114 ++++++++++++ 59 files changed, 1857 insertions(+), 558 deletions(-) create mode 100644 src/main/java/com/avaje/ebean/config/JsonConfig.java create mode 100644 src/main/java/com/avaje/ebeaninternal/server/type/DecimalUtils.java create mode 100644 src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeDuration.java create mode 100644 src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeDurationWithNanos.java create mode 100644 src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeInstant.java create mode 100644 src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalTime.java create mode 100644 src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeYear.java create mode 100644 src/test/java/com/avaje/ebeaninternal/server/type/DecimalUtilsTest.java create mode 100644 src/test/java/com/avaje/ebeaninternal/server/type/ScalarTypeDurationTest.java create mode 100644 src/test/java/com/avaje/ebeaninternal/server/type/ScalarTypeDurationWithNanosTest.java create mode 100644 src/test/java/com/avaje/ebeaninternal/server/type/ScalarTypeInstantTest.java create mode 100644 src/test/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalTimeTest.java create mode 100644 src/test/java/com/avaje/ebeaninternal/server/type/ScalarTypeYearTest.java diff --git a/src/main/java/com/avaje/ebean/config/JsonConfig.java b/src/main/java/com/avaje/ebean/config/JsonConfig.java new file mode 100644 index 000000000..a813be3fe --- /dev/null +++ b/src/main/java/com/avaje/ebean/config/JsonConfig.java @@ -0,0 +1,29 @@ +package com.avaje.ebean.config; + +/** + * Configuration for JSON features. + */ +public abstract class JsonConfig { + + /** + * Defined the format used for DateTime types. + */ + public enum DateTime { + + /** + * Format as epoch millis. + */ + MILLIS, + + /** + * Format as epoch with nanos. + */ + NANOS, + + /** + * Format as ISO-8601 date format. + */ + ISO8601 + } + +} diff --git a/src/main/java/com/avaje/ebean/config/ServerConfig.java b/src/main/java/com/avaje/ebean/config/ServerConfig.java index 5618389c3..a7e322eb7 100644 --- a/src/main/java/com/avaje/ebean/config/ServerConfig.java +++ b/src/main/java/com/avaje/ebean/config/ServerConfig.java @@ -121,6 +121,11 @@ public class ServerConfig { */ private AutofetchConfig autofetchConfig = new AutofetchConfig(); + /** + * The JSON format used for DateTime types. Default to millis. + */ + private JsonConfig.DateTime jsonDateTime = JsonConfig.DateTime.MILLIS; + /** * The database platform name. Used to imply a DatabasePlatform to use. */ @@ -270,6 +275,20 @@ public class ServerConfig { this.jsonFactory = jsonFactory; } + /** + * Return the JSON format used for DateTime types. + */ + public JsonConfig.DateTime getJsonDateTime() { + return jsonDateTime; + } + + /** + * Set the JSON format to use for DateTime types. + */ + public void setJsonDateTime(JsonConfig.DateTime jsonDateTime) { + this.jsonDateTime = jsonDateTime; + } + /** * Return the name of the EbeanServer. */ @@ -1368,6 +1387,13 @@ public class ServerConfig { lazyLoadBatchSize = p.getInt("lazyLoadBatchSize", 1); queryBatchSize = p.getInt("queryBatchSize", DEFAULT_QUERY_BATCH_SIZE); + String jsonDateTimeFormat = p.get("jsonDateTime", null); + if (jsonDateTimeFormat != null) { + jsonDateTime = JsonConfig.DateTime.valueOf(jsonDateTimeFormat); + } else { + jsonDateTime = JsonConfig.DateTime.MILLIS; + } + ddlGenerate = p.getBoolean("ddl.generate", false); ddlRun = p.getBoolean("ddl.run", false); diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanProperty.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanProperty.java index 7b0d79fb5..fa7a5ddaf 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanProperty.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanProperty.java @@ -41,29 +41,6 @@ import com.fasterxml.jackson.core.JsonToken; */ public class BeanProperty implements ElPropertyValue { - /** - * Advanced bean deployment. To exclude this property from update where - * clause. - */ - public static final String EXCLUDE_FROM_UPDATE_WHERE = "EXCLUDE_FROM_UPDATE_WHERE"; - - /** - * Advanced bean deployment. To exclude this property from delete where - * clause. - */ - public static final String EXCLUDE_FROM_DELETE_WHERE = "EXCLUDE_FROM_DELETE_WHERE"; - - /** - * Advanced bean deployment. To exclude this property from insert. - */ - public static final String EXCLUDE_FROM_INSERT = "EXCLUDE_FROM_INSERT"; - - /** - * Advanced bean deployment. To exclude this property from update set - * clause. - */ - public static final String EXCLUDE_FROM_UPDATE = "EXCLUDE_FROM_UPDATE"; - /** * Flag to mark this at part of the unique id. */ @@ -488,15 +465,7 @@ public class BeanProperty implements ElPropertyValue { * Return true if the underlying type is mutable. */ public boolean isMutableScalarType() { - if (scalarType == null) { - return false; - } - return scalarType.isMutable(); - } - - public void copyProperty(EntityBean sourceBean, EntityBean destBean) { - Object value = getValue(sourceBean); - setValue(destBean, value); + return scalarType != null && scalarType.isMutable(); } /** @@ -506,10 +475,6 @@ public class BeanProperty implements ElPropertyValue { return descriptor.getEncryptKey(this); } - public String getDecryptProperty() { - return dbEncryptFunction.getDecryptSql(this.getName()); - } - public String getDecryptProperty(String propertyName) { return dbEncryptFunction.getDecryptSql(propertyName); } @@ -575,24 +540,6 @@ public class BeanProperty implements ElPropertyValue { return owningType.isAssignableFrom(type); } - public Object readSetOwning(DbReadContext ctx, EntityBean bean, Class type) throws SQLException { - - try { - Object value = scalarType.read(ctx.getDataReader()); - if (value == null || bean == null) { - // not setting the value... - } else { - if (owningType.equals(type)) { - setValue(bean, value); - } - } - return value; - } catch (Exception e) { - String msg = "Error readSet on " + descriptor + "." + name; - throw new PersistenceException(msg, e); - } - } - public void loadIgnore(DbReadContext ctx) { scalarType.loadIgnore(ctx.getDataReader()); } @@ -616,16 +563,13 @@ public class BeanProperty implements ElPropertyValue { public Object readSet(DbReadContext ctx, EntityBean bean, Class type) throws SQLException { try { - Object value = scalarType.read(ctx.getDataReader()); - if (bean == null || (type != null && !owningType.isAssignableFrom(type))) { - // not setting the value... - } else { - setValue(bean, value); - } - return value; + Object value = scalarType.read(ctx.getDataReader()); + if (bean != null && ((type == null || owningType.isAssignableFrom(type)))) { + setValue(bean, value); + } + return value; } catch (Exception e) { - String msg = "Error readSet on " + descriptor + "." + name; - throw new PersistenceException(msg, e); + throw new PersistenceException("Error readSet on " + descriptor + "." + name, e); } } @@ -653,21 +597,6 @@ public class BeanProperty implements ElPropertyValue { return scalarType.readData(dataInput); } - public boolean isCascadeValidate() { - return cascadeValidate; - } - - /** - * Checks to see if a bean is a reference (will be lazy loaded) or a - * BeanCollection that has not yet been populated. - *

- * For base types this returns true. - *

- */ - public boolean isValueLoaded(Object value) { - return true; - } - public BeanProperty getBeanProperty() { return this; } @@ -737,11 +666,9 @@ public class BeanProperty implements ElPropertyValue { } } - private static Object[] NO_ARGS = new Object[0]; - public Object getCacheDataValue(EntityBean bean) { return getValue(bean); - } + } public void setCacheDataValue(EntityBean bean, Object cacheData) { setValue(bean, cacheData); @@ -759,19 +686,6 @@ public class BeanProperty implements ElPropertyValue { throw new RuntimeException(msg, ex); } } - - /** - * Explicitly use reflection to get value. - */ - public Object getValueViaReflection(Object bean) { - try { - return readMethod.invoke(bean, NO_ARGS); - } catch (Exception ex) { - String beanType = bean == null ? "null" : bean.getClass().getName(); - String msg = "get " + name + " on [" + descriptor + "] type[" + beanType + "] threw error."; - throw new RuntimeException(msg, ex); - } - } public Object getValueIntercept(EntityBean bean) { try { @@ -826,13 +740,6 @@ public class BeanProperty implements ElPropertyValue { return name; } - /** - * This is a full ElGetValue. - */ - public boolean isDeployOnly() { - return false; - } - @Override public boolean containsFormulaWithJoin() { return formula && sqlFormulaJoin != null; @@ -902,7 +809,7 @@ public class BeanProperty implements ElPropertyValue { /** * Return the scalarType. */ - public ScalarType getScalarType() { + public ScalarType getScalarType() { return scalarType; } @@ -923,7 +830,7 @@ public class BeanProperty implements ElPropertyValue { } public Object parseDateTime(long systemTimeMillis) { - return scalarType.parseDateTime(systemTimeMillis); + return scalarType.convertFromMillis(systemTimeMillis); } /** @@ -1031,10 +938,6 @@ public class BeanProperty implements ElPropertyValue { return version; } - public String getDeployProperty() { - return dbColumn; - } - /** * The database column name this is mapped to. */ @@ -1168,13 +1071,6 @@ public class BeanProperty implements ElPropertyValue { return embedded; } - /** - * Return an extra attribute set on this property. - */ - public String getExtraAttribute(String key) { - return extraAttributeMap.get(key); - } - /** * Return the default value. */ diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocMany.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocMany.java index 0745915b7..2d8d42c55 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocMany.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocMany.java @@ -385,12 +385,6 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc { return null; } - - @Override - public boolean isValueLoaded(Object value) { - return !(value instanceof BeanCollection) || ((BeanCollection) value).isPopulated(); - } - public void add(BeanCollection collection, EntityBean bean) { help.add(collection, bean); } diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocOne.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocOne.java index 997b04659..2a463971b 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocOne.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocOne.java @@ -265,14 +265,6 @@ public class BeanPropertyAssocOne extends BeanPropertyAssoc { } } - @Override - public boolean isValueLoaded(Object value) { - if (value instanceof EntityBean) { - return ((EntityBean) value)._ebean_getIntercept().isLoaded(); - } - return true; - } - /** * Return meta data for the deployment of the embedded bean specific to this * property. diff --git a/src/main/java/com/avaje/ebeaninternal/server/el/ElPropertyChain.java b/src/main/java/com/avaje/ebeaninternal/server/el/ElPropertyChain.java index c23dc7465..af9db6390 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/el/ElPropertyChain.java +++ b/src/main/java/com/avaje/ebeaninternal/server/el/ElPropertyChain.java @@ -215,7 +215,7 @@ public class ElPropertyChain implements ElPropertyValue { } public Object parseDateTime(long systemTimeMillis) { - return scalarType.parseDateTime(systemTimeMillis); + return scalarType.convertFromMillis(systemTimeMillis); } public StringParser getStringParser() { diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/DateTimeJsonParser.java b/src/main/java/com/avaje/ebeaninternal/server/type/DateTimeJsonParser.java index decc9ccbd..df303c431 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/DateTimeJsonParser.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/DateTimeJsonParser.java @@ -3,6 +3,7 @@ package com.avaje.ebeaninternal.server.type; import java.sql.Timestamp; import java.text.ParseException; import java.text.SimpleDateFormat; +import java.util.Date; import java.util.TimeZone; public class DateTimeJsonParser { @@ -31,4 +32,7 @@ public class DateTimeJsonParser { } } + public String format(Date value) { + return dtFormat().format(value); + } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/DecimalUtils.java b/src/main/java/com/avaje/ebeaninternal/server/type/DecimalUtils.java new file mode 100644 index 000000000..235e94882 --- /dev/null +++ b/src/main/java/com/avaje/ebeaninternal/server/type/DecimalUtils.java @@ -0,0 +1,89 @@ +package com.avaje.ebeaninternal.server.type; + +/* + * Copyright 2013 FasterXML.com + * + * Licensed 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. + */ + +import java.math.BigDecimal; +import java.sql.Timestamp; +import java.time.Duration; +import java.time.Instant; + +/** + * Utilities to aid in the translation of decimal types to/from multiple parts. + * + * @author Nick Williams + * @since 2.2.0 + */ +public final class DecimalUtils { + + private static final char[] ZEROES = new char[]{'0', '0', '0', '0', '0', '0', '0', '0', '0'}; + + private static final BigDecimal ONE_BILLION = new BigDecimal(1000000000L); + + private DecimalUtils() { + throw new RuntimeException("DecimalUtils cannot be instantiated."); + } + + public static Duration toDuration(BigDecimal value) { + + long seconds = value.longValue(); + int nanoseconds = extractNanosecondDecimal(value, seconds); + + return Duration.ofSeconds(seconds, nanoseconds); + } + + public static BigDecimal toDecimal(Duration instant) { + return new BigDecimal(toDecimal(instant.getSeconds(), instant.getNano())); + } + + public static Timestamp toTimestamp(BigDecimal value) { + + long seconds = value.longValue(); + int nanoseconds = extractNanosecondDecimal(value, seconds); + + Timestamp ts = new Timestamp(seconds * 1000); + ts.setNanos(nanoseconds); + return ts; + } + + public static BigDecimal toDecimal(Timestamp instant) { + long millis = instant.getTime(); + long secs = millis/1000; + return new BigDecimal(toDecimal(secs, instant.getNanos())); + } + + public static Instant toInstant(BigDecimal value) { + + long seconds = value.longValue(); + int nanoseconds = DecimalUtils.extractNanosecondDecimal(value, seconds); + return Instant.ofEpochSecond(seconds, nanoseconds); + } + + public static BigDecimal toDecimal(Instant instant) { + return new BigDecimal(toDecimal(instant.getEpochSecond(), instant.getNano())); + } + + public static String toDecimal(long seconds, int nanoseconds) { + StringBuilder string = new StringBuilder(Integer.toString(nanoseconds)); + if (string.length() < 9) + string.insert(0, ZEROES, 0, 9 - string.length()); + return seconds + "." + string; + } + + public static int extractNanosecondDecimal(BigDecimal value, long integer) { + return value.subtract(new BigDecimal(integer)).multiply(ONE_BILLION).intValue(); + } +} \ No newline at end of file diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/DefaultTypeFactory.java b/src/main/java/com/avaje/ebeaninternal/server/type/DefaultTypeFactory.java index dab788a76..ffbd27410 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/DefaultTypeFactory.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/DefaultTypeFactory.java @@ -4,6 +4,7 @@ import java.math.BigInteger; import java.sql.Types; import java.util.Calendar; +import com.avaje.ebean.config.JsonConfig; import com.avaje.ebean.config.ServerConfig; import com.avaje.ebeaninternal.server.core.BasicTypeConverter; @@ -80,27 +81,27 @@ public class DefaultTypeFactory { /** * Create the default ScalarType for java.util.Date. */ - public ScalarType createUtilDate() { + public ScalarType createUtilDate(JsonConfig.DateTime mode) { // by default map anonymous java.util.Date to java.sql.Timestamp. // String mapType = // properties.getProperty("type.mapping.java.util.Date","timestamp"); int utilDateType = getTemporalMapType("timestamp"); - return createUtilDate(utilDateType); + return createUtilDate(mode, utilDateType); } /** * Create a ScalarType for java.util.Date explicitly specifying the type to * map to. */ - public ScalarType createUtilDate(int utilDateType) { + public ScalarType createUtilDate(JsonConfig.DateTime mode, int utilDateType) { switch (utilDateType) { case Types.DATE: return new ScalarTypeUtilDate.DateType(); case Types.TIMESTAMP: - return new ScalarTypeUtilDate.TimestampType(); + return new ScalarTypeUtilDate.TimestampType(mode); default: throw new RuntimeException("Invalid type " + utilDateType); @@ -110,23 +111,19 @@ public class DefaultTypeFactory { /** * Create the default ScalarType for java.util.Calendar. */ - public ScalarType createCalendar() { - // by default map anonymous java.util.Calendar to java.sql.Timestamp. - // String mapType = - // properties.getProperty("type.mapping.java.util.Calendar", - // "timestamp"); - int jdbcType = getTemporalMapType("timestamp"); + public ScalarType createCalendar(JsonConfig.DateTime mode) { - return createCalendar(jdbcType); + int jdbcType = getTemporalMapType("timestamp"); + return createCalendar(mode, jdbcType); } /** * Create a ScalarType for java.util.Calendar explicitly specifying the type * to map to. */ - public ScalarType createCalendar(int jdbcType) { + public ScalarType createCalendar(JsonConfig.DateTime mode, int jdbcType) { - return new ScalarTypeCalendar(jdbcType); + return new ScalarTypeCalendar(mode, jdbcType); } private int getTemporalMapType(String mapType) { diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/DefaultTypeManager.java b/src/main/java/com/avaje/ebeaninternal/server/type/DefaultTypeManager.java index bbff03a0c..1d8b4533d 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/DefaultTypeManager.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/DefaultTypeManager.java @@ -23,6 +23,7 @@ import java.util.TimeZone; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; +import com.avaje.ebean.config.*; import org.joda.time.DateMidnight; import org.joda.time.DateTime; import org.joda.time.LocalDate; @@ -33,10 +34,6 @@ import org.slf4j.LoggerFactory; import com.avaje.ebean.annotation.EnumMapping; import com.avaje.ebean.annotation.EnumValue; -import com.avaje.ebean.config.CompoundType; -import com.avaje.ebean.config.CompoundTypeProperty; -import com.avaje.ebean.config.ScalarTypeConverter; -import com.avaje.ebean.config.ServerConfig; import com.avaje.ebeaninternal.api.ClassUtil; import com.avaje.ebeaninternal.server.core.BootupClasses; import com.avaje.ebeaninternal.server.lib.util.StringHelper; @@ -103,8 +100,6 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable { private final ScalarType dateType = new ScalarTypeDate(); - private final ScalarType timestampType = new ScalarTypeTimestamp(); - private final ScalarType inetAddressType = new ScalarTypeInetAddress(); private final ScalarType urlType = new ScalarTypeURL(); private final ScalarType uriType = new ScalarTypeURI(); @@ -116,7 +111,6 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable { private final ScalarType classType = new ScalarTypeClass(); - private final ScalarTypeLongToTimestamp longToTimestamp = new ScalarTypeLongToTimestamp(); private final List> customScalarTypes = new ArrayList>(); @@ -126,6 +120,8 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable { private final ReflectionBasedTypeBuilder reflectScalarBuilder; + private final JsonConfig.DateTime jsonDateTime; + /** * Create the DefaultTypeManager. */ @@ -134,6 +130,7 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable { int clobType = config == null ? Types.CLOB : config.getDatabasePlatform().getClobDbType(); int blobType = config == null ? Types.BLOB : config.getDatabasePlatform().getBlobDbType(); + this.jsonDateTime = config.getJsonDateTime(); this.checkImmutable = new CheckImmutable(this); this.reflectScalarBuilder = new ReflectionBasedTypeBuilder(this); @@ -146,12 +143,12 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable { this.extraTypeFactory = new DefaultTypeFactory(config); - initialiseStandard(clobType, blobType, config.isUuidStoreAsBinary()); - initialiseJavaTimeTypes(); - initialiseJodaTypes(); + initialiseStandard(jsonDateTime, clobType, blobType, config.isUuidStoreAsBinary()); + initialiseJavaTimeTypes(jsonDateTime); + initialiseJodaTypes(jsonDateTime); if (bootupClasses != null) { - initialiseCustomScalarTypes(bootupClasses); + initialiseCustomScalarTypes(jsonDateTime, bootupClasses); initialiseScalarConverters(bootupClasses); initialiseCompoundTypes(bootupClasses); } @@ -313,19 +310,15 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable { if (jdbcType == 0 || scalarType.getJdbcType() == jdbcType) { // matching type return (ScalarType) scalarType; - } else { - // sometime like java.util.Date or java.util.Calendar - // that that does not map to the same jdbc type as the - // server wide settings. } } // a util Date with jdbcType not matching server wide settings if (type.equals(java.util.Date.class)) { - return (ScalarType) extraTypeFactory.createUtilDate(jdbcType); + return (ScalarType) extraTypeFactory.createUtilDate(jsonDateTime, jdbcType); } // a Calendar with jdbcType not matching server wide settings if (type.equals(java.util.Calendar.class)) { - return (ScalarType) extraTypeFactory.createCalendar(jdbcType); + return (ScalarType) extraTypeFactory.createCalendar(jsonDateTime, jdbcType); } String msg = "Unmatched ScalarType for " + type + " jdbcType:" + jdbcType; @@ -417,7 +410,7 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable { public ScalarType createEnumScalarType(Class enumType) { // get the mapping information from EnumMapping - EnumMapping enumMapping = (EnumMapping) enumType.getAnnotation(EnumMapping.class); + EnumMapping enumMapping = enumType.getAnnotation(EnumMapping.class); if (enumMapping == null) { // look for EnumValue annotations instead return createEnumScalarType2(enumType); @@ -468,7 +461,9 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable { * interface and register it with this TypeManager. *

*/ - protected void initialiseCustomScalarTypes(BootupClasses bootupClasses) { + protected void initialiseCustomScalarTypes(JsonConfig.DateTime mode, BootupClasses bootupClasses) { + + ScalarTypeLongToTimestamp longToTimestamp = new ScalarTypeLongToTimestamp(mode); customScalarTypes.add(longToTimestamp); @@ -604,12 +599,12 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable { return propParamTypes[1]; } - protected void initialiseJavaTimeTypes() { + protected void initialiseJavaTimeTypes(JsonConfig.DateTime mode) { if (ClassUtil.isPresent("java.time.LocalDate", this.getClass())) { logger.debug("Registering java.time data types"); typeMap.put(java.time.LocalDate.class, new ScalarTypeLocalDate()); - typeMap.put(java.time.LocalDateTime.class, new ScalarTypeLocalDateTime()); - typeMap.put(OffsetDateTime.class, new ScalarTypeOffsetDateTime()); + typeMap.put(java.time.LocalDateTime.class, new ScalarTypeLocalDateTime(mode)); + typeMap.put(OffsetDateTime.class, new ScalarTypeOffsetDateTime(mode)); } } @@ -617,16 +612,16 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable { * Detect if Joda classes are in the classpath and if so register the Joda * data types. */ - protected void initialiseJodaTypes() { + protected void initialiseJodaTypes(JsonConfig.DateTime mode) { // detect if Joda classes are in the classpath if (ClassUtil.isPresent("org.joda.time.LocalDateTime", this.getClass())) { // Joda classes are in the classpath so register the types logger.debug("Registering Joda data types"); - typeMap.put(LocalDateTime.class, new ScalarTypeJodaLocalDateTime()); + typeMap.put(LocalDateTime.class, new ScalarTypeJodaLocalDateTime(mode)); + typeMap.put(DateTime.class, new ScalarTypeJodaDateTime(mode)); typeMap.put(LocalDate.class, new ScalarTypeJodaLocalDate()); typeMap.put(LocalTime.class, new ScalarTypeJodaLocalTime()); - typeMap.put(DateTime.class, new ScalarTypeJodaDateTime()); typeMap.put(DateMidnight.class, new ScalarTypeJodaDateMidnight()); } } @@ -635,12 +630,12 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable { * Register all the standard types supported. This is the standard JDBC types * plus some other common types such as java.util.Date and java.util.Calendar. */ - protected void initialiseStandard(int platformClobType, int platformBlobType, boolean binaryUUID) { + protected void initialiseStandard(JsonConfig.DateTime mode, int platformClobType, int platformBlobType, boolean binaryUUID) { - ScalarType utilDateType = extraTypeFactory.createUtilDate(); + ScalarType utilDateType = extraTypeFactory.createUtilDate(mode); typeMap.put(java.util.Date.class, utilDateType); - ScalarType calType = extraTypeFactory.createCalendar(); + ScalarType calType = extraTypeFactory.createCalendar(mode); typeMap.put(Calendar.class, calType); ScalarType mathBigIntType = extraTypeFactory.createMathBigInteger(); @@ -655,8 +650,6 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable { if (booleanType.getJdbcType() == Types.BIT) { // for MapBeans ... BIT types are assumed to be booleans nativeMap.put(Types.BIT, booleanType); - } else { - // boolean mapping to Types.Integer, Types.VARCHAR or Types.Boolean } // Store UUID as binary(16) or varchar(40) @@ -744,6 +737,9 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable { nativeMap.put(Types.TIME, timeType); typeMap.put(Date.class, dateType); nativeMap.put(Types.DATE, dateType); + + ScalarType timestampType = new ScalarTypeTimestamp(mode); + typeMap.put(Timestamp.class, timestampType); nativeMap.put(Types.TIMESTAMP, timestampType); diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarType.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarType.java index c49cfcb00..b59bb38f0 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarType.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarType.java @@ -162,19 +162,11 @@ public interface ScalarType extends StringParser, StringFormatter, ScalarData */ public T parse(String value); - /** - * Convert the systemTimeMillis into the appropriate java object. - *

- * For non dateTime types this will throw an exception. - *

- */ - public T parseDateTime(long dateTime); - /** * Return true if the type can accept long systemTimeMillis input. *

* This is used to determine if is is sensible to use the - * {@link #parseDateTime(long)} method. + * {@link #convertFromMillis(long)} method. *

*

* This includes the Date, Calendar, sql Date, Time, Timestamp, JODA types @@ -184,24 +176,32 @@ public interface ScalarType extends StringParser, StringFormatter, ScalarData */ public boolean isDateTimeCapable(); - /** + /** + * Convert the systemTimeMillis into the appropriate java object. + *

+ * For non dateTime types this will throw an exception. + *

+ */ + public T convertFromMillis(long dateTime); + + /** * Read the value from binary input. */ - public Object readData(DataInput dataInput) throws IOException; + public T readData(DataInput dataInput) throws IOException; /** * Write the value to binary output. */ - public void writeData(DataOutput dataOutput, Object v) throws IOException; + public void writeData(DataOutput dataOutput, T v) throws IOException; /** * Read the value from JsonParser. */ - public Object jsonRead(JsonParser ctx, JsonToken event) throws IOException; + public T jsonRead(JsonParser ctx, JsonToken event) throws IOException; /** * Write the value to the JsonGenerator. */ - public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException; + public void jsonWrite(JsonGenerator ctx, String name, T value) throws IOException; } diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBaseDate.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBaseDate.java index 5d18df075..8f39b6cfd 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBaseDate.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBaseDate.java @@ -64,7 +64,7 @@ public abstract class ScalarTypeBaseDate extends ScalarTypeBase { return convertFromDate(date); } - public T parseDateTime(long systemTimeMillis) { + public T convertFromMillis(long systemTimeMillis) { Date ts = new Date(systemTimeMillis); return convertFromDate(ts); } @@ -74,20 +74,20 @@ public abstract class ScalarTypeBaseDate extends ScalarTypeBase { } @Override - public Object jsonRead(JsonParser ctx, JsonToken event) throws IOException { + public T jsonRead(JsonParser ctx, JsonToken event) throws IOException { if (JsonToken.VALUE_NUMBER_INT == event) { - return parseDateTime(ctx.getLongValue()); + return convertFromMillis(ctx.getLongValue()); } else { return convertFromDate(Date.valueOf(ctx.getText())); } } - public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException { + public void jsonWrite(JsonGenerator ctx, String name, T value) throws IOException { long millis = convertToMillis(value); ctx.writeNumberField(name, millis); } - public Object readData(DataInput dataInput) throws IOException { + public T readData(DataInput dataInput) throws IOException { if (!dataInput.readBoolean()) { return null; } else { @@ -98,9 +98,8 @@ public abstract class ScalarTypeBaseDate extends ScalarTypeBase { } @SuppressWarnings("unchecked") - public void writeData(DataOutput dataOutput, Object v) throws IOException { + public void writeData(DataOutput dataOutput, T value) throws IOException { - T value = (T) v; if (value == null) { dataOutput.writeBoolean(false); } else { diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBaseDateTime.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBaseDateTime.java index f3f53de1f..b267544a3 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBaseDateTime.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBaseDateTime.java @@ -1,39 +1,69 @@ package com.avaje.ebeaninternal.server.type; +import com.avaje.ebean.config.JsonConfig; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; + import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; +import java.math.BigDecimal; import java.sql.SQLException; import java.sql.Timestamp; import java.sql.Types; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.JsonToken; +import java.time.Instant; /** * Base type for DateTime types. */ public abstract class ScalarTypeBaseDateTime extends ScalarTypeBase { - protected DateTimeJsonParser dateTimeParser = new DateTimeJsonParser(); - - public ScalarTypeBaseDateTime(Class type, boolean jdbcNative, int jdbcType) { + + protected final DateTimeJsonParser dateTimeParser = new DateTimeJsonParser(); + + protected final JsonConfig.DateTime mode; + + public ScalarTypeBaseDateTime(JsonConfig.DateTime mode, Class type, boolean jdbcNative, int jdbcType) { super(type, jdbcNative, jdbcType); + this.mode = mode; } - public abstract long convertToMillis(Object value); - + /** + * Convert the value to a Timestamp. + */ public abstract Timestamp convertToTimestamp(T t); + /** + * Convert to the value from a Timestamp. + */ public abstract T convertFromTimestamp(Timestamp ts); + /** + * Convert from epoch millis to the value. + */ + public abstract T convertFromMillis(long systemTimeMillis); + + /** + * Convert from the value to epoch millis. + */ + public abstract long convertToMillis(T value); + + /** + * Convert the value to time with nanos format. + */ + protected abstract String toJsonNanos(T value); + + /** + * Convert the value to ISO8601 format. + */ + protected abstract String toJsonISO8601(T value); + public void bind(DataBind b, T value) throws SQLException { if (value == null) { b.setNull(Types.TIMESTAMP); } else { - Timestamp ts = convertToTimestamp(value); - b.setTimestamp(ts); + b.setTimestamp(convertToTimestamp(value)); } } @@ -47,23 +77,49 @@ public abstract class ScalarTypeBaseDateTime extends ScalarTypeBase { } } + /** + * Helper method that given epoch seconds and nanos return a JSON nanos formatted string. + */ + protected String toJsonNanos(long epochSecs, int nanos) { + return DecimalUtils.toDecimal(epochSecs, nanos); + } + @Override - public Object jsonRead(JsonParser ctx, JsonToken event) throws IOException { + public T jsonRead(JsonParser ctx, JsonToken event) throws IOException { - if (JsonToken.VALUE_NUMBER_INT == event) { - long millis = ctx.getLongValue(); - return parseDateTime(millis); - - } else { - String jsonDateTime = ctx.getText(); - return convertFromTimestamp(dateTimeParser.parse(jsonDateTime)); + switch (event) { + case VALUE_NUMBER_INT: { + return convertFromMillis(ctx.getLongValue()); + } + case VALUE_NUMBER_FLOAT: { + BigDecimal value = ctx.getDecimalValue(); + //Instant instant = DecimalUtils.toInstant(value); + Timestamp timestamp = DecimalUtils.toTimestamp(value); + convertFromTimestamp(timestamp);//Timestamp.from(instant)); + } + default: { + String jsonDateTime = ctx.getText(); + return convertFromTimestamp(dateTimeParser.parse(jsonDateTime)); + } } } @Override - public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException { - long millis = convertToMillis(value); - ctx.writeNumberField(name, millis); + public void jsonWrite(JsonGenerator generator, String name, T value) throws IOException { + + switch (mode) { + case ISO8601: { + generator.writeNumber(toJsonISO8601(value)); + break; + } + case NANOS: { + generator.writeNumber(toJsonNanos(value)); + break; + } + default: { + generator.writeNumberField(name, convertToMillis(value)); + } + } } public String formatValue(T t) { @@ -76,16 +132,12 @@ public abstract class ScalarTypeBaseDateTime extends ScalarTypeBase { return convertFromTimestamp(ts); } - public T parseDateTime(long systemTimeMillis) { - Timestamp ts = new Timestamp(systemTimeMillis); - return convertFromTimestamp(ts); - } public boolean isDateTimeCapable() { return true; } - public Object readData(DataInput dataInput) throws IOException { + public T readData(DataInput dataInput) throws IOException { if (!dataInput.readBoolean()) { return null; } else { @@ -95,10 +147,8 @@ public abstract class ScalarTypeBaseDateTime extends ScalarTypeBase { } } - @SuppressWarnings("unchecked") - public void writeData(DataOutput dataOutput, Object v) throws IOException { + public void writeData(DataOutput dataOutput, T value) throws IOException { - T value = (T) v; if (value == null) { dataOutput.writeBoolean(false); } else { diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBaseVarchar.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBaseVarchar.java index 0df4a1b06..750400b95 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBaseVarchar.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBaseVarchar.java @@ -86,7 +86,7 @@ public abstract class ScalarTypeBaseVarchar extends ScalarTypeBase { } @Override - public T parseDateTime(long systemTimeMillis) { + public T convertFromMillis(long systemTimeMillis) { throw new TextException("Not Supported"); } @@ -102,7 +102,7 @@ public abstract class ScalarTypeBaseVarchar extends ScalarTypeBase { } @Override - public Object readData(DataInput dataInput) throws IOException { + public T readData(DataInput dataInput) throws IOException { if (!dataInput.readBoolean()) { return null; } else { @@ -111,10 +111,8 @@ public abstract class ScalarTypeBaseVarchar extends ScalarTypeBase { } } - @SuppressWarnings("unchecked") - public void writeData(DataOutput dataOutput, Object v) throws IOException { + public void writeData(DataOutput dataOutput, T value) throws IOException { - T value = (T) v; if (value == null) { dataOutput.writeBoolean(false); } else { @@ -125,12 +123,12 @@ public abstract class ScalarTypeBaseVarchar extends ScalarTypeBase { } @Override - public Object jsonRead(JsonParser ctx, JsonToken event) throws IOException { + public T jsonRead(JsonParser ctx, JsonToken event) throws IOException { return parse(ctx.getValueAsString()); } @Override - public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException { + public void jsonWrite(JsonGenerator ctx, String name, T value) throws IOException { ctx.writeStringField(name, format(value)); } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBigDecimal.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBigDecimal.java index 4aee53063..23d4fad29 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBigDecimal.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBigDecimal.java @@ -17,75 +17,73 @@ import com.fasterxml.jackson.core.JsonToken; */ public class ScalarTypeBigDecimal extends ScalarTypeBase { - public ScalarTypeBigDecimal() { - super(BigDecimal.class, true, Types.DECIMAL); - } - - public Object readData(DataInput dataInput) throws IOException { - if (!dataInput.readBoolean()) { - return null; - } else { - double val = dataInput.readDouble(); - return new BigDecimal(val); - } + public ScalarTypeBigDecimal() { + super(BigDecimal.class, true, Types.DECIMAL); + } + + public BigDecimal readData(DataInput dataInput) throws IOException { + if (!dataInput.readBoolean()) { + return null; + } else { + double val = dataInput.readDouble(); + return new BigDecimal(val); } + } - public void writeData(DataOutput dataOutput, Object v) throws IOException { - - BigDecimal b = (BigDecimal)v; - if (b == null){ - dataOutput.writeBoolean(false); - } else { - dataOutput.writeBoolean(true); - dataOutput.writeDouble(b.doubleValue()); - } + public void writeData(DataOutput dataOutput, BigDecimal b) throws IOException { + + if (b == null) { + dataOutput.writeBoolean(false); + } else { + dataOutput.writeBoolean(true); + dataOutput.writeDouble(b.doubleValue()); } - - public void bind(DataBind b, BigDecimal value) throws SQLException { - if (value == null){ - b.setNull(Types.DECIMAL); - } else { - b.setBigDecimal(value); - } - } + } - public BigDecimal read(DataReader dataReader) throws SQLException { - - return dataReader.getBigDecimal(); - } - - public Object toJdbcType(Object value) { - return BasicTypeConverter.toBigDecimal(value); - } - - public BigDecimal toBeanType(Object value) { - return BasicTypeConverter.toBigDecimal(value); - } - - public String formatValue(BigDecimal t) { - return t.toPlainString(); + public void bind(DataBind b, BigDecimal value) throws SQLException { + if (value == null) { + b.setNull(Types.DECIMAL); + } else { + b.setBigDecimal(value); } + } - public BigDecimal parse(String value) { - return new BigDecimal(value); - } + public BigDecimal read(DataReader dataReader) throws SQLException { - public BigDecimal parseDateTime(long systemTimeMillis) { - return BigDecimal.valueOf(systemTimeMillis); - } + return dataReader.getBigDecimal(); + } - public boolean isDateTimeCapable() { - return true; - } + public Object toJdbcType(Object value) { + return BasicTypeConverter.toBigDecimal(value); + } + + public BigDecimal toBeanType(Object value) { + return BasicTypeConverter.toBigDecimal(value); + } + + public String formatValue(BigDecimal t) { + return t.toPlainString(); + } + + public BigDecimal parse(String value) { + return new BigDecimal(value); + } + + public BigDecimal convertFromMillis(long systemTimeMillis) { + return BigDecimal.valueOf(systemTimeMillis); + } + + public boolean isDateTimeCapable() { + return true; + } @Override - public Object jsonRead(JsonParser ctx, JsonToken event) throws IOException { + public BigDecimal jsonRead(JsonParser ctx, JsonToken event) throws IOException { return ctx.getDecimalValue(); } - - public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException { - ctx.writeNumberField(name, (BigDecimal)value); + + public void jsonWrite(JsonGenerator ctx, String name, BigDecimal value) throws IOException { + ctx.writeNumberField(name, (BigDecimal) value); } - } diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBoolean.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBoolean.java index 5a9db4c98..67780c3bb 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBoolean.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBoolean.java @@ -261,7 +261,7 @@ public class ScalarTypeBoolean { return Boolean.valueOf(value); } - public Boolean parseDateTime(long systemTimeMillis) { + public Boolean convertFromMillis(long systemTimeMillis) { throw new TextException("Not Supported"); } @@ -269,32 +269,30 @@ public class ScalarTypeBoolean { return false; } - public Object readData(DataInput dataInput) throws IOException { + public Boolean readData(DataInput dataInput) throws IOException { if (!dataInput.readBoolean()) { return null; } else { - boolean val = dataInput.readBoolean(); - return Boolean.valueOf(val); + return dataInput.readBoolean(); } } - public void writeData(DataOutput dataOutput, Object v) throws IOException { + public void writeData(DataOutput dataOutput, Boolean val) throws IOException { - Boolean val = (Boolean) v; if (val == null) { dataOutput.writeBoolean(false); } else { dataOutput.writeBoolean(true); - dataOutput.writeBoolean(val.booleanValue()); + dataOutput.writeBoolean(val); } } @Override - public Object jsonRead(JsonParser ctx, JsonToken event) { + public Boolean jsonRead(JsonParser ctx, JsonToken event) { return JsonToken.VALUE_TRUE == event ? Boolean.TRUE : Boolean.FALSE; } - public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException { + public void jsonWrite(JsonGenerator ctx, String name, Boolean value) throws IOException { ctx.writeBooleanField(name, (Boolean) value); } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeByte.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeByte.java index f92cccf94..1ac6dfcf2 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeByte.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeByte.java @@ -42,12 +42,12 @@ public class ScalarTypeByte extends ScalarTypeBase { } @Override - public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException { + public void jsonWrite(JsonGenerator ctx, String name, Byte value) throws IOException { throw new IOException("Not supported"); } @Override - public Object jsonRead(JsonParser ctx, JsonToken event) throws IOException { + public Byte jsonRead(JsonParser ctx, JsonToken event) throws IOException { throw new IOException("Not supported"); } @@ -59,7 +59,7 @@ public class ScalarTypeByte extends ScalarTypeBase { throw new TextException("Not supported"); } - public Byte parseDateTime(long systemTimeMillis) { + public Byte convertFromMillis(long systemTimeMillis) { throw new TextException("Not Supported"); } @@ -67,18 +67,16 @@ public class ScalarTypeByte extends ScalarTypeBase { return false; } - public Object readData(DataInput dataInput) throws IOException { + public Byte readData(DataInput dataInput) throws IOException { if (!dataInput.readBoolean()) { return null; } else { - byte val = dataInput.readByte(); - return Byte.valueOf(val); + return dataInput.readByte(); } } - public void writeData(DataOutput dataOutput, Object v) throws IOException { + public void writeData(DataOutput dataOutput, Byte val) throws IOException { - Byte val = (Byte) v; if (val == null) { dataOutput.writeBoolean(false); } else { diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBytesBase.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBytesBase.java index 73d198fbc..2f03c15aa 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBytesBase.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBytesBase.java @@ -45,12 +45,12 @@ public abstract class ScalarTypeBytesBase extends ScalarTypeBase { } @Override - public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException { + public void jsonWrite(JsonGenerator ctx, String name, byte[] value) throws IOException { ctx.writeBinaryField(name, (byte[]) value); } @Override - public Object jsonRead(JsonParser ctx, JsonToken event) throws IOException { + public byte[] jsonRead(JsonParser ctx, JsonToken event) throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(500); ctx.readBinaryValue(out); return out.toByteArray(); @@ -64,7 +64,7 @@ public abstract class ScalarTypeBytesBase extends ScalarTypeBase { throw new TextException("Not supported"); } - public byte[] parseDateTime(long systemTimeMillis) { + public byte[] convertFromMillis(long systemTimeMillis) { throw new TextException("Not supported"); } @@ -72,7 +72,7 @@ public abstract class ScalarTypeBytesBase extends ScalarTypeBase { return false; } - public Object readData(DataInput dataInput) throws IOException { + public byte[] readData(DataInput dataInput) throws IOException { if (!dataInput.readBoolean()) { return null; } else { @@ -83,10 +83,11 @@ public abstract class ScalarTypeBytesBase extends ScalarTypeBase { } } - public void writeData(DataOutput dataOutput, Object v) throws IOException { + public void writeData(DataOutput dataOutput, byte[] v) throws IOException { if (v == null) { dataOutput.writeBoolean(false); } else { + dataOutput.writeBoolean(true); byte[] bytes = convertToBytes(v); dataOutput.writeInt(bytes.length); dataOutput.write(bytes); diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBytesEncrypted.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBytesEncrypted.java index e2fe6aa48..4dfbc2b1f 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBytesEncrypted.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeBytesEncrypted.java @@ -67,12 +67,12 @@ public class ScalarTypeBytesEncrypted implements ScalarType { } @Override - public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException { + public void jsonWrite(JsonGenerator ctx, String name, byte[] value) throws IOException { ctx.writeBinaryField(name, (byte[]) value); } @Override - public Object jsonRead(JsonParser ctx, JsonToken event) throws IOException { + public byte[] jsonRead(JsonParser ctx, JsonToken event) throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(500); ctx.readBinaryValue(out); return out.toByteArray(); @@ -90,8 +90,8 @@ public class ScalarTypeBytesEncrypted implements ScalarType { return baseType.parse(value); } - public byte[] parseDateTime(long systemTimeMillis) { - return baseType.parseDateTime(systemTimeMillis); + public byte[] convertFromMillis(long systemTimeMillis) { + return baseType.convertFromMillis(systemTimeMillis); } public byte[] read(DataReader dataReader) throws SQLException { @@ -113,17 +113,26 @@ public class ScalarTypeBytesEncrypted implements ScalarType { baseType.accumulateScalarTypes(propName, list); } - public Object readData(DataInput dataInput) throws IOException { - int len = dataInput.readInt(); - byte[] value = new byte[len]; - dataInput.readFully(value); - return value; + public byte[] readData(DataInput dataInput) throws IOException { + if (!dataInput.readBoolean()) { + return null; + } else { + int len = dataInput.readInt(); + byte[] value = new byte[len]; + dataInput.readFully(value); + return value; + } } - public void writeData(DataOutput dataOutput, Object v) throws IOException { - byte[] value = (byte[]) v; - dataOutput.writeInt(value.length); - dataOutput.write(value); + public void writeData(DataOutput dataOutput, byte[] value) throws IOException { + + if (value == null) { + dataOutput.writeBoolean(false); + } else { + dataOutput.writeBoolean(true); + dataOutput.writeInt(value.length); + dataOutput.write(value); + } } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeCalendar.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeCalendar.java index ed214945d..ee790cc87 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeCalendar.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeCalendar.java @@ -6,6 +6,7 @@ import java.sql.Timestamp; import java.sql.Types; import java.util.Calendar; +import com.avaje.ebean.config.JsonConfig; import com.avaje.ebeaninternal.server.core.BasicTypeConverter; /** @@ -13,25 +14,32 @@ import com.avaje.ebeaninternal.server.core.BasicTypeConverter; */ public class ScalarTypeCalendar extends ScalarTypeBaseDateTime { - public ScalarTypeCalendar(int jdbcType) { - super(Calendar.class, false, jdbcType); + public ScalarTypeCalendar(JsonConfig.DateTime mode, int jdbcType) { + super(mode, Calendar.class, false, jdbcType); } public void bind(DataBind b, Calendar value) throws SQLException { if (value == null) { b.setNull(Types.TIMESTAMP); } else { - Calendar date = (Calendar) value; + if (jdbcType == Types.TIMESTAMP) { - Timestamp timestamp = new Timestamp(date.getTimeInMillis()); + Timestamp timestamp = new Timestamp(value.getTimeInMillis()); b.setTimestamp(timestamp); } else { - Date d = new Date(date.getTimeInMillis()); + Date d = new Date(value.getTimeInMillis()); b.setDate(d); } } } + @Override + public Calendar convertFromMillis(long systemTimeMillis) { + Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis(systemTimeMillis); + return calendar; + } + @Override public Calendar convertFromTimestamp(Timestamp ts) { Calendar calendar = Calendar.getInstance(); @@ -40,8 +48,18 @@ public class ScalarTypeCalendar extends ScalarTypeBaseDateTime { } @Override - public long convertToMillis(Object value) { - return ((Calendar) value).getTimeInMillis(); + protected String toJsonNanos(Calendar value) { + return String.valueOf(value.getTime()); + } + + @Override + protected String toJsonISO8601(Calendar value) { + return dateTimeParser.format(value.getTime()); + } + + @Override + public long convertToMillis(Calendar value) { + return value.getTimeInMillis(); } @Override @@ -49,10 +67,12 @@ public class ScalarTypeCalendar extends ScalarTypeBaseDateTime { return new Timestamp(t.getTimeInMillis()); } + @Override public Object toJdbcType(Object value) { return BasicTypeConverter.convert(value, jdbcType); } + @Override public Calendar toBeanType(Object value) { return BasicTypeConverter.toCalendar(value); } diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeCharArray.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeCharArray.java index f9e96f15c..ec947202f 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeCharArray.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeCharArray.java @@ -64,11 +64,11 @@ public class ScalarTypeCharArray extends ScalarTypeBaseVarchar { } @Override - public Object jsonRead(JsonParser ctx, JsonToken event) throws IOException { + public char[] jsonRead(JsonParser ctx, JsonToken event) throws IOException { return ctx.getValueAsString().toCharArray(); } - public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException { + public void jsonWrite(JsonGenerator ctx, String name, char[] value) throws IOException { ctx.writeStringField(name, String.valueOf(value)); } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeDouble.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeDouble.java index fa27077d4..10b5c97fe 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeDouble.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeDouble.java @@ -55,7 +55,7 @@ public class ScalarTypeDouble extends ScalarTypeBase { } @Override - public Double parseDateTime(long systemTimeMillis) { + public Double convertFromMillis(long systemTimeMillis) { return Double.valueOf(systemTimeMillis); } @@ -65,34 +65,32 @@ public class ScalarTypeDouble extends ScalarTypeBase { } @Override - public Object readData(DataInput dataInput) throws IOException { + public Double readData(DataInput dataInput) throws IOException { if (!dataInput.readBoolean()) { return null; } else { - double val = dataInput.readDouble(); - return Double.valueOf(val); + return dataInput.readDouble(); } } @Override - public void writeData(DataOutput dataOutput, Object v) throws IOException { + public void writeData(DataOutput dataOutput, Double value) throws IOException { - Double value = (Double) v; if (value == null) { dataOutput.writeBoolean(false); } else { dataOutput.writeBoolean(true); - dataOutput.writeDouble(value.doubleValue()); + dataOutput.writeDouble(value); } } @Override - public Object jsonRead(JsonParser ctx, JsonToken event) throws IOException { + public Double jsonRead(JsonParser ctx, JsonToken event) throws IOException { return ctx.getDoubleValue(); } @Override - public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException { - ctx.writeNumberField(name, (Double) value); + public void jsonWrite(JsonGenerator ctx, String name, Double value) throws IOException { + ctx.writeNumberField(name, value); } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeDuration.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeDuration.java new file mode 100644 index 000000000..23cbbcd42 --- /dev/null +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeDuration.java @@ -0,0 +1,104 @@ +package com.avaje.ebeaninternal.server.type; + +import com.avaje.ebean.text.TextException; +import com.avaje.ebeaninternal.server.core.BasicTypeConverter; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.sql.SQLException; +import java.sql.Types; +import java.time.Duration; +import java.time.LocalTime; + +/** + * ScalarType for java.time.Duration + */ +public class ScalarTypeDuration extends ScalarTypeBase { + + public ScalarTypeDuration() { + super(Duration.class, false, Types.BIGINT); + } + + protected ScalarTypeDuration(int jdbcType) { + super(Duration.class, false, jdbcType); + } + + @Override + public void bind(DataBind bind, Duration value) throws SQLException { + if (value == null) { + bind.setNull(Types.BIGINT); + } else { + bind.setLong(value.getSeconds()); + } + } + + @Override + public Duration read(DataReader dataReader) throws SQLException { + return Duration.ofSeconds(dataReader.getLong()); + } + + @Override + public Duration readData(DataInput dataInput) throws IOException { + if (!dataInput.readBoolean()) { + return null; + } else { + return Duration.ofSeconds(dataInput.readLong()); + } + } + + @Override + public void writeData(DataOutput dataOutput, Duration value) throws IOException { + if (value == null) { + dataOutput.writeBoolean(false); + } else { + dataOutput.writeBoolean(true); + dataOutput.writeLong(value.getSeconds()); + } + } + + @Override + public Object toJdbcType(Object value) { + if (value instanceof Long) return value; + return ((Duration)value).getSeconds(); + } + + @Override + public Duration toBeanType(Object value) { + if (value instanceof Duration) return (Duration) value; + return Duration.ofSeconds(BasicTypeConverter.toLong(value)); + } + + @Override + public String formatValue(Duration v) { + return v.toString(); + } + + @Override + public Duration parse(String value) { + return Duration.parse(value); + } + + @Override + public boolean isDateTimeCapable() { + return false; + } + + @Override + public Duration convertFromMillis(long systemTimeMillis) { + throw new TextException("Not Supported"); + } + + @Override + public Duration jsonRead(JsonParser ctx, JsonToken event) throws IOException { + return Duration.parse(ctx.getValueAsString()); + } + + @Override + public void jsonWrite(JsonGenerator ctx, String name, Duration value) throws IOException { + ctx.writeStringField(name, value.toString()); + } +} diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeDurationWithNanos.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeDurationWithNanos.java new file mode 100644 index 000000000..78d792614 --- /dev/null +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeDurationWithNanos.java @@ -0,0 +1,82 @@ +package com.avaje.ebeaninternal.server.type; + +import com.avaje.ebean.text.TextException; +import com.avaje.ebeaninternal.server.core.BasicTypeConverter; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.math.BigDecimal; +import java.sql.SQLException; +import java.sql.Types; +import java.time.Duration; + +/** + * ScalarType for java.time.Duration with Nanos precision. + *

+ * Stored in the DB as DECIMAL value. + *

+ */ +public class ScalarTypeDurationWithNanos extends ScalarTypeDuration { + + public ScalarTypeDurationWithNanos() { + super(Types.DECIMAL); + } + + public BigDecimal convertToBigDecimal(Duration value) { + return DecimalUtils.toDecimal(value); + } + + public Duration convertFromBigDecimal(BigDecimal value) { + return DecimalUtils.toDuration(value); + } + + @Override + public void bind(DataBind bind, Duration value) throws SQLException { + if (value == null) { + bind.setNull(Types.DECIMAL); + } else { + bind.setBigDecimal(convertToBigDecimal(value)); + } + } + + @Override + public Duration read(DataReader dataReader) throws SQLException { + return convertFromBigDecimal(dataReader.getBigDecimal()); + } + + @Override + public Duration readData(DataInput dataInput) throws IOException { + if (!dataInput.readBoolean()) { + return null; + } else { + return convertFromBigDecimal(new BigDecimal(dataInput.readUTF())); + } + } + + @Override + public void writeData(DataOutput dataOutput, Duration value) throws IOException { + if (value == null) { + dataOutput.writeBoolean(false); + } else { + dataOutput.writeBoolean(true); + dataOutput.writeUTF(convertToBigDecimal(value).toString()); + } + } + + @Override + public Object toJdbcType(Object value) { + if (value instanceof BigDecimal) return value; + return convertToBigDecimal((Duration)value); + } + + @Override + public Duration toBeanType(Object value) { + if (value instanceof Duration) return (Duration) value; + return convertFromBigDecimal(BasicTypeConverter.toBigDecimal(value)); + } + +} diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeEncryptedWrapper.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeEncryptedWrapper.java index 9c3eeccdf..041fd9471 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeEncryptedWrapper.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeEncryptedWrapper.java @@ -34,12 +34,12 @@ public class ScalarTypeEncryptedWrapper implements ScalarType { } @Override - public Object readData(DataInput dataInput) throws IOException { + public T readData(DataInput dataInput) throws IOException { return wrapped.readData(dataInput); } @Override - public void writeData(DataOutput dataOutput, Object v) throws IOException { + public void writeData(DataOutput dataOutput, T v) throws IOException { wrapped.writeData(dataOutput, v); } @@ -113,8 +113,8 @@ public class ScalarTypeEncryptedWrapper implements ScalarType { } @Override - public T parseDateTime(long systemTimeMillis) { - return wrapped.parseDateTime(systemTimeMillis); + public T convertFromMillis(long systemTimeMillis) { + return wrapped.convertFromMillis(systemTimeMillis); } @Override @@ -133,12 +133,12 @@ public class ScalarTypeEncryptedWrapper implements ScalarType { } @Override - public Object jsonRead(JsonParser ctx, JsonToken event) throws IOException { + public T jsonRead(JsonParser ctx, JsonToken event) throws IOException { return wrapped.jsonRead(ctx, event); } @Override - public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException { + public void jsonWrite(JsonGenerator ctx, String name, T value) throws IOException { wrapped.jsonWrite(ctx, name, value); } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeEnumStandard.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeEnumStandard.java index 6fdfb1e72..19ee664d6 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeEnumStandard.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeEnumStandard.java @@ -222,7 +222,7 @@ public class ScalarTypeEnumStandard { } @Override - public Object parseDateTime(long systemTimeMillis) { + public Object convertFromMillis(long systemTimeMillis) { throw new TextException("Not Supported"); } diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeFloat.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeFloat.java index 7fee93bd7..96807eab4 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeFloat.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeFloat.java @@ -55,7 +55,7 @@ public class ScalarTypeFloat extends ScalarTypeBase { } @Override - public Float parseDateTime(long systemTimeMillis) { + public Float convertFromMillis(long systemTimeMillis) { return Float.valueOf(systemTimeMillis); } @@ -65,7 +65,7 @@ public class ScalarTypeFloat extends ScalarTypeBase { } @Override - public Object readData(DataInput dataInput) throws IOException { + public Float readData(DataInput dataInput) throws IOException { if (!dataInput.readBoolean()) { return null; } else { @@ -75,24 +75,23 @@ public class ScalarTypeFloat extends ScalarTypeBase { } @Override - public void writeData(DataOutput dataOutput, Object v) throws IOException { + public void writeData(DataOutput dataOutput, Float value) throws IOException { - Float value = (Float) v; if (value == null) { dataOutput.writeBoolean(false); } else { dataOutput.writeBoolean(true); - dataOutput.writeFloat(value.floatValue()); + dataOutput.writeFloat(value); } } @Override - public Object jsonRead(JsonParser ctx, JsonToken event) throws IOException { + public Float jsonRead(JsonParser ctx, JsonToken event) throws IOException { return ctx.getFloatValue(); } @Override - public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException { + public void jsonWrite(JsonGenerator ctx, String name, Float value) throws IOException { ctx.writeNumberField(name, (Float) value); } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeInstant.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeInstant.java new file mode 100644 index 000000000..00997022d --- /dev/null +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeInstant.java @@ -0,0 +1,59 @@ +package com.avaje.ebeaninternal.server.type; + +import com.avaje.ebean.config.JsonConfig; + +import java.sql.Timestamp; +import java.sql.Types; +import java.time.Instant; + +/** + * ScalarType for java.sql.Timestamp. + */ +public class ScalarTypeInstant extends ScalarTypeBaseDateTime { + + public ScalarTypeInstant(JsonConfig.DateTime mode) { + super(mode, Instant.class, true, Types.TIMESTAMP); + } + + @Override + protected String toJsonNanos(Instant value) { + return toJsonNanos(value.getEpochSecond(), value.getNano()); + } + + @Override + protected String toJsonISO8601(Instant value) { + return value.toString(); + } + + @Override + public long convertToMillis(Instant value) { + return value.toEpochMilli(); + } + + @Override + public Instant convertFromMillis(long systemTimeMillis) { + return Instant.ofEpochMilli(systemTimeMillis); + } + + @Override + public Instant convertFromTimestamp(Timestamp ts) { + return ts.toInstant(); + } + + @Override + public Timestamp convertToTimestamp(Instant t) { + return Timestamp.from(t); + } + + @Override + public Object toJdbcType(Object value) { + if (value instanceof Timestamp) return value; + return convertToTimestamp((Instant) value); + } + + @Override + public Instant toBeanType(Object value) { + if (value instanceof Instant) return (Instant) value; + return convertFromTimestamp((Timestamp) value); + } +} diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeInteger.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeInteger.java index 101e84a6c..3199fb609 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeInteger.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeInteger.java @@ -36,13 +36,22 @@ public class ScalarTypeInteger extends ScalarTypeBase { } @Override - public Object readData(DataInput dataInput) throws IOException { - return Integer.valueOf(dataInput.readInt()); + public Integer readData(DataInput dataInput) throws IOException { + if (!dataInput.readBoolean()) { + return null; + } else { + return Integer.valueOf(dataInput.readInt()); + } } @Override - public void writeData(DataOutput dataOutput, Object v) throws IOException { - dataOutput.writeInt((Integer) v); + public void writeData(DataOutput dataOutput, Integer value) throws IOException { + if (value == null) { + dataOutput.writeBoolean(false); + } else { + dataOutput.writeBoolean(true); + dataOutput.writeInt(value); + } } @Override @@ -66,7 +75,7 @@ public class ScalarTypeInteger extends ScalarTypeBase { } @Override - public Integer parseDateTime(long systemTimeMillis) { + public Integer convertFromMillis(long systemTimeMillis) { throw new TextException("Not Supported"); } @@ -76,12 +85,12 @@ public class ScalarTypeInteger extends ScalarTypeBase { } @Override - public Object jsonRead(JsonParser ctx, JsonToken event) throws IOException { + public Integer jsonRead(JsonParser ctx, JsonToken event) throws IOException { return ctx.getIntValue(); } @Override - public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException { - ctx.writeNumberField(name, (Integer) value); + public void jsonWrite(JsonGenerator ctx, String name, Integer value) throws IOException { + ctx.writeNumberField(name, value); } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeJodaDateTime.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeJodaDateTime.java index 5df0cf9b4..9f0d5de86 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeJodaDateTime.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeJodaDateTime.java @@ -3,22 +3,39 @@ package com.avaje.ebeaninternal.server.type; import java.sql.Timestamp; import java.sql.Types; +import com.avaje.ebean.config.JsonConfig; import org.joda.time.DateTime; import com.avaje.ebeaninternal.server.core.BasicTypeConverter; +import org.joda.time.LocalDateTime; /** * ScalarType for Joda DateTime. This maps to a JDBC Timestamp. */ public class ScalarTypeJodaDateTime extends ScalarTypeBaseDateTime { - public ScalarTypeJodaDateTime() { - super(DateTime.class, false, Types.TIMESTAMP); + public ScalarTypeJodaDateTime(JsonConfig.DateTime mode) { + super(mode, DateTime.class, false, Types.TIMESTAMP); } @Override - public long convertToMillis(Object value) { - return ((DateTime) value).getMillis(); + public long convertToMillis(DateTime value) { + return value.getMillis(); + } + + @Override + protected String toJsonNanos(DateTime value) { + return String.valueOf(value.toDateTime().getMillis()); + } + + @Override + protected String toJsonISO8601(DateTime value) { + return value.toString(); + } + + @Override + public DateTime convertFromMillis(long systemTimeMillis) { + return new DateTime(systemTimeMillis); } @Override diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeJodaLocalDate.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeJodaLocalDate.java index 1fe6822dd..20f125361 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeJodaLocalDate.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeJodaLocalDate.java @@ -48,7 +48,7 @@ public class ScalarTypeJodaLocalDate extends ScalarTypeBaseDate { } @Override - public LocalDate parseDateTime(long systemTimeMillis) { + public LocalDate convertFromMillis(long systemTimeMillis) { return new LocalDate(systemTimeMillis); } diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeJodaLocalDateTime.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeJodaLocalDateTime.java index d139a5da2..8f4c57745 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeJodaLocalDateTime.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeJodaLocalDateTime.java @@ -2,7 +2,9 @@ package com.avaje.ebeaninternal.server.type; import java.sql.Timestamp; import java.sql.Types; +import java.util.Date; +import com.avaje.ebean.config.JsonConfig; import org.joda.time.LocalDateTime; import com.avaje.ebeaninternal.server.core.BasicTypeConverter; @@ -12,13 +14,29 @@ import com.avaje.ebeaninternal.server.core.BasicTypeConverter; */ public class ScalarTypeJodaLocalDateTime extends ScalarTypeBaseDateTime { - public ScalarTypeJodaLocalDateTime() { - super(LocalDateTime.class, false, Types.TIMESTAMP); + public ScalarTypeJodaLocalDateTime(JsonConfig.DateTime mode) { + super(mode, LocalDateTime.class, false, Types.TIMESTAMP); } @Override - public long convertToMillis(Object value) { - return ((LocalDateTime) value).toDateTime().getMillis(); + protected String toJsonNanos(LocalDateTime value) { + return String.valueOf(value.toDateTime().getMillis()); + } + + @Override + protected String toJsonISO8601(LocalDateTime value) { + return value.toString(); + } + + @Override + public long convertToMillis(LocalDateTime value) { + return value.toDateTime().getMillis(); + } + + + @Override + public LocalDateTime convertFromMillis(long systemTimeMillis) { + return new LocalDateTime(systemTimeMillis); } @Override @@ -47,9 +65,4 @@ public class ScalarTypeJodaLocalDateTime extends ScalarTypeBaseDateTime { } @Override - public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException { + public void jsonWrite(JsonGenerator ctx, String name, LocalTime value) throws IOException { ctx.writeStringField(name, value.toString()); } @Override - public Object jsonRead(JsonParser ctx, JsonToken event) throws IOException { + public LocalTime jsonRead(JsonParser ctx, JsonToken event) throws IOException { if (JsonToken.VALUE_NUMBER_INT == event) { long millis = ctx.getLongValue(); - return parseDateTime(millis); + return convertFromMillis(millis); } else { String string = ctx.getValueAsString(); throw new RuntimeException("convert " + string); @@ -88,7 +88,7 @@ public class ScalarTypeJodaLocalTime extends ScalarTypeBase { } @Override - public LocalTime parseDateTime(long systemTimeMillis) { + public LocalTime convertFromMillis(long systemTimeMillis) { return new LocalTime(systemTimeMillis); } @@ -98,7 +98,7 @@ public class ScalarTypeJodaLocalTime extends ScalarTypeBase { } @Override - public Object readData(DataInput dataInput) throws IOException { + public LocalTime readData(DataInput dataInput) throws IOException { if (!dataInput.readBoolean()) { return null; } else { @@ -108,9 +108,8 @@ public class ScalarTypeJodaLocalTime extends ScalarTypeBase { } @Override - public void writeData(DataOutput dataOutput, Object v) throws IOException { + public void writeData(DataOutput dataOutput, LocalTime value) throws IOException { - Time value = (Time) v; if (value == null) { dataOutput.writeBoolean(false); } else { diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalDate.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalDate.java index d69073fee..ed83eb957 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalDate.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalDate.java @@ -52,7 +52,7 @@ public class ScalarTypeLocalDate extends ScalarTypeBaseDate { } @Override - public LocalDate parseDateTime(long systemTimeMillis) { + public LocalDate convertFromMillis(long systemTimeMillis) { return new Timestamp(systemTimeMillis).toLocalDateTime().toLocalDate(); } diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalDateTime.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalDateTime.java index 3a937910b..2bce3d064 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalDateTime.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalDateTime.java @@ -1,21 +1,40 @@ package com.avaje.ebeaninternal.server.type; +import com.avaje.ebean.config.JsonConfig; + import java.sql.Timestamp; import java.sql.Types; -import java.time.*; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; /** * ScalarType for java.sql.Timestamp. */ public class ScalarTypeLocalDateTime extends ScalarTypeBaseDateTime { - public ScalarTypeLocalDateTime() { - super(LocalDateTime.class, true, Types.TIMESTAMP); + public ScalarTypeLocalDateTime(JsonConfig.DateTime mode) { + super(mode, LocalDateTime.class, true, Types.TIMESTAMP); } @Override - public long convertToMillis(Object value) { - return ((LocalDateTime) value).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(); + public LocalDateTime convertFromMillis(long systemTimeMillis) { + return new Timestamp(systemTimeMillis).toLocalDateTime(); + } + + @Override + public long convertToMillis(LocalDateTime value) { + return value.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(); + } + + @Override + protected String toJsonNanos(LocalDateTime value) { + return String.valueOf(convertToMillis(value)); + } + + @Override + protected String toJsonISO8601(LocalDateTime value) { + return value.toString(); } @Override diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalTime.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalTime.java new file mode 100644 index 000000000..b8a24312c --- /dev/null +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLocalTime.java @@ -0,0 +1,100 @@ +package com.avaje.ebeaninternal.server.type; + +import com.avaje.ebean.text.TextException; +import com.avaje.ebeaninternal.server.core.BasicTypeConverter; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.sql.SQLException; +import java.sql.Types; +import java.time.LocalTime; +import java.time.Year; + +/** + * ScalarType for java.time.Year + */ +public class ScalarTypeLocalTime extends ScalarTypeBase { + + public ScalarTypeLocalTime() { + super(LocalTime.class, true, Types.BIGINT); + } + + @Override + public void bind(DataBind bind, LocalTime value) throws SQLException { + if (value == null) { + bind.setNull(Types.BIGINT); + } else { + bind.setLong(value.toNanoOfDay()); + } + } + + @Override + public LocalTime read(DataReader dataReader) throws SQLException { + return LocalTime.ofNanoOfDay(dataReader.getLong()); + } + + @Override + public LocalTime readData(DataInput dataInput) throws IOException { + if (!dataInput.readBoolean()) { + return null; + } else { + return LocalTime.ofNanoOfDay(dataInput.readLong()); + } + } + + @Override + public void writeData(DataOutput dataOutput, LocalTime value) throws IOException { + if (value == null) { + dataOutput.writeBoolean(false); + } else { + dataOutput.writeBoolean(true); + dataOutput.writeLong(value.toNanoOfDay()); + } + } + + @Override + public Object toJdbcType(Object value) { + if (value instanceof Long) return value; + return ((LocalTime)value).toNanoOfDay(); + } + + @Override + public LocalTime toBeanType(Object value) { + if (value instanceof LocalTime) return (LocalTime) value; + return LocalTime.ofNanoOfDay(BasicTypeConverter.toLong(value)); + } + + @Override + public String formatValue(LocalTime v) { + return v.toString(); + } + + @Override + public LocalTime parse(String value) { + return LocalTime.parse(value); + } + + @Override + public boolean isDateTimeCapable() { + return false; + } + + @Override + public LocalTime convertFromMillis(long systemTimeMillis) { + throw new TextException("Not Supported"); + } + + @Override + public LocalTime jsonRead(JsonParser ctx, JsonToken event) throws IOException { + return LocalTime.parse(ctx.getValueAsString()); + } + + @Override + public void jsonWrite(JsonGenerator ctx, String name, LocalTime value) throws IOException { + ctx.writeStringField(name, value.toString()); + } +} diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLong.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLong.java index 1427553b4..1bf541144 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLong.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLong.java @@ -55,8 +55,8 @@ public class ScalarTypeLong extends ScalarTypeBase { } @Override - public Long parseDateTime(long systemTimeMillis) { - return Long.valueOf(systemTimeMillis); + public Long convertFromMillis(long systemTimeMillis) { + return systemTimeMillis; } @Override @@ -65,34 +65,32 @@ public class ScalarTypeLong extends ScalarTypeBase { } @Override - public Object readData(DataInput dataInput) throws IOException { + public Long readData(DataInput dataInput) throws IOException { if (!dataInput.readBoolean()) { return null; } else { - long val = dataInput.readLong(); - return Long.valueOf(val); + return dataInput.readLong(); } } @Override - public void writeData(DataOutput dataOutput, Object v) throws IOException { + public void writeData(DataOutput dataOutput, Long value) throws IOException { - Long value = (Long) v; if (value == null) { dataOutput.writeBoolean(false); } else { dataOutput.writeBoolean(true); - dataOutput.writeLong(value.longValue()); + dataOutput.writeLong(value); } } @Override - public Object jsonRead(JsonParser ctx, JsonToken event) throws IOException { + public Long jsonRead(JsonParser ctx, JsonToken event) throws IOException { return ctx.getLongValue(); } @Override - public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException { + public void jsonWrite(JsonGenerator ctx, String name, Long value) throws IOException { ctx.writeNumberField(name, (Long) value); } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLongToTimestamp.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLongToTimestamp.java index d01d67469..7a9b119d2 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLongToTimestamp.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeLongToTimestamp.java @@ -1,10 +1,12 @@ package com.avaje.ebeaninternal.server.type; +import com.avaje.ebean.config.JsonConfig; + import java.sql.Timestamp; public class ScalarTypeLongToTimestamp extends ScalarTypeWrapper { - public ScalarTypeLongToTimestamp() { - super(Long.class, new ScalarTypeTimestamp(), new LongToTimestampConverter()); + public ScalarTypeLongToTimestamp(JsonConfig.DateTime mode) { + super(Long.class, new ScalarTypeTimestamp(mode), new LongToTimestampConverter()); } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeMathBigInteger.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeMathBigInteger.java index 1ea865e7a..521462b65 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeMathBigInteger.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeMathBigInteger.java @@ -3,9 +3,11 @@ package com.avaje.ebeaninternal.server.type; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; +import java.math.BigDecimal; import java.math.BigInteger; import java.sql.SQLException; import java.sql.Types; +import java.time.Instant; import com.avaje.ebeaninternal.server.core.BasicTypeConverter; import com.fasterxml.jackson.core.JsonGenerator; @@ -61,7 +63,7 @@ public class ScalarTypeMathBigInteger extends ScalarTypeBase { } @Override - public BigInteger parseDateTime(long systemTimeMillis) { + public BigInteger convertFromMillis(long systemTimeMillis) { return BigInteger.valueOf(systemTimeMillis); } @@ -71,19 +73,18 @@ public class ScalarTypeMathBigInteger extends ScalarTypeBase { } @Override - public Object readData(DataInput dataInput) throws IOException { + public BigInteger readData(DataInput dataInput) throws IOException { if (!dataInput.readBoolean()) { return null; } else { long val = dataInput.readLong(); - return Long.valueOf(val); + return BigInteger.valueOf(val); } } @Override - public void writeData(DataOutput dataOutput, Object v) throws IOException { + public void writeData(DataOutput dataOutput, BigInteger value) throws IOException { - Long value = (Long) v; if (value == null) { dataOutput.writeBoolean(false); } else { @@ -93,12 +94,12 @@ public class ScalarTypeMathBigInteger extends ScalarTypeBase { } @Override - public Object jsonRead(JsonParser ctx, JsonToken event) throws IOException { + public BigInteger jsonRead(JsonParser ctx, JsonToken event) throws IOException { return ctx.getDecimalValue().toBigInteger(); } @Override - public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException { + public void jsonWrite(JsonGenerator ctx, String name, BigInteger value) throws IOException { ctx.writeNumberField(name, ((BigInteger) value).longValue()); } diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeOffsetDateTime.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeOffsetDateTime.java index 8fc004792..9a5d99750 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeOffsetDateTime.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeOffsetDateTime.java @@ -1,7 +1,10 @@ package com.avaje.ebeaninternal.server.type; +import com.avaje.ebean.config.JsonConfig; + import java.sql.Timestamp; import java.sql.Types; +import java.time.Instant; import java.time.OffsetDateTime; import java.time.ZoneId; @@ -10,13 +13,28 @@ import java.time.ZoneId; */ public class ScalarTypeOffsetDateTime extends ScalarTypeBaseDateTime { - public ScalarTypeOffsetDateTime() { - super(OffsetDateTime.class, true, Types.TIMESTAMP); + public ScalarTypeOffsetDateTime(JsonConfig.DateTime mode) { + super(mode, OffsetDateTime.class, true, Types.TIMESTAMP); } @Override - public long convertToMillis(Object value) { - return ((OffsetDateTime) value).toInstant().toEpochMilli(); + protected String toJsonNanos(OffsetDateTime value) { + return toJsonNanos(value.toEpochSecond(), value.getNano()); + } + + @Override + protected String toJsonISO8601(OffsetDateTime value) { + return value.toString(); + } + + @Override + public long convertToMillis(OffsetDateTime value) { + return value.toInstant().toEpochMilli(); + } + + @Override + public OffsetDateTime convertFromMillis(long systemTimeMillis) { + return OffsetDateTime.ofInstant(Instant.ofEpochMilli(systemTimeMillis), ZoneId.systemDefault()); } @Override diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypePostgresHstore.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypePostgresHstore.java index 847f5fc4b..7b8a0e4c8 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypePostgresHstore.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypePostgresHstore.java @@ -88,7 +88,7 @@ public class ScalarTypePostgresHstore extends ScalarTypeBase { } @Override - public Map parseDateTime(long dateTime) { + public Map convertFromMillis(long dateTime) { throw new RuntimeException("Should never be called"); } @@ -98,19 +98,28 @@ public class ScalarTypePostgresHstore extends ScalarTypeBase { } @Override - public Object readData(DataInput dataInput) throws IOException { - String json = dataInput.readUTF(); - return parse(json); + public Map readData(DataInput dataInput) throws IOException { + if (!dataInput.readBoolean()) { + return null; + } else { + String json = dataInput.readUTF(); + return parse(json); + } } @Override - public void writeData(DataOutput dataOutput, Object v) throws IOException { - String json = format(v); - dataOutput.writeUTF(json); + public void writeData(DataOutput dataOutput, Map v) throws IOException { + if (v == null) { + dataOutput.writeBoolean(false); + } else { + dataOutput.writeBoolean(true); + String json = format(v); + dataOutput.writeUTF(json); + } } @Override - public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException { + public void jsonWrite(JsonGenerator ctx, String name, Map value) throws IOException { // write the field name followed by the Map/JSON Object if (value == null) { ctx.writeNullField(name); @@ -121,7 +130,7 @@ public class ScalarTypePostgresHstore extends ScalarTypeBase { } @Override - public Object jsonRead(JsonParser ctx, JsonToken event) throws IOException { + public Map jsonRead(JsonParser ctx, JsonToken event) throws IOException { // at this point the BeanProperty has read the START_OBJECT token // to check for a null value. Pass the START_OBJECT token through to // the EJson parsing so that it knows the first token has been read diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeShort.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeShort.java index 6d6245897..9c9871251 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeShort.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeShort.java @@ -56,7 +56,7 @@ public class ScalarTypeShort extends ScalarTypeBase { } @Override - public Short parseDateTime(long systemTimeMillis) { + public Short convertFromMillis(long systemTimeMillis) { throw new TextException("Not Supported"); } @@ -66,34 +66,32 @@ public class ScalarTypeShort extends ScalarTypeBase { } @Override - public Object readData(DataInput dataInput) throws IOException { + public Short readData(DataInput dataInput) throws IOException { if (!dataInput.readBoolean()) { return null; } else { - short val = dataInput.readShort(); - return Short.valueOf(val); + return dataInput.readShort(); } } @Override - public void writeData(DataOutput dataOutput, Object v) throws IOException { + public void writeData(DataOutput dataOutput, Short value) throws IOException { - Short value = (Short) v; if (value == null) { dataOutput.writeBoolean(false); } else { dataOutput.writeBoolean(true); - dataOutput.writeShort(value.shortValue()); + dataOutput.writeShort(value); } } @Override - public Object jsonRead(JsonParser ctx, JsonToken event) throws IOException { + public Short jsonRead(JsonParser ctx, JsonToken event) throws IOException { return ctx.getShortValue(); } @Override - public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException { + public void jsonWrite(JsonGenerator ctx, String name, Short value) throws IOException { ctx.writeNumberField(name, (Short) value); } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeString.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeString.java index a66153e74..9584d26a7 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeString.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeString.java @@ -55,7 +55,7 @@ public class ScalarTypeString extends ScalarTypeBase { } @Override - public String parseDateTime(long systemTimeMillis) { + public String convertFromMillis(long systemTimeMillis) { return String.valueOf(systemTimeMillis); } @@ -65,7 +65,7 @@ public class ScalarTypeString extends ScalarTypeBase { } @Override - public Object readData(DataInput dataInput) throws IOException { + public String readData(DataInput dataInput) throws IOException { if (!dataInput.readBoolean()) { return null; } else { @@ -74,9 +74,8 @@ public class ScalarTypeString extends ScalarTypeBase { } @Override - public void writeData(DataOutput dataOutput, Object v) throws IOException { + public void writeData(DataOutput dataOutput, String value) throws IOException { - String value = (String) v; if (value == null) { dataOutput.writeBoolean(false); } else { @@ -86,12 +85,12 @@ public class ScalarTypeString extends ScalarTypeBase { } @Override - public Object jsonRead(JsonParser ctx, JsonToken event) throws IOException { + public String jsonRead(JsonParser ctx, JsonToken event) throws IOException { return ctx.getValueAsString(); } @Override - public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException { + public void jsonWrite(JsonGenerator ctx, String name, String value) throws IOException { ctx.writeStringField(name, (String) value); } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeTime.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeTime.java index 5568ff179..955430f65 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeTime.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeTime.java @@ -56,7 +56,7 @@ public class ScalarTypeTime extends ScalarTypeBase