From 483f0398b2d9ded9685b7566ac8b8ca4c13f97cf Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Wed, 24 Nov 2021 14:37:45 +0100 Subject: [PATCH 01/10] Fix: 'No ScalarType registered for class java.util.GregorianCalendar' - check all registered scalar type if no exact match was found --- .../io/ebeaninternal/server/type/DefaultTypeManager.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java index 544d8433e..42c9e2ded 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java @@ -43,6 +43,7 @@ import java.sql.Timestamp; import java.sql.Types; import java.time.*; import java.util.*; +import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; /** @@ -281,8 +282,11 @@ public final class DefaultTypeManager implements TypeManager { } private ScalarType checkInterfaceTypes(Class type) { - if (java.nio.file.Path.class.isAssignableFrom(type)) { - return typeMap.get(java.nio.file.Path.class); + for (Entry, ScalarType> entry : typeMap.entrySet()) { + if (entry.getKey().isAssignableFrom(type)) { + typeMap.put(type, entry.getValue()); + return entry.getValue(); + } } return null; } From 84ac737ceb7d62da9f46eea06d5f2bcde6d4fce3 Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Thu, 2 Dec 2021 10:13:15 +0100 Subject: [PATCH 02/10] ADD: Testcase for Calendar --- .../io/ebeaninternal/server/type/TestTypeManager.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/ebean-test/src/test/java/io/ebeaninternal/server/type/TestTypeManager.java b/ebean-test/src/test/java/io/ebeaninternal/server/type/TestTypeManager.java index c28da92a7..383671363 100644 --- a/ebean-test/src/test/java/io/ebeaninternal/server/type/TestTypeManager.java +++ b/ebean-test/src/test/java/io/ebeaninternal/server/type/TestTypeManager.java @@ -15,6 +15,8 @@ import org.tests.model.ivo.converter.MoneyTypeConverter; import javax.persistence.EnumType; import java.sql.SQLException; import java.sql.Types; +import java.util.Calendar; +import java.util.GregorianCalendar; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; @@ -29,7 +31,6 @@ public class TestTypeManager extends BaseTestCase { DefaultTypeManager typeManager = createTypeManager(); ScalarType type = typeManager.createEnumScalarType(MyEnum.class, null); - typeManager.addEnumType(type, MyEnum.class); Object val = type.read(new DummyDataReader("A")); assertThat(val).isEqualTo(MyEnum.Aval); @@ -131,6 +132,13 @@ public class TestTypeManager extends BaseTestCase { return new DefaultTypeManager(config, bootupClasses); } + @Test + public void testCalendar() throws SQLException { + + DefaultTypeManager typeManager = createTypeManager(); + ScalarType typeB = typeManager.getScalarType(GregorianCalendar.class); + assertThat(typeB).isInstanceOf(ScalarTypeCalendar.class); + } /** * Test double DataReader implementation. */ From f830662cce91e550f08a02f6b6646977a8817cef Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Thu, 2 Dec 2021 11:18:22 +0100 Subject: [PATCH 03/10] Improve TypeManager - cache typeNotFound information. --- .../server/type/DefaultTypeManager.java | 76 +++++----- .../server/type/ScalarTypeNotFound.java | 140 ++++++++++++++++++ .../server/type/TypeManager.java | 6 - 3 files changed, 179 insertions(+), 43 deletions(-) create mode 100644 ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeNotFound.java diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java index 42c9e2ded..941d5745c 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java @@ -43,7 +43,6 @@ import java.sql.Timestamp; import java.sql.Types; import java.time.*; import java.util.*; -import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; /** @@ -194,7 +193,7 @@ public final class DefaultTypeManager implements TypeManager { List> types = plugin.createTypes(config, objectMapper); for (ScalarType type : types) { log.debug("adding ScalarType {}", type.getClass()); - addCustomType(type); + add(type); } } } @@ -212,25 +211,6 @@ public final class DefaultTypeManager implements TypeManager { logAdd(scalarType); } - /** - * Register the ScalarType for an enum. This is special in the sense that an Enum - * can have many classes if it uses method overrides and we need to register all - * the variations/classes for the enum. - */ - @SuppressWarnings({"rawtypes", "unchecked"}) - @Override - public void addEnumType(ScalarType scalarType, Class enumClass) { - Set> mappedClasses = new HashSet<>(); - mappedClasses.add(enumClass); - for (Object value : EnumSet.allOf(enumClass).toArray()) { - mappedClasses.add(value.getClass()); - } - for (Class cls : mappedClasses) { - typeMap.put(cls, scalarType); - } - logAdd(scalarType); - } - private void logAdd(ScalarType scalarType) { if (log.isTraceEnabled()) { String msg = "ScalarType register [" + scalarType.getClass().getName() + "]"; @@ -270,25 +250,50 @@ public final class DefaultTypeManager implements TypeManager { @Override public ScalarType getScalarType(Class type) { ScalarType found = typeMap.get(type); - if (found == null) { + if (found == null || found == ScalarTypeNotFound.INSTANCE) { + found = null; if (type.getName().equals("org.joda.time.LocalTime")) { throw new IllegalStateException( "ScalarType of Joda LocalTime not defined. You need to set DatabaseConfig.jodaLocalTimeMode to" + " either 'normal' or 'utc'. UTC is the old mode using UTC timezone but local time zone is now preferred as 'normal' mode."); } - found = checkInterfaceTypes(type); + found = checkInheritedTypes(type); } return found; } - private ScalarType checkInterfaceTypes(Class type) { - for (Entry, ScalarType> entry : typeMap.entrySet()) { - if (entry.getKey().isAssignableFrom(type)) { - typeMap.put(type, entry.getValue()); - return entry.getValue(); + /** + * Checks the typeMap for inherited types. + * + * If type is a GregorianCalendar, then this method + * will check the class hierarchy and will probably return a + * ScalarTypeCalendar To speed up a second lookup, it will write + * back the found scalarType to typeMap. + * + * @param type + * @return + */ + private ScalarType checkInheritedTypes(Class type) { + // first step loop through inheritance chain + Class parent = type; + while (parent != null && parent != Object.class) { + ScalarType found = typeMap.get(parent); + if (found != null && found != ScalarTypeNotFound.INSTANCE) { + typeMap.put(type, found); // store type for next lookup + return found; + } + parent = parent.getSuperclass(); + } + // second step - loop through interface chain + for (Class iface: type.getInterfaces()) { + ScalarType found = checkInheritedTypes(iface); + if (found != null && found != ScalarTypeNotFound.INSTANCE) { + typeMap.put(type, found); // store type for next lookup + return found; } } - return null; + typeMap.put(type, ScalarTypeNotFound.INSTANCE); + return null; // no success } @Override @@ -394,8 +399,8 @@ public final class DefaultTypeManager implements TypeManager { private DocPropertyType getDocType(Type genericType) { if (genericType instanceof Class) { - ScalarType found = typeMap.get(genericType); - if (found != null) { + ScalarType found = getScalarType((Class)genericType); + if (found != null && found != ScalarTypeNotFound.INSTANCE) { return found.getDocType(); } } @@ -452,7 +457,7 @@ public final class DefaultTypeManager implements TypeManager { return scalarType; } - scalarType = typeMap.get(type); + scalarType = getScalarType(type); if (scalarType != null) { if (jdbcType == 0 || scalarType.getJdbcType() == jdbcType) { // matching type @@ -570,7 +575,7 @@ public final class DefaultTypeManager implements TypeManager { // use JPA normal Enum type (without mapping) scalarEnum = createEnumScalarTypePerSpec(enumType, type); } - addEnumType(scalarEnum, enumType); + add(scalarEnum); return scalarEnum; } @@ -660,16 +665,13 @@ public final class DefaultTypeManager implements TypeManager { scalarType = cls.getDeclaredConstructor().newInstance(); } } - addCustomType(scalarType); + add(scalarType); } catch (Exception e) { log.error("Error loading ScalarType [" + cls.getName() + "]", e); } } } - private void addCustomType(ScalarType scalarType) { - add(scalarType); - } private Object initObjectMapper(DatabaseConfig config) { Object objectMapper = config.getObjectMapper(); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeNotFound.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeNotFound.java new file mode 100644 index 000000000..7fbb5b5e9 --- /dev/null +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeNotFound.java @@ -0,0 +1,140 @@ +package io.ebeaninternal.server.type; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.sql.SQLException; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonParser; + +import io.ebean.core.type.DataBinder; +import io.ebean.core.type.DataReader; +import io.ebean.core.type.DocPropertyType; +import io.ebean.core.type.ScalarType; + +/** + * Class is required as "null" key in ConcurrentHashMap. + * @author Roland Praml, FOCONIS AG + * + */ +class ScalarTypeNotFound implements ScalarType { + + public static final ScalarTypeNotFound INSTANCE = new ScalarTypeNotFound(); + private ScalarTypeNotFound() { } + @Override + public boolean isBinaryType() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isMutable() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isDirty(Object value) { + throw new UnsupportedOperationException(); + } + + @Override + public int getLength() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isJdbcNative() { + throw new UnsupportedOperationException(); + } + + @Override + public int getJdbcType() { + throw new UnsupportedOperationException(); + } + + @Override + public Class getType() { + throw new UnsupportedOperationException(); + } + + @Override + public Void read(DataReader reader) throws SQLException { + throw new UnsupportedOperationException(); + } + + @Override + public void loadIgnore(DataReader reader) { + throw new UnsupportedOperationException(); + } + + @Override + public void bind(DataBinder binder, Void value) throws SQLException { + throw new UnsupportedOperationException(); + } + + @Override + public Object toJdbcType(Object value) { + throw new UnsupportedOperationException(); + } + + @Override + public Void toBeanType(Object value) { + throw new UnsupportedOperationException(); + } + + @Override + public String formatValue(Void value) { + throw new UnsupportedOperationException(); + } + + @Override + public String format(Object value) { + throw new UnsupportedOperationException(); + } + + @Override + public Void parse(String value) { + throw new UnsupportedOperationException(); + } + + @Override + public DocPropertyType getDocType() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isDateTimeCapable() { + throw new UnsupportedOperationException(); + } + + @Override + public long asVersion(Void value) { + throw new UnsupportedOperationException(); + } + + @Override + public Void convertFromMillis(long dateTime) { + throw new UnsupportedOperationException(); + } + + @Override + public Void readData(DataInput dataInput) throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public void writeData(DataOutput dataOutput, Void v) throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public Void jsonRead(JsonParser parser) throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public void jsonWrite(JsonGenerator writer, Void value) throws IOException { + throw new UnsupportedOperationException(); + } + +} diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/TypeManager.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/TypeManager.java index 692e65681..079782972 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/TypeManager.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/TypeManager.java @@ -17,12 +17,6 @@ public interface TypeManager { */ void add(ScalarType scalarType); - /** - * Register a ScalarType for an Enum with can have multiple classes. - */ - @SuppressWarnings("rawtypes") - void addEnumType(ScalarType type, Class myEnumClass); - /** * Return the scalar type for the given logical type. */ From eb21b41fba722854d4a73b4b92082a7241ecd7b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20P=C3=B6hler?= Date: Wed, 5 Jan 2022 14:13:09 +0100 Subject: [PATCH 04/10] Refactor and fixes for interfaces (like Path) + extend existing tests --- .../server/type/DefaultTypeManager.java | 35 +++++++++---------- .../tests/model/types/SomeNewTypesBean.java | 11 ++++++ .../java/org/tests/types/TestNewTypes.java | 9 ++++- 3 files changed, 36 insertions(+), 19 deletions(-) diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java index 401ad2216..81d6a1ea2 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java @@ -250,8 +250,7 @@ public final class DefaultTypeManager implements TypeManager { @Override public ScalarType getScalarType(Class type) { ScalarType found = typeMap.get(type); - if (found == null || found == ScalarTypeNotFound.INSTANCE) { - found = null; + if (found == null) { if (type.getName().equals("org.joda.time.LocalTime")) { throw new IllegalStateException( "ScalarType of Joda LocalTime not defined. You need to set DatabaseConfig.jodaLocalTimeMode to" @@ -259,19 +258,19 @@ public final class DefaultTypeManager implements TypeManager { } found = checkInheritedTypes(type); } - return found; + return found != ScalarTypeNotFound.INSTANCE ? found : null; // Do not return ScalarTypeNotFound, otherwise checks will fail } /** * Checks the typeMap for inherited types. - * - * If type is a GregorianCalendar, then this method + * + * If e.g. type is a GregorianCalendar, then this method * will check the class hierarchy and will probably return a * ScalarTypeCalendar To speed up a second lookup, it will write * back the found scalarType to typeMap. - * - * @param type - * @return + * + * @param type the for which to search for a ScalarType + * @return either a valid ScalarType if one could be found or {@link ScalarTypeNotFound#INSTANCE} if not */ private ScalarType checkInheritedTypes(Class type) { // first step loop through inheritance chain @@ -282,18 +281,18 @@ public final class DefaultTypeManager implements TypeManager { typeMap.put(type, found); // store type for next lookup return found; } + // second step - loop through interfaces of this type + for (Class iface: parent.getInterfaces()) { + found = checkInheritedTypes(iface); + if (found != null && found != ScalarTypeNotFound.INSTANCE) { + typeMap.put(type, found); // store type for next lookup + return found; + } + } parent = parent.getSuperclass(); } - // second step - loop through interface chain - for (Class iface: type.getInterfaces()) { - ScalarType found = checkInheritedTypes(iface); - if (found != null && found != ScalarTypeNotFound.INSTANCE) { - typeMap.put(type, found); // store type for next lookup - return found; - } - } typeMap.put(type, ScalarTypeNotFound.INSTANCE); - return null; // no success + return ScalarTypeNotFound.INSTANCE; // no success } @Override @@ -399,7 +398,7 @@ public final class DefaultTypeManager implements TypeManager { private DocPropertyType getDocType(Type genericType) { if (genericType instanceof Class) { ScalarType found = getScalarType((Class)genericType); - if (found != null && found != ScalarTypeNotFound.INSTANCE) { + if (found != null) { return found.getDocType(); } } diff --git a/ebean-test/src/test/java/org/tests/model/types/SomeNewTypesBean.java b/ebean-test/src/test/java/org/tests/model/types/SomeNewTypesBean.java index 2596dbcba..1a0fee0bf 100644 --- a/ebean-test/src/test/java/org/tests/model/types/SomeNewTypesBean.java +++ b/ebean-test/src/test/java/org/tests/model/types/SomeNewTypesBean.java @@ -7,6 +7,7 @@ import javax.persistence.Version; import java.nio.file.Path; import java.sql.Date; import java.time.*; +import java.util.Calendar; @Entity public class SomeNewTypesBean { @@ -58,6 +59,8 @@ public class SomeNewTypesBean { Duration duration; + Calendar calendar; + public Long getId() { return id; } @@ -217,4 +220,12 @@ public class SomeNewTypesBean { public void setDuration(Duration duration) { this.duration = duration; } + + public Calendar getCalendar() { + return calendar; + } + + public void setCalendar(final Calendar calendar) { + this.calendar = calendar; + } } diff --git a/ebean-test/src/test/java/org/tests/types/TestNewTypes.java b/ebean-test/src/test/java/org/tests/types/TestNewTypes.java index 35732801e..a40c673ea 100644 --- a/ebean-test/src/test/java/org/tests/types/TestNewTypes.java +++ b/ebean-test/src/test/java/org/tests/types/TestNewTypes.java @@ -10,6 +10,8 @@ import org.tests.model.types.SomeNewTypesBean; import java.io.File; import java.nio.file.Paths; import java.time.*; +import java.util.Calendar; +import java.util.GregorianCalendar; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; @@ -44,6 +46,7 @@ public class TestNewTypes extends BaseTestCase { bean.setPath(Paths.get(TEMP_PATH)); bean.setPeriod(Period.of(4,3,2)); bean.setDuration(Duration.ofMinutes(5)); + bean.setCalendar(Calendar.getInstance()); DB.save(bean); @@ -104,6 +107,9 @@ public class TestNewTypes extends BaseTestCase { list = DB.find(SomeNewTypesBean.class).where().eq("duration", Duration.ofMinutes(5)).findList(); assertThat(list).isNotEmpty(); + list = DB.find(SomeNewTypesBean.class).where().le("calendar", GregorianCalendar.getInstance()).findList(); + assertThat(list).isNotEmpty(); + SomeNewTypesBean fetched = DB.find(SomeNewTypesBean.class, bean.getId()); assertEquals(bean.getZoneId(), fetched.getZoneId()); @@ -122,6 +128,7 @@ public class TestNewTypes extends BaseTestCase { assertEquals(bean.getPath(), fetched.getPath()); assertEquals(bean.getPeriod(), fetched.getPeriod()); assertEquals(bean.getDuration(), fetched.getDuration()); + assertEquals(bean.getCalendar(), fetched.getCalendar()); String asJson = DB.json().toJson(fetched); @@ -139,10 +146,10 @@ public class TestNewTypes extends BaseTestCase { assertThat(toBean.getOffsetDateTime()).isEqualToIgnoringNanos(bean.getOffsetDateTime()); assertEquals(bean.getLocalTime().toSecondOfDay(), toBean.getLocalTime().toSecondOfDay()); assertEquals(bean.getInstant().toEpochMilli() / 1000, toBean.getInstant().toEpochMilli() / 1000); - // FIXME: This test fails on Windows with: expected:<\tmp> but was: assertEquals(bean.getPath(), toBean.getPath()); assertEquals(bean.getPeriod(), toBean.getPeriod()); assertEquals(bean.getDuration(), toBean.getDuration()); + assertEquals(bean.getCalendar(), toBean.getCalendar()); } From e7f9c6350261c0b2e24c44fd06d115aa8f5d5beb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20P=C3=B6hler?= Date: Wed, 5 Jan 2022 15:46:34 +0100 Subject: [PATCH 05/10] Clear up some possible confusion in the test --- ebean-test/src/test/java/org/tests/types/TestNewTypes.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ebean-test/src/test/java/org/tests/types/TestNewTypes.java b/ebean-test/src/test/java/org/tests/types/TestNewTypes.java index a40c673ea..90ffd842a 100644 --- a/ebean-test/src/test/java/org/tests/types/TestNewTypes.java +++ b/ebean-test/src/test/java/org/tests/types/TestNewTypes.java @@ -11,7 +11,6 @@ import java.io.File; import java.nio.file.Paths; import java.time.*; import java.util.Calendar; -import java.util.GregorianCalendar; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; @@ -107,7 +106,8 @@ public class TestNewTypes extends BaseTestCase { list = DB.find(SomeNewTypesBean.class).where().eq("duration", Duration.ofMinutes(5)).findList(); assertThat(list).isNotEmpty(); - list = DB.find(SomeNewTypesBean.class).where().le("calendar", GregorianCalendar.getInstance()).findList(); + // Calendar.getInstance() returns an implementation, which then has to be remapped to ScalarTypeCalendar + list = DB.find(SomeNewTypesBean.class).where().le("calendar", Calendar.getInstance()).findList(); assertThat(list).isNotEmpty(); SomeNewTypesBean fetched = DB.find(SomeNewTypesBean.class, bean.getId()); From 8d85000970df57434d1b1a9b5bb6dbe89dba15dc Mon Sep 17 00:00:00 2001 From: "FOCONIS\\szemenyei" Date: Mon, 10 Jan 2022 15:55:58 +0100 Subject: [PATCH 06/10] Fix Checksum calculate() with special characters (cherry picked from commit e9efd5a70222f372a38d5bcac4254de3759010b9) --- .../src/main/java/io/ebeaninternal/dbmigration/MChecksum.java | 4 ++-- .../test/java/io/ebeaninternal/dbmigration/MChecksumTest.java | 4 ++-- .../resources/dbmigration/index-special-chars/1.0__hello.sql | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) create mode 100644 ebean-ddl-generator/src/test/resources/dbmigration/index-special-chars/1.0__hello.sql diff --git a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/MChecksum.java b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/MChecksum.java index 9c533992e..bd63afe0b 100644 --- a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/MChecksum.java +++ b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/MChecksum.java @@ -1,6 +1,7 @@ package io.ebeaninternal.dbmigration; import java.io.*; +import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.zip.CRC32; @@ -13,9 +14,8 @@ class MChecksum { * Returns the checksum of the file. Agnostic of encoding and new line character. */ static int calculate(File file) { - try { + try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(file), Charset.forName("UTF-8")))) { final CRC32 crc32 = new CRC32(); - BufferedReader bufferedReader = new BufferedReader(new FileReader(file)); String line; while ((line = bufferedReader.readLine()) != null) { final byte[] lineBytes = line.getBytes(StandardCharsets.UTF_8); diff --git a/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/MChecksumTest.java b/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/MChecksumTest.java index 0f41e7ba0..65756f58f 100644 --- a/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/MChecksumTest.java +++ b/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/MChecksumTest.java @@ -10,9 +10,9 @@ public class MChecksumTest { @Test public void calculate() { - File file = new File("src/test/resources/dbmigration/index/1.0__hello.sql"); + File file = new File("src/test/resources/dbmigration/index-special-chars/1.0__hello.sql"); assertThat(file).exists(); - assertThat(MChecksum.calculate(file)).isEqualTo(907060870); + assertThat(MChecksum.calculate(file)).isEqualTo(1859426839); } } diff --git a/ebean-ddl-generator/src/test/resources/dbmigration/index-special-chars/1.0__hello.sql b/ebean-ddl-generator/src/test/resources/dbmigration/index-special-chars/1.0__hello.sql new file mode 100644 index 000000000..6814e2a28 --- /dev/null +++ b/ebean-ddl-generator/src/test/resources/dbmigration/index-special-chars/1.0__hello.sql @@ -0,0 +1 @@ +helloäüü From b01b44af10419010b4b175b03381319ddfca43e1 Mon Sep 17 00:00:00 2001 From: "FOCONIS\\szemenyei" Date: Tue, 11 Jan 2022 09:48:47 +0100 Subject: [PATCH 07/10] at first revert solution --- .../src/main/java/io/ebeaninternal/dbmigration/MChecksum.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/MChecksum.java b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/MChecksum.java index bd63afe0b..9c533992e 100644 --- a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/MChecksum.java +++ b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/MChecksum.java @@ -1,7 +1,6 @@ package io.ebeaninternal.dbmigration; import java.io.*; -import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.zip.CRC32; @@ -14,8 +13,9 @@ class MChecksum { * Returns the checksum of the file. Agnostic of encoding and new line character. */ static int calculate(File file) { - try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(file), Charset.forName("UTF-8")))) { + try { final CRC32 crc32 = new CRC32(); + BufferedReader bufferedReader = new BufferedReader(new FileReader(file)); String line; while ((line = bufferedReader.readLine()) != null) { final byte[] lineBytes = line.getBytes(StandardCharsets.UTF_8); From 0cf9f0bf5875c2002529d7ae909c23ee2248706b Mon Sep 17 00:00:00 2001 From: "FOCONIS\\szemenyei" Date: Tue, 11 Jan 2022 09:49:02 +0100 Subject: [PATCH 08/10] Revert "at first revert solution" This reverts commit b01b44af10419010b4b175b03381319ddfca43e1. --- .../src/main/java/io/ebeaninternal/dbmigration/MChecksum.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/MChecksum.java b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/MChecksum.java index 9c533992e..bd63afe0b 100644 --- a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/MChecksum.java +++ b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/MChecksum.java @@ -1,6 +1,7 @@ package io.ebeaninternal.dbmigration; import java.io.*; +import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.zip.CRC32; @@ -13,9 +14,8 @@ class MChecksum { * Returns the checksum of the file. Agnostic of encoding and new line character. */ static int calculate(File file) { - try { + try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(file), Charset.forName("UTF-8")))) { final CRC32 crc32 = new CRC32(); - BufferedReader bufferedReader = new BufferedReader(new FileReader(file)); String line; while ((line = bufferedReader.readLine()) != null) { final byte[] lineBytes = line.getBytes(StandardCharsets.UTF_8); From 01847e44de796cfceae29d8b3a7aaa9617a54751 Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Tue, 11 Jan 2022 09:01:45 +0100 Subject: [PATCH 09/10] Always use UTF-8 --- .../java/io/ebean/text/csv/CsvReader.java | 2 +- .../src/main/java/io/ebean/util/IOUtils.java | 48 +++++++++++++++++ .../server/core/DScriptRunner.java | 7 +-- .../transaction/DefaultProfileHandler.java | 4 +- .../server/type/ScalarTypeJsonMap.java | 5 +- .../server/type/ScalarTypeJsonNode.java | 4 +- .../server/type/SimpleAesEncryptor.java | 2 +- .../dbmigration/DdlGenerator.java | 13 ++--- .../dbmigration/DefaultDbMigration.java | 29 +++++----- .../dbmigration/IndexMigration.java | 17 +++--- .../ebeaninternal/dbmigration/MChecksum.java | 5 +- .../migrationreader/MigrationXmlWriter.java | 5 +- .../dbmigration/model/PlatformDdlWriter.java | 8 +-- .../dbmigration/ddlgeneration/Helper.java | 6 +-- .../test/java/io/ebean/json/EJsonTests.java | 23 ++++---- .../cache/CachedBeanDataSerializeTest.java | 3 +- .../server/type/TestSimpleEncryptor.java | 3 +- .../basic/TestDeleteImportedPartial.java | 4 +- .../org/tests/basic/TestDeleteOneToOne.java | 4 +- .../basic/TestDeleteOneToOneMultiple.java | 6 ++- .../tests/basic/TestSaveDeleteOneToOne.java | 6 ++- .../basic/TestSaveDeleteOneToOneMultiple.java | 6 ++- .../TestConstructorPutfieldReplacement.java | 4 +- .../org/tests/text/csv/TestCsvReader.java | 18 +++---- .../text/csv/TestCsvReaderWithCallback.java | 54 +++++++++---------- .../org/tests/text/json/TestJsonSimple.java | 20 ++++--- 26 files changed, 189 insertions(+), 117 deletions(-) create mode 100644 ebean-api/src/main/java/io/ebean/util/IOUtils.java diff --git a/ebean-api/src/main/java/io/ebean/text/csv/CsvReader.java b/ebean-api/src/main/java/io/ebean/text/csv/CsvReader.java index de64444ab..b20232fc0 100644 --- a/ebean-api/src/main/java/io/ebean/text/csv/CsvReader.java +++ b/ebean-api/src/main/java/io/ebean/text/csv/CsvReader.java @@ -18,7 +18,7 @@ import java.util.Locale; * try { * File f = new File("src/test/resources/test1.csv"); * - * FileReader reader = new FileReader(f); + * FileReader reader = new FileReader(f, encoding); * * CsvReader csvReader = DB.createCsvReader(Customer.class); * diff --git a/ebean-api/src/main/java/io/ebean/util/IOUtils.java b/ebean-api/src/main/java/io/ebean/util/IOUtils.java new file mode 100644 index 000000000..e4f437e10 --- /dev/null +++ b/ebean-api/src/main/java/io/ebean/util/IOUtils.java @@ -0,0 +1,48 @@ +package io.ebean.util; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.nio.charset.StandardCharsets; + +/** + * Utilities for IO. It uses UTF-8 as encoding when reading/writing and uses + * buffered IO for better performance. + */ +public class IOUtils { + + /** + * Read from stream as UTF-8. + */ + public static BufferedReader newReader(InputStream is) { + return new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8)); + } + + /** + * Read from file as UTF-8. + */ + public static BufferedReader newReader(File file) throws FileNotFoundException { + return newReader(new FileInputStream(file)); + } + + /** + * Write to stream as UTF-8 + */ + public static BufferedWriter newWriter(OutputStream os) { + return new BufferedWriter(new OutputStreamWriter(os, StandardCharsets.UTF_8)); + } + + /** + * Write to file as UTF-8 + */ + public static BufferedWriter newWriter(File file) throws FileNotFoundException { + return newWriter(new FileOutputStream(file)); + } +} diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/core/DScriptRunner.java b/ebean-core/src/main/java/io/ebeaninternal/server/core/DScriptRunner.java index 2b4c81f0b..394f1faea 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/core/DScriptRunner.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/core/DScriptRunner.java @@ -3,13 +3,13 @@ package io.ebeaninternal.server.core; import io.ebean.ScriptRunner; import io.ebean.ddlrunner.DdlRunner; import io.ebean.ddlrunner.ScriptTransform; +import io.ebean.util.IOUtils; import io.ebeaninternal.api.SpiEbeanServer; import io.ebeaninternal.util.UrlHelper; import javax.persistence.PersistenceException; import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; import java.io.LineNumberReader; import java.io.Reader; import java.net.URL; @@ -66,8 +66,9 @@ final class DScriptRunner implements ScriptRunner { throw new IllegalArgumentException("resource is null?"); } - try (InputStream inputStream = UrlHelper.openNoCache(resource)) { - return readContent(new InputStreamReader(inputStream)); + try (InputStream inputStream = UrlHelper.openNoCache(resource); + Reader reader = IOUtils.newReader(inputStream)) { + return readContent(reader); } catch (IOException e) { throw new PersistenceException("Failed to read script content", e); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/DefaultProfileHandler.java b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/DefaultProfileHandler.java index 87c7401e2..8ac394a8c 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/DefaultProfileHandler.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/DefaultProfileHandler.java @@ -4,11 +4,13 @@ import io.ebean.ProfileLocation; import io.ebean.config.ProfilingConfig; import io.ebean.plugin.Plugin; import io.ebean.plugin.SpiServer; +import io.ebean.util.IOUtils; import io.ebeaninternal.api.CoreLog; import io.ebeaninternal.api.SpiProfileHandler; import org.slf4j.Logger; import java.io.*; +import java.nio.charset.StandardCharsets; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; @@ -123,7 +125,7 @@ public final class DefaultProfileHandler implements SpiProfileHandler, Plugin { try { String now = DTF.format(LocalDateTime.now()); File file = new File(dir, "txprofile-" + now + ".tprofile"); - out = new BufferedWriter(new FileWriter(file)); + out = IOUtils.newWriter(file); } catch (IOException e) { log.error("Not expected", e); } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonMap.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonMap.java index 93ecdab79..b5942289e 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonMap.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonMap.java @@ -8,6 +8,7 @@ import io.ebean.core.type.DataReader; import io.ebean.core.type.DocPropertyType; import io.ebean.text.TextException; import io.ebean.text.json.EJson; +import io.ebean.util.IOUtils; import java.io.*; import java.nio.charset.StandardCharsets; @@ -75,14 +76,14 @@ abstract class ScalarTypeJsonMap extends ScalarTypeBase { try { if (keepSource) { StringWriter jsonBuffer = new StringWriter(); - try (InputStreamReader streamReader = new InputStreamReader(is, StandardCharsets.UTF_8)) { + try (Reader streamReader = IOUtils.newReader(is)) { transferTo(streamReader, jsonBuffer); } String rawJson = jsonBuffer.toString(); reader.pushJson(rawJson); return parse(rawJson); } else { - try (InputStreamReader streamReader = new InputStreamReader(is, StandardCharsets.UTF_8)) { + try (Reader streamReader = IOUtils.newReader(is)) { return parse(streamReader); } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonNode.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonNode.java index 675328de5..8d2501f04 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonNode.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonNode.java @@ -8,12 +8,12 @@ import io.ebean.core.type.DataBinder; import io.ebean.core.type.DataReader; import io.ebean.core.type.DocPropertyType; import io.ebean.text.TextException; +import io.ebean.util.IOUtils; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; import java.io.Reader; import java.nio.charset.StandardCharsets; import java.sql.SQLException; @@ -68,7 +68,7 @@ abstract class ScalarTypeJsonNode extends ScalarTypeBase { if (is == null) { return null; } - try (InputStreamReader reader = new InputStreamReader(is)) { + try (Reader reader = IOUtils.newReader(is)) { return parse(reader); } catch (IOException e) { throw new SQLException("Error reading Blob stream from DB", e); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/SimpleAesEncryptor.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/SimpleAesEncryptor.java index 0dfd3f999..0b16967c7 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/SimpleAesEncryptor.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/SimpleAesEncryptor.java @@ -32,7 +32,7 @@ public final class SimpleAesEncryptor implements Encryptor { } private IvParameterSpec getIvParameterSpec(String initialVector) { - return new IvParameterSpec(initialVector.getBytes()); + return new IvParameterSpec(initialVector.getBytes(StandardCharsets.UTF_8)); } @Override diff --git a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/DdlGenerator.java b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/DdlGenerator.java index 69a4af033..37c413420 100644 --- a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/DdlGenerator.java +++ b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/DdlGenerator.java @@ -5,6 +5,7 @@ import io.ebean.config.DatabaseConfig; import io.ebean.config.dbplatform.DatabasePlatform; import io.ebean.ddlrunner.DdlRunner; import io.ebean.ddlrunner.ScriptTransform; +import io.ebean.util.IOUtils; import io.ebean.util.JdbcClose; import io.ebeaninternal.api.SpiDdlGenerator; import io.ebeaninternal.api.SpiEbeanServer; @@ -17,13 +18,11 @@ import org.slf4j.LoggerFactory; import javax.persistence.PersistenceException; import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; import java.io.LineNumberReader; import java.io.Reader; +import java.io.Writer; import java.sql.Connection; import java.sql.SQLException; @@ -268,7 +267,7 @@ public class DdlGenerator implements SpiDdlGenerator { if (is == null) { log.warn("sql script {} was not found as a resource", sqlScript); } else { - String content = readContent(new InputStreamReader(is)); + String content = readContent(IOUtils.newReader(is)); // 'is' is closed runScript(connection, false, content, sqlScript); } } @@ -337,7 +336,7 @@ public class DdlGenerator implements SpiDdlGenerator { protected void writeFile(String fileName, String fileContent) throws IOException { File f = new File(baseDir, fileName); - try (FileWriter fw = new FileWriter(f)) { + try (Writer fw = IOUtils.newWriter(f)) { fw.write(fileContent); fw.flush(); } @@ -348,7 +347,9 @@ public class DdlGenerator implements SpiDdlGenerator { if (!f.exists()) { return null; } - return readContent(new FileReader(f)); + try (Reader reader = IOUtils.newReader(f)) { + return readContent(reader); + } } protected String readContent(Reader reader) throws IOException { diff --git a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java index a7a3703d7..dbe1a00f3 100644 --- a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java +++ b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java @@ -1,8 +1,22 @@ package io.ebeaninternal.dbmigration; +import static io.ebeaninternal.api.PlatformMatch.matchPlatform; + +import java.io.File; +import java.io.IOException; +import java.io.Writer; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; +import java.util.StringJoiner; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import io.ebean.DB; import io.ebean.Database; import io.ebean.annotation.Platform; +import io.ebean.config.ClassLoadConfig; import io.ebean.config.DatabaseConfig; import io.ebean.config.DbConstraintNaming; import io.ebean.config.PlatformConfig; @@ -27,6 +41,8 @@ import io.ebean.config.dbplatform.sqlite.SQLitePlatform; import io.ebean.config.dbplatform.sqlserver.SqlServer16Platform; import io.ebean.config.dbplatform.sqlserver.SqlServer17Platform; import io.ebean.dbmigration.DbMigration; +import io.ebean.util.IOUtils; +import io.ebean.util.StringHelper; import io.ebeaninternal.api.DbOffline; import io.ebeaninternal.api.SpiEbeanServer; import io.ebeaninternal.dbmigration.ddlgeneration.DdlOptions; @@ -42,17 +58,6 @@ import io.ebeaninternal.dbmigration.model.PlatformDdlWriter; import io.ebeaninternal.extraddl.model.DdlScript; import io.ebeaninternal.extraddl.model.ExtraDdl; import io.ebeaninternal.extraddl.model.ExtraDdlXmlReader; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Properties; - -import static io.ebeaninternal.api.PlatformMatch.matchPlatform; /** * Generates DB Migration xml and sql scripts. @@ -417,7 +422,7 @@ public class DefaultDbMigration implements DbMigration { String fullName = repeatableMigrationName(script.isInit(), script.getName()); logger.debug("writing repeatable script {}", fullName); File file = new File(migrationDir, fullName); - try (FileWriter writer = new FileWriter(file)) { + try (Writer writer = IOUtils.newWriter(file)) { writer.write(script.getValue()); writer.flush(); } diff --git a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/IndexMigration.java b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/IndexMigration.java index baedb77b9..c0f6221d7 100644 --- a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/IndexMigration.java +++ b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/IndexMigration.java @@ -2,10 +2,11 @@ package io.ebeaninternal.dbmigration; import io.ebean.config.dbplatform.DatabasePlatform; import io.ebean.migration.MigrationVersion; +import io.ebean.util.IOUtils; import java.io.File; -import java.io.FileWriter; import java.io.IOException; +import java.io.Writer; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -50,17 +51,17 @@ class IndexMigration { private void generateIndex() throws IOException { Collections.sort(all); - FileWriter writer = new FileWriter(indexFile); - for (Entry entry : all) { - writeChecksumPadded(writer, entry.checksum); - writer.write(entry.fileName); + try (Writer writer = IOUtils.newWriter(indexFile)) { + for (Entry entry : all) { + writeChecksumPadded(writer, entry.checksum); + writer.write(entry.fileName); + writer.write(eol); + } writer.write(eol); } - writer.write(eol); - writer.close(); } - private void writeChecksumPadded(FileWriter writer, int checksum) throws IOException { + private void writeChecksumPadded(Writer writer, int checksum) throws IOException { final String asStr = String.valueOf(checksum); writer.write(asStr); writer.write(','); diff --git a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/MChecksum.java b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/MChecksum.java index bd63afe0b..9ce34a7ba 100644 --- a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/MChecksum.java +++ b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/MChecksum.java @@ -1,10 +1,11 @@ package io.ebeaninternal.dbmigration; import java.io.*; -import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.zip.CRC32; +import io.ebean.util.IOUtils; + /** * Calculates the checksum for the given file content. */ @@ -14,7 +15,7 @@ class MChecksum { * Returns the checksum of the file. Agnostic of encoding and new line character. */ static int calculate(File file) { - try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(file), Charset.forName("UTF-8")))) { + try (BufferedReader bufferedReader = IOUtils.newReader(file)) { final CRC32 crc32 = new CRC32(); String line; while ((line = bufferedReader.readLine()) != null) { diff --git a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/migrationreader/MigrationXmlWriter.java b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/migrationreader/MigrationXmlWriter.java index 43d389b56..c887fc2b0 100644 --- a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/migrationreader/MigrationXmlWriter.java +++ b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/migrationreader/MigrationXmlWriter.java @@ -1,14 +1,15 @@ package io.ebeaninternal.dbmigration.migrationreader; +import io.ebean.util.IOUtils; import io.ebeaninternal.dbmigration.migration.Migration; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import java.io.File; -import java.io.FileWriter; import java.io.IOException; +import java.io.Writer; /** * Simple writer for output of the Migration/ChangeSet as an XML document. @@ -26,7 +27,7 @@ public class MigrationXmlWriter { */ public void write(Migration migration, File file) { - try (FileWriter writer = new FileWriter(file)) { + try (Writer writer = IOUtils.newWriter(file)) { writer.write("\n"); if (comment != null) { diff --git a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/model/PlatformDdlWriter.java b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/model/PlatformDdlWriter.java index 59da934e4..ec55dd9a9 100644 --- a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/model/PlatformDdlWriter.java +++ b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/model/PlatformDdlWriter.java @@ -2,6 +2,7 @@ package io.ebeaninternal.dbmigration.model; import io.ebean.config.DatabaseConfig; import io.ebean.config.dbplatform.DatabasePlatform; +import io.ebean.util.IOUtils; import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer; import io.ebeaninternal.dbmigration.ddlgeneration.DdlHandler; import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite; @@ -14,7 +15,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; -import java.io.FileWriter; import java.io.IOException; import java.io.Writer; import java.util.List; @@ -70,16 +70,16 @@ public class PlatformDdlWriter { */ protected void writePlatformDdl(DdlWrite write, File resourcePath, String fullVersion) throws IOException { if (!write.isApplyEmpty()) { - try (FileWriter applyWriter = createWriter(resourcePath, fullVersion, ".sql")) { + try (Writer applyWriter = createWriter(resourcePath, fullVersion, ".sql")) { writeApplyDdl(applyWriter, write); applyWriter.flush(); } } } - protected FileWriter createWriter(File path, String fullVersion, String suffix) throws IOException { + protected Writer createWriter(File path, String fullVersion, String suffix) throws IOException { File applyFile = new File(path, fullVersion + suffix); - return new FileWriter(applyFile); + return IOUtils.newWriter(applyFile); } /** diff --git a/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/Helper.java b/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/Helper.java index b85bd6fb7..9ce850323 100644 --- a/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/Helper.java +++ b/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/Helper.java @@ -1,5 +1,6 @@ package io.ebeaninternal.dbmigration.ddlgeneration; +import io.ebean.util.IOUtils; import io.ebeaninternal.dbmigration.migration.AddColumn; import io.ebeaninternal.dbmigration.migration.ChangeSet; import io.ebeaninternal.dbmigration.migration.CreateTable; @@ -9,8 +10,8 @@ import io.ebeaninternal.dbmigration.migrationreader.MigrationXmlReader; import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; import java.io.LineNumberReader; +import java.io.Reader; import java.util.List; /** @@ -89,8 +90,7 @@ public class Helper { public static String asText(InputStream in) throws IOException { - try { - InputStreamReader reader = new InputStreamReader(in); + try (Reader reader = IOUtils.newReader(in)) { LineNumberReader lineNumberReader = new LineNumberReader(reader); diff --git a/ebean-test/src/test/java/io/ebean/json/EJsonTests.java b/ebean-test/src/test/java/io/ebean/json/EJsonTests.java index 929c6582c..6be980a40 100644 --- a/ebean-test/src/test/java/io/ebean/json/EJsonTests.java +++ b/ebean-test/src/test/java/io/ebean/json/EJsonTests.java @@ -4,24 +4,22 @@ import com.fasterxml.jackson.core.JsonFactory; import com.fasterxml.jackson.core.JsonParser; import io.ebean.ModifyAwareType; import io.ebean.text.json.EJson; +import io.ebean.util.IOUtils; import io.ebeaninternal.json.ModifyAwareMap; import org.junit.jupiter.api.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.io.File; -import java.io.FileWriter; import java.io.IOException; import java.io.StringReader; +import java.io.Writer; import java.nio.file.Files; import java.util.*; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.*; public class EJsonTests { - private static final Logger log = LoggerFactory.getLogger(EJsonTests.class); - @Test public void test_map_simple() throws IOException { @@ -46,15 +44,14 @@ public class EJsonTests { public void write_withWriter_expect_writerNotClosed() throws IOException { File temp = Files.createTempFile("some", ".json").toFile(); - FileWriter writer = new FileWriter(temp); - Map map = new LinkedHashMap<>(); - map.put("foo", "bar"); - EJson.write(map, writer); - writer.write("The end."); - writer.flush(); - writer.close(); + try (Writer writer = IOUtils.newWriter(temp)) { - log.info("write to file {}", temp.getAbsolutePath()); + Map map = new LinkedHashMap<>(); + map.put("foo", "bar"); + EJson.write(map, writer); + writer.write("The end."); + } + assertThat(temp).hasContent("{\"foo\":\"bar\"}The end."); } @Test diff --git a/ebean-test/src/test/java/io/ebeaninternal/server/cache/CachedBeanDataSerializeTest.java b/ebean-test/src/test/java/io/ebeaninternal/server/cache/CachedBeanDataSerializeTest.java index 53bf0c21d..08988cfce 100644 --- a/ebean-test/src/test/java/io/ebeaninternal/server/cache/CachedBeanDataSerializeTest.java +++ b/ebean-test/src/test/java/io/ebeaninternal/server/cache/CachedBeanDataSerializeTest.java @@ -11,6 +11,7 @@ import org.tests.model.basic.ResetBasicData; import org.tests.model.basic.TBytesOnly; import java.io.*; +import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.LinkedHashMap; import java.util.List; @@ -94,7 +95,7 @@ public class CachedBeanDataSerializeTest extends BaseTestCase { TBytesOnly bean = new TBytesOnly(); bean.setId(42); - bean.setContent(stringContent.getBytes("UTF-8")); + bean.setContent(stringContent.getBytes(StandardCharsets.UTF_8)); BeanDescriptor desc = getBeanDescriptor(TBytesOnly.class); CachedBeanData extract = CachedBeanDataFromBean.extract(desc, (EntityBean) bean); diff --git a/ebean-test/src/test/java/io/ebeaninternal/server/type/TestSimpleEncryptor.java b/ebean-test/src/test/java/io/ebeaninternal/server/type/TestSimpleEncryptor.java index 7ea6d2b3c..74c4fcd7a 100644 --- a/ebean-test/src/test/java/io/ebeaninternal/server/type/TestSimpleEncryptor.java +++ b/ebean-test/src/test/java/io/ebeaninternal/server/type/TestSimpleEncryptor.java @@ -5,6 +5,7 @@ import io.ebean.config.EncryptKey; import org.junit.jupiter.api.Test; import org.tests.basic.encrypt.BasicEncryptKey; +import java.nio.charset.StandardCharsets; import java.sql.Timestamp; import static org.assertj.core.api.Assertions.assertThat; @@ -19,7 +20,7 @@ public class TestSimpleEncryptor extends BaseTestCase { EncryptKey key = new BasicEncryptKey("hello"); - byte[] data = "test123".getBytes(); + byte[] data = "test123".getBytes(StandardCharsets.UTF_8); byte[] ecData = e.encrypt(data, key); diff --git a/ebean-test/src/test/java/org/tests/basic/TestDeleteImportedPartial.java b/ebean-test/src/test/java/org/tests/basic/TestDeleteImportedPartial.java index 16ba29c32..4729929c9 100644 --- a/ebean-test/src/test/java/org/tests/basic/TestDeleteImportedPartial.java +++ b/ebean-test/src/test/java/org/tests/basic/TestDeleteImportedPartial.java @@ -8,12 +8,14 @@ import org.tests.model.basic.PFileContent; import static org.junit.jupiter.api.Assertions.assertNull; +import java.nio.charset.StandardCharsets; + public class TestDeleteImportedPartial extends BaseTestCase { @Test public void test() { - PFile persistentFile = new PFile("test.txt", new PFileContent("test".getBytes())); + PFile persistentFile = new PFile("test.txt", new PFileContent("test".getBytes(StandardCharsets.UTF_8))); DB.save(persistentFile); Integer id = persistentFile.getId(); diff --git a/ebean-test/src/test/java/org/tests/basic/TestDeleteOneToOne.java b/ebean-test/src/test/java/org/tests/basic/TestDeleteOneToOne.java index dfe431246..98b837db2 100644 --- a/ebean-test/src/test/java/org/tests/basic/TestDeleteOneToOne.java +++ b/ebean-test/src/test/java/org/tests/basic/TestDeleteOneToOne.java @@ -8,13 +8,15 @@ import org.tests.model.basic.PersistentFileContent; import static org.junit.jupiter.api.Assertions.assertNull; +import java.nio.charset.StandardCharsets; + public class TestDeleteOneToOne extends BaseTestCase { @Test public void testCreateDeletePersistentFile() { PersistentFile persistentFile = new PersistentFile("test.txt", new PersistentFileContent( - "test".getBytes())); + "test".getBytes(StandardCharsets.UTF_8))); DB.save(persistentFile); Integer id = persistentFile.getId(); diff --git a/ebean-test/src/test/java/org/tests/basic/TestDeleteOneToOneMultiple.java b/ebean-test/src/test/java/org/tests/basic/TestDeleteOneToOneMultiple.java index 433fb270c..af51fdec5 100644 --- a/ebean-test/src/test/java/org/tests/basic/TestDeleteOneToOneMultiple.java +++ b/ebean-test/src/test/java/org/tests/basic/TestDeleteOneToOneMultiple.java @@ -8,16 +8,18 @@ import org.tests.model.basic.PFileContent; import static org.junit.jupiter.api.Assertions.assertNull; +import java.nio.charset.StandardCharsets; + public class TestDeleteOneToOneMultiple extends BaseTestCase { @Test public void testCreateDeletePersistentFile() { - PFile persistentFile = new PFile("test.txt", new PFileContent("test".getBytes())); + PFile persistentFile = new PFile("test.txt", new PFileContent("test".getBytes(StandardCharsets.UTF_8))); // PFile persistentFile = new PFile(); // persistentFile.setName("test.txt"); // PFileContent content = new PFileContent(); -// content.setContent("test".getBytes()); +// content.setContent("test".getBytes(StandardCharsets.UTF_8)); // persistentFile.setFileContent(content); DB.save(persistentFile); diff --git a/ebean-test/src/test/java/org/tests/basic/TestSaveDeleteOneToOne.java b/ebean-test/src/test/java/org/tests/basic/TestSaveDeleteOneToOne.java index 75208a534..f17c9862a 100644 --- a/ebean-test/src/test/java/org/tests/basic/TestSaveDeleteOneToOne.java +++ b/ebean-test/src/test/java/org/tests/basic/TestSaveDeleteOneToOne.java @@ -8,12 +8,14 @@ import org.tests.model.basic.PersistentFileContent; import static org.junit.jupiter.api.Assertions.assertNotNull; +import java.nio.charset.StandardCharsets; + public class TestSaveDeleteOneToOne extends BaseTestCase { @Test public void testCreateDeletePersistentFile() { PersistentFile persistentFile = new PersistentFile("test.txt", - new PersistentFileContent("test".getBytes())); + new PersistentFileContent("test".getBytes(StandardCharsets.UTF_8))); DB.save(persistentFile); DB.delete(persistentFile); @@ -22,7 +24,7 @@ public class TestSaveDeleteOneToOne extends BaseTestCase { @Test public void testCreateLoadDeletePersistentFile() { PersistentFile persistentFile = new PersistentFile("test.txt", - new PersistentFileContent("test".getBytes())); + new PersistentFileContent("test".getBytes(StandardCharsets.UTF_8))); DB.save(persistentFile); diff --git a/ebean-test/src/test/java/org/tests/basic/TestSaveDeleteOneToOneMultiple.java b/ebean-test/src/test/java/org/tests/basic/TestSaveDeleteOneToOneMultiple.java index e7e23283d..b357445e5 100644 --- a/ebean-test/src/test/java/org/tests/basic/TestSaveDeleteOneToOneMultiple.java +++ b/ebean-test/src/test/java/org/tests/basic/TestSaveDeleteOneToOneMultiple.java @@ -8,11 +8,13 @@ import org.tests.model.basic.PFileContent; import static org.junit.jupiter.api.Assertions.assertNotNull; +import java.nio.charset.StandardCharsets; + public class TestSaveDeleteOneToOneMultiple extends BaseTestCase { // public void testCreateDeletePFile() { // PFile persistentFile = new PFile("test.txt", -// new PFileContent("test".getBytes())); +// new PFileContent("test".getBytes(StandardCharsets.UTF_8))); // // DB.save(persistentFile); // DB.delete(persistentFile); @@ -21,7 +23,7 @@ public class TestSaveDeleteOneToOneMultiple extends BaseTestCase { @Test public void testCreateLoadDeletePFile() { PFile persistentFile = new PFile("test.txt", - new PFileContent("test".getBytes())); + new PFileContent("test".getBytes(StandardCharsets.UTF_8))); DB.save(persistentFile); diff --git a/ebean-test/src/test/java/org/tests/enhancement/TestConstructorPutfieldReplacement.java b/ebean-test/src/test/java/org/tests/enhancement/TestConstructorPutfieldReplacement.java index 3a945c8e7..0b82b7c33 100644 --- a/ebean-test/src/test/java/org/tests/enhancement/TestConstructorPutfieldReplacement.java +++ b/ebean-test/src/test/java/org/tests/enhancement/TestConstructorPutfieldReplacement.java @@ -9,12 +9,14 @@ import org.tests.model.basic.PFileContent; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.nio.charset.StandardCharsets; + public class TestConstructorPutfieldReplacement extends BaseTestCase { @Test public void test() { - PFile persistentFile = new PFile("test.txt", new PFileContent("test".getBytes())); + PFile persistentFile = new PFile("test.txt", new PFileContent("test".getBytes(StandardCharsets.UTF_8))); EntityBean eb = (EntityBean) persistentFile; EntityBeanIntercept ebi = eb._ebean_getIntercept(); diff --git a/ebean-test/src/test/java/org/tests/text/csv/TestCsvReader.java b/ebean-test/src/test/java/org/tests/text/csv/TestCsvReader.java index 5658d3263..e8cb48160 100644 --- a/ebean-test/src/test/java/org/tests/text/csv/TestCsvReader.java +++ b/ebean-test/src/test/java/org/tests/text/csv/TestCsvReader.java @@ -3,27 +3,25 @@ package org.tests.text.csv; import io.ebean.DB; import io.ebean.TransactionalTestCase; import io.ebean.text.csv.CsvReader; +import io.ebean.util.IOUtils; + import org.junit.jupiter.api.Test; import org.tests.model.basic.Customer; import org.tests.model.basic.ResetBasicData; -import java.io.File; -import java.io.FileReader; +import java.io.Reader; import java.net.URL; import java.util.Locale; public class TestCsvReader extends TransactionalTestCase { @Test - public void test() { + public void test() throws Exception { ResetBasicData.reset(); - try { - URL resource = TestCsvReaderWithCallback.class.getResource("/test1.csv"); - File f = new File(resource.getFile()); - - FileReader reader = new FileReader(f); + URL resource = TestCsvReaderWithCallback.class.getResource("/test1.csv"); + try (Reader reader = IOUtils.newReader(resource.openStream())){ CsvReader csvReader = DB.getDefault().createCsvReader(Customer.class); @@ -39,9 +37,7 @@ public class TestCsvReader extends TransactionalTestCase { csvReader.addProperty("billingAddress.country.code"); csvReader.process(reader); - - } catch (Exception e) { - throw new RuntimeException(e); + } } diff --git a/ebean-test/src/test/java/org/tests/text/csv/TestCsvReaderWithCallback.java b/ebean-test/src/test/java/org/tests/text/csv/TestCsvReaderWithCallback.java index bd620401e..efa424d07 100644 --- a/ebean-test/src/test/java/org/tests/text/csv/TestCsvReaderWithCallback.java +++ b/ebean-test/src/test/java/org/tests/text/csv/TestCsvReaderWithCallback.java @@ -4,11 +4,12 @@ import io.ebean.DB; import io.ebean.TransactionalTestCase; import io.ebean.text.csv.CsvReader; import io.ebean.text.csv.DefaultCsvCallback; +import io.ebean.util.IOUtils; + import org.junit.jupiter.api.Test; import org.tests.model.basic.Customer; -import java.io.File; -import java.io.FileReader; +import java.io.Reader; import java.net.URL; import java.util.Locale; @@ -20,41 +21,40 @@ public class TestCsvReaderWithCallback extends TransactionalTestCase { public void test() throws Throwable { URL resource = TestCsvReaderWithCallback.class.getResource("/test1.csv"); - File f = new File(resource.getFile()); + try (Reader reader = IOUtils.newReader(resource.openStream())) { - FileReader reader = new FileReader(f); + CsvReader csvReader = DB.getDefault().createCsvReader(Customer.class); - CsvReader csvReader = DB.getDefault().createCsvReader(Customer.class); + csvReader.setPersistBatchSize(2); + csvReader.setLogInfoFrequency(3); - csvReader.setPersistBatchSize(2); - csvReader.setLogInfoFrequency(3); + csvReader.addIgnore(); + // csvReader.addProperty("id"); + csvReader.addProperty("status"); + csvReader.addProperty("name"); + csvReader.addDateTime("anniversary", "dd-MMM-yyyy", Locale.ENGLISH); + csvReader.addProperty("billingAddress.line1"); + csvReader.addProperty("billingAddress.city"); + // processor.addReference("billingAddress.country.code"); + csvReader.addProperty("billingAddress.country.code"); - csvReader.addIgnore(); - // csvReader.addProperty("id"); - csvReader.addProperty("status"); - csvReader.addProperty("name"); - csvReader.addDateTime("anniversary", "dd-MMM-yyyy", Locale.ENGLISH); - csvReader.addProperty("billingAddress.line1"); - csvReader.addProperty("billingAddress.city"); - // processor.addReference("billingAddress.country.code"); - csvReader.addProperty("billingAddress.country.code"); + int before = DB.find(Customer.class).findCount(); - int before = DB.find(Customer.class).findCount(); + csvReader.process(reader, new DefaultCsvCallback() { - csvReader.process(reader, new DefaultCsvCallback() { + @Override + public void processBean(int row, String[] lineContent, Customer cust) { - @Override - public void processBean(int row, String[] lineContent, Customer cust) { + server.save(cust.getBillingAddress(), transaction); + server.save(cust, transaction); - server.save(cust.getBillingAddress(), transaction); - server.save(cust, transaction); + } - } + }); - }); - - int after = DB.find(Customer.class).findCount(); - assertThat(after).isEqualTo(before + 9); + int after = DB.find(Customer.class).findCount(); + assertThat(after).isEqualTo(before + 9); + } } } diff --git a/ebean-test/src/test/java/org/tests/text/json/TestJsonSimple.java b/ebean-test/src/test/java/org/tests/text/json/TestJsonSimple.java index f635d926b..c462a80cc 100644 --- a/ebean-test/src/test/java/org/tests/text/json/TestJsonSimple.java +++ b/ebean-test/src/test/java/org/tests/text/json/TestJsonSimple.java @@ -4,9 +4,12 @@ import io.ebean.BaseTestCase; import io.ebean.DB; import io.ebean.text.json.EJson; import io.ebean.text.json.JsonContext; +import io.ebean.util.IOUtils; + import org.junit.jupiter.api.Test; import java.io.*; +import java.nio.charset.StandardCharsets; import java.util.LinkedHashMap; import java.util.Map; @@ -20,19 +23,20 @@ public class TestJsonSimple extends BaseTestCase { public void test() throws IOException { InputStream is = this.getClass().getResourceAsStream("/example1.json"); + String jsonText; + try (final Reader reader = IOUtils.newReader(is)) { + LineNumberReader lineReader = new LineNumberReader(reader); - final Reader reader = new BufferedReader(new InputStreamReader(is, "UTF-8")); - LineNumberReader lineReader = new LineNumberReader(reader); + String readLine; - String readLine; + StringBuilder sb = new StringBuilder(); + while ((readLine = lineReader.readLine()) != null) { + sb.append(readLine); + } - StringBuilder sb = new StringBuilder(); - while ((readLine = lineReader.readLine()) != null) { - sb.append(readLine); + jsonText = sb.toString(); } - String jsonText = sb.toString(); - Object el = EJson.parse(jsonText); assertThat(el).isNotNull(); From 8eed983fbb23b080420b6968337ecb9e07ec918b Mon Sep 17 00:00:00 2001 From: "FOCONIS\\szemenyei" Date: Wed, 12 Jan 2022 08:37:46 +0100 Subject: [PATCH 10/10] restore old test --- .../io/ebeaninternal/server/core/DScriptRunner.java | 2 +- .../io/ebeaninternal/dbmigration/MChecksumTest.java | 10 +++++++++- ebean-test/src/test/java/io/ebean/json/EJsonTests.java | 1 - 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/core/DScriptRunner.java b/ebean-core/src/main/java/io/ebeaninternal/server/core/DScriptRunner.java index 394f1faea..fb2fbd0a2 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/core/DScriptRunner.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/core/DScriptRunner.java @@ -67,7 +67,7 @@ final class DScriptRunner implements ScriptRunner { } try (InputStream inputStream = UrlHelper.openNoCache(resource); - Reader reader = IOUtils.newReader(inputStream)) { + Reader reader = IOUtils.newReader(inputStream)) { return readContent(reader); } catch (IOException e) { diff --git a/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/MChecksumTest.java b/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/MChecksumTest.java index 65756f58f..3bd677a7e 100644 --- a/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/MChecksumTest.java +++ b/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/MChecksumTest.java @@ -7,9 +7,17 @@ import java.io.File; import static org.assertj.core.api.Assertions.assertThat; public class MChecksumTest { - + @Test public void calculate() { + File file = new File("src/test/resources/dbmigration/index/1.0__hello.sql"); + assertThat(file).exists(); + + assertThat(MChecksum.calculate(file)).isEqualTo(907060870); + } + + @Test + public void calculateWithSpecialChars() { File file = new File("src/test/resources/dbmigration/index-special-chars/1.0__hello.sql"); assertThat(file).exists(); diff --git a/ebean-test/src/test/java/io/ebean/json/EJsonTests.java b/ebean-test/src/test/java/io/ebean/json/EJsonTests.java index 6be980a40..1063e4d36 100644 --- a/ebean-test/src/test/java/io/ebean/json/EJsonTests.java +++ b/ebean-test/src/test/java/io/ebean/json/EJsonTests.java @@ -45,7 +45,6 @@ public class EJsonTests { File temp = Files.createTempFile("some", ".json").toFile(); try (Writer writer = IOUtils.newWriter(temp)) { - Map map = new LinkedHashMap<>(); map.put("foo", "bar"); EJson.write(map, writer);