diff --git a/jOOQ/src/main/java/org/jooq/CharsetProvider.java b/jOOQ/src/main/java/org/jooq/CharsetProvider.java
new file mode 100644
index 0000000000..a55213e1ff
--- /dev/null
+++ b/jOOQ/src/main/java/org/jooq/CharsetProvider.java
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ *
+ * Other licenses:
+ * -----------------------------------------------------------------------------
+ * Commercial licenses for this work are available. These replace the above
+ * ASL 2.0 and offer limited warranties, support, maintenance, and commercial
+ * database integrations.
+ *
+ * For more information, please visit: http://www.jooq.org/licenses
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+package org.jooq;
+
+import java.nio.charset.Charset;
+
+/**
+ * A provider of a default {@link Charset} to be used when converting between
+ * {@link String} data and byte[] data.
+ *
+ * @author Lukas Eder
+ */
+@FunctionalInterface
+public interface CharsetProvider {
+
+ /**
+ * Provide a charset for string to binary conversion.
+ */
+ Charset provide();
+}
diff --git a/jOOQ/src/main/java/org/jooq/Configuration.java b/jOOQ/src/main/java/org/jooq/Configuration.java
index 0b71ca1d77..81b99dab56 100644
--- a/jOOQ/src/main/java/org/jooq/Configuration.java
+++ b/jOOQ/src/main/java/org/jooq/Configuration.java
@@ -387,6 +387,12 @@ public interface Configuration extends Serializable {
@NotNull
UnwrapperProvider unwrapperProvider();
+ /**
+ * Get the configured CharsetProvider from this configuration.
+ */
+ @NotNull
+ CharsetProvider charsetProvider();
+
/**
* Get this configuration's underlying record mapper provider.
*/
@@ -927,6 +933,19 @@ public interface Configuration extends Serializable {
@NotNull
Configuration set(UnwrapperProvider newUnwrapperProvider);
+ /**
+ * Change this configuration to hold a new charset provider.
+ *
+ * This method is not thread-safe and should not be used in globally
+ * available Configuration objects.
+ *
+ * @param newCharsetProvider The new charset provider to be contained in
+ * the changed configuration.
+ * @return The changed configuration.
+ */
+ @NotNull
+ Configuration set(CharsetProvider newCharsetProvider);
+
/**
* Change this configuration to hold a new converter provider.
*
@@ -1291,6 +1310,17 @@ public interface Configuration extends Serializable {
@NotNull
Configuration derive(UnwrapperProvider newUnwrapperProvider);
+ /**
+ * Create a derived configuration from this one, with a new charset
+ * provider.
+ *
+ * @param newCharsetProvider The new charset provider to be contained in
+ * the derived configuration.
+ * @return The derived configuration.
+ */
+ @NotNull
+ Configuration derive(CharsetProvider newCharsetProvider);
+
/**
* Create a derived configuration from this one, with new converter
* provider.
diff --git a/jOOQ/src/main/java/org/jooq/FilenameComparator.java b/jOOQ/src/main/java/org/jooq/FilenameComparator.java
index afbaae6d5c..c57a52de98 100644
--- a/jOOQ/src/main/java/org/jooq/FilenameComparator.java
+++ b/jOOQ/src/main/java/org/jooq/FilenameComparator.java
@@ -94,8 +94,4 @@ final class FilenameComparator implements Comparator {
return split1.length - split2.length;
}
-
- public static void main(String[] args) {
- INSTANCE.compare("0", new String(new byte[] { 0 }));
- }
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultBinding.java b/jOOQ/src/main/java/org/jooq/impl/DefaultBinding.java
index 5d4888b9ad..d38cacf26d 100644
--- a/jOOQ/src/main/java/org/jooq/impl/DefaultBinding.java
+++ b/jOOQ/src/main/java/org/jooq/impl/DefaultBinding.java
@@ -4355,32 +4355,14 @@ public class DefaultBinding implements Binding {
private static final long serialVersionUID = 3430629127218407737L;
private static final Set EMULATE_AS_BLOB = SQLDialect.supportedBy(HSQLDB);
- private final Converter BYTES_CONVERTER;
- private final DefaultBytesBinding BYTES;
-
- @SuppressWarnings({ "serial", "unchecked", "rawtypes" })
DefaultJSONBBinding(Converter converter, boolean isLob) {
super(converter, isLob);
-
- // [#8949] TODO: Support overriding the system default Charset
- BYTES_CONVERTER = new AbstractConverter(byte[].class, JSONB.class) {
- @Override
- public JSONB from(byte[] t) {
- return t == null ? null : JSONB.valueOf(new String(t));
- }
-
- @Override
- public byte[] to(JSONB u) {
- return u == null ? null : u.toString().getBytes();
- }
- };
- BYTES = new DefaultBytesBinding<>((Converter) BYTES_CONVERTER, isLob);
}
@Override
void sqlInline0(BindingSQLContext ctx, JSONB value) throws SQLException {
if (EMULATE_AS_BLOB.contains(ctx.dialect())) {
- BYTES.sqlInline0(ctx, BYTES_CONVERTER.to(value));
+ bytes(ctx.configuration()).sqlInline0(ctx, bytesConverter(ctx.configuration()).to(value));
}
else {
super.sqlInline0(ctx, value);
@@ -4401,7 +4383,7 @@ public class DefaultBinding implements Binding {
@Override
final void set0(BindingSetStatementContext ctx, JSONB value) throws SQLException {
if (EMULATE_AS_BLOB.contains(ctx.dialect()))
- BYTES.set0(ctx, BYTES_CONVERTER.to(value));
+ bytes(ctx.configuration()).set0(ctx, bytesConverter(ctx.configuration()).to(value));
else
ctx.statement().setString(ctx.index(), value.toString());
}
@@ -4409,7 +4391,7 @@ public class DefaultBinding implements Binding {
@Override
final void set0(BindingSetSQLOutputContext ctx, JSONB value) throws SQLException {
if (EMULATE_AS_BLOB.contains(ctx.dialect()))
- BYTES.set0(ctx, BYTES_CONVERTER.to(value));
+ bytes(ctx.configuration()).set0(ctx, bytesConverter(ctx.configuration()).to(value));
else
ctx.output().writeString(value.toString());
}
@@ -4417,7 +4399,7 @@ public class DefaultBinding implements Binding {
@Override
final JSONB get0(BindingGetResultSetContext ctx) throws SQLException {
if (EMULATE_AS_BLOB.contains(ctx.dialect()))
- return BYTES_CONVERTER.from(BYTES.get0(ctx));
+ return bytesConverter(ctx.configuration()).from(bytes(ctx.configuration()).get0(ctx));
String string = ctx.resultSet().getString(ctx.index());
return string == null ? null : JSONB.valueOf(string);
@@ -4426,7 +4408,7 @@ public class DefaultBinding implements Binding {
@Override
final JSONB get0(BindingGetStatementContext ctx) throws SQLException {
if (EMULATE_AS_BLOB.contains(ctx.dialect()))
- return BYTES_CONVERTER.from(BYTES.get0(ctx));
+ return bytesConverter(ctx.configuration()).from(bytes(ctx.configuration()).get0(ctx));
String string = ctx.statement().getString(ctx.index());
return string == null ? null : JSONB.valueOf(string);
@@ -4435,7 +4417,7 @@ public class DefaultBinding implements Binding {
@Override
final JSONB get0(BindingGetSQLInputContext ctx) throws SQLException {
if (EMULATE_AS_BLOB.contains(ctx.dialect()))
- return BYTES_CONVERTER.from(BYTES.get0(ctx));
+ return bytesConverter(ctx.configuration()).from(bytes(ctx.configuration()).get0(ctx));
String string = ctx.input().readString();
return string == null ? null : JSONB.valueOf(string);
@@ -4444,10 +4426,30 @@ public class DefaultBinding implements Binding {
@Override
final int sqltype(Statement statement, Configuration configuration) {
if (EMULATE_AS_BLOB.contains(configuration.dialect()))
- BYTES.sqltype(statement, configuration);
+ bytes(configuration).sqltype(statement, configuration);
return Types.VARCHAR;
}
+
+ @SuppressWarnings({ "serial" })
+ private final Converter bytesConverter(Configuration configuration) {
+ return new AbstractConverter(byte[].class, JSONB.class) {
+ @Override
+ public JSONB from(byte[] t) {
+ return t == null ? null : JSONB.valueOf(new String(t, configuration.charsetProvider().provide()));
+ }
+
+ @Override
+ public byte[] to(JSONB u) {
+ return u == null ? null : u.toString().getBytes(configuration.charsetProvider().provide());
+ }
+ };
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ private final DefaultBytesBinding bytes(Configuration configuration) {
+ return new DefaultBytesBinding<>((Converter) bytesConverter(configuration), isLob);
+ }
}
static final class DefaultXMLBinding extends AbstractBinding {
diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultCharsetProvider.java b/jOOQ/src/main/java/org/jooq/impl/DefaultCharsetProvider.java
new file mode 100644
index 0000000000..15e94f4096
--- /dev/null
+++ b/jOOQ/src/main/java/org/jooq/impl/DefaultCharsetProvider.java
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ *
+ * Other licenses:
+ * -----------------------------------------------------------------------------
+ * Commercial licenses for this work are available. These replace the above
+ * ASL 2.0 and offer limited warranties, support, maintenance, and commercial
+ * database integrations.
+ *
+ * For more information, please visit: http://www.jooq.org/licenses
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+package org.jooq.impl;
+
+import java.nio.charset.Charset;
+
+import org.jooq.CharsetProvider;
+
+/**
+ * @author Lukas Eder
+ */
+final class DefaultCharsetProvider implements CharsetProvider {
+
+ @Override
+ public final Charset provide() {
+ return Charset.defaultCharset();
+ }
+}
diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultConfiguration.java b/jOOQ/src/main/java/org/jooq/impl/DefaultConfiguration.java
index 911b0e2786..a5cd75462e 100644
--- a/jOOQ/src/main/java/org/jooq/impl/DefaultConfiguration.java
+++ b/jOOQ/src/main/java/org/jooq/impl/DefaultConfiguration.java
@@ -53,6 +53,7 @@ import java.util.concurrent.Executor;
import javax.sql.DataSource;
+import org.jooq.CharsetProvider;
import org.jooq.Configuration;
import org.jooq.ConnectionProvider;
import org.jooq.ConverterProvider;
@@ -127,6 +128,7 @@ public class DefaultConfiguration implements Configuration {
private transient TransactionListenerProvider[] transactionListenerProviders;
private transient DiagnosticsListenerProvider[] diagnosticsListenerProviders;
private transient UnwrapperProvider unwrapperProvider;
+ private transient CharsetProvider charsetProvider;
private transient ConverterProvider converterProvider;
// [#7062] Apart from the possibility of containing user defined objects, the data
@@ -181,6 +183,7 @@ public class DefaultConfiguration implements Configuration {
null,
null,
null,
+ null,
null,
@@ -216,6 +219,7 @@ public class DefaultConfiguration implements Configuration {
configuration.transactionListenerProviders,
configuration.diagnosticsListenerProviders,
configuration.unwrapperProvider,
+ configuration.charsetProvider,
configuration.converterProvider,
configuration.clock,
@@ -251,6 +255,7 @@ public class DefaultConfiguration implements Configuration {
TransactionListenerProvider[] transactionListenerProviders,
DiagnosticsListenerProvider[] diagnosticsListenerProviders,
UnwrapperProvider unwrapperProvider,
+ CharsetProvider charsetProvider,
ConverterProvider converterProvider,
Clock clock,
@@ -275,6 +280,7 @@ public class DefaultConfiguration implements Configuration {
set(transactionListenerProviders);
set(diagnosticsListenerProviders);
set(unwrapperProvider);
+ set(charsetProvider);
set(converterProvider);
set(clock);
@@ -334,6 +340,7 @@ public class DefaultConfiguration implements Configuration {
transactionListenerProviders,
diagnosticsListenerProviders,
unwrapperProvider,
+ charsetProvider,
converterProvider,
clock,
@@ -363,6 +370,7 @@ public class DefaultConfiguration implements Configuration {
transactionListenerProviders,
diagnosticsListenerProviders,
unwrapperProvider,
+ charsetProvider,
converterProvider,
clock,
@@ -392,6 +400,7 @@ public class DefaultConfiguration implements Configuration {
transactionListenerProviders,
diagnosticsListenerProviders,
unwrapperProvider,
+ charsetProvider,
converterProvider,
clock,
@@ -426,6 +435,7 @@ public class DefaultConfiguration implements Configuration {
transactionListenerProviders,
diagnosticsListenerProviders,
unwrapperProvider,
+ charsetProvider,
converterProvider,
clock,
@@ -455,6 +465,7 @@ public class DefaultConfiguration implements Configuration {
transactionListenerProviders,
diagnosticsListenerProviders,
unwrapperProvider,
+ charsetProvider,
converterProvider,
clock,
@@ -489,6 +500,7 @@ public class DefaultConfiguration implements Configuration {
transactionListenerProviders,
diagnosticsListenerProviders,
unwrapperProvider,
+ charsetProvider,
converterProvider,
clock,
@@ -523,6 +535,7 @@ public class DefaultConfiguration implements Configuration {
transactionListenerProviders,
diagnosticsListenerProviders,
unwrapperProvider,
+ charsetProvider,
converterProvider,
clock,
@@ -557,6 +570,7 @@ public class DefaultConfiguration implements Configuration {
transactionListenerProviders,
diagnosticsListenerProviders,
unwrapperProvider,
+ charsetProvider,
converterProvider,
clock,
@@ -591,6 +605,7 @@ public class DefaultConfiguration implements Configuration {
transactionListenerProviders,
diagnosticsListenerProviders,
unwrapperProvider,
+ charsetProvider,
converterProvider,
clock,
@@ -625,6 +640,7 @@ public class DefaultConfiguration implements Configuration {
transactionListenerProviders,
diagnosticsListenerProviders,
unwrapperProvider,
+ charsetProvider,
converterProvider,
clock,
@@ -659,6 +675,7 @@ public class DefaultConfiguration implements Configuration {
transactionListenerProviders,
diagnosticsListenerProviders,
unwrapperProvider,
+ charsetProvider,
converterProvider,
clock,
@@ -693,6 +710,7 @@ public class DefaultConfiguration implements Configuration {
newTransactionListenerProviders,
diagnosticsListenerProviders,
unwrapperProvider,
+ charsetProvider,
converterProvider,
clock,
@@ -727,6 +745,7 @@ public class DefaultConfiguration implements Configuration {
transactionListenerProviders,
newDiagnosticsListenerProviders,
unwrapperProvider,
+ charsetProvider,
converterProvider,
clock,
@@ -761,6 +780,37 @@ public class DefaultConfiguration implements Configuration {
transactionListenerProviders,
diagnosticsListenerProviders,
newUnwrapperProvider,
+ charsetProvider,
+ converterProvider,
+
+ clock,
+
+ dialect,
+ settings,
+ data
+ );
+ }
+
+ @Override
+ public final Configuration derive(CharsetProvider newCharsetProvider) {
+ return new DefaultConfiguration(
+ connectionProvider,
+ interpreterConnectionProvider,
+ systemConnectionProvider,
+ metaProvider,
+ versionProvider,
+ executorProvider,
+ transactionProvider,
+ recordMapperProvider,
+ recordUnmapperProvider,
+ recordListenerProviders,
+ executeListenerProviders,
+ migrationListenerProviders,
+ visitListenerProviders,
+ transactionListenerProviders,
+ diagnosticsListenerProviders,
+ unwrapperProvider,
+ newCharsetProvider,
converterProvider,
clock,
@@ -790,6 +840,7 @@ public class DefaultConfiguration implements Configuration {
transactionListenerProviders,
diagnosticsListenerProviders,
unwrapperProvider,
+ charsetProvider,
newConverterProvider,
clock,
@@ -820,6 +871,7 @@ public class DefaultConfiguration implements Configuration {
transactionListenerProviders,
diagnosticsListenerProviders,
unwrapperProvider,
+ charsetProvider,
converterProvider,
newClock,
dialect,
@@ -848,6 +900,7 @@ public class DefaultConfiguration implements Configuration {
transactionListenerProviders,
diagnosticsListenerProviders,
unwrapperProvider,
+ charsetProvider,
converterProvider,
clock,
@@ -877,6 +930,7 @@ public class DefaultConfiguration implements Configuration {
transactionListenerProviders,
diagnosticsListenerProviders,
unwrapperProvider,
+ charsetProvider,
converterProvider,
clock,
@@ -1076,6 +1130,12 @@ public class DefaultConfiguration implements Configuration {
return this;
}
+ @Override
+ public final Configuration set(CharsetProvider newCharsetProvider) {
+ this.charsetProvider = newCharsetProvider;
+ return this;
+ }
+
@Override
public final Configuration set(ConverterProvider newConverterProvider) {
this.converterProvider = newConverterProvider != null
@@ -1450,6 +1510,13 @@ public class DefaultConfiguration implements Configuration {
: new DefaultUnwrapperProvider();
}
+ @Override
+ public final CharsetProvider charsetProvider() {
+ return charsetProvider != null
+ ? charsetProvider
+ : new DefaultCharsetProvider();
+ }
+
@Override
public final ConverterProvider converterProvider() {
return converterProvider;
@@ -1552,6 +1619,10 @@ public class DefaultConfiguration implements Configuration {
? unwrapperProvider
: null);
+ oos.writeObject(charsetProvider instanceof Serializable
+ ? charsetProvider
+ : null);
+
oos.writeObject(converterProvider instanceof Serializable
? converterProvider
: null);
@@ -1600,6 +1671,7 @@ public class DefaultConfiguration implements Configuration {
transactionListenerProviders = (TransactionListenerProvider[]) ois.readObject();
diagnosticsListenerProviders = (DiagnosticsListenerProvider[]) ois.readObject();
unwrapperProvider = (UnwrapperProvider) ois.readObject();
+ charsetProvider = (CharsetProvider) ois.readObject();
converterProvider = (ConverterProvider) ois.readObject();
data = new ConcurrentHashMap<>();
diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultDSLContext.java b/jOOQ/src/main/java/org/jooq/impl/DefaultDSLContext.java
index fbebb5cbd5..e0746a3a3a 100644
--- a/jOOQ/src/main/java/org/jooq/impl/DefaultDSLContext.java
+++ b/jOOQ/src/main/java/org/jooq/impl/DefaultDSLContext.java
@@ -1519,7 +1519,7 @@ public class DefaultDSLContext extends AbstractScope implements DSLContext, Seri
// TODO: Why does the SAXParser replace \r by \n?
XMLHandler handler = new XMLHandler(this);
- saxParser.parse(new ByteArrayInputStream(string.getBytes()), handler);
+ saxParser.parse(new ByteArrayInputStream(string.getBytes(configuration().charsetProvider().provide())), handler);
return handler.result;
}
catch (Exception e) {
diff --git a/jOOQ/src/main/java/org/jooq/tools/Convert.java b/jOOQ/src/main/java/org/jooq/tools/Convert.java
index 637355e660..cc51a4f0f9 100644
--- a/jOOQ/src/main/java/org/jooq/tools/Convert.java
+++ b/jOOQ/src/main/java/org/jooq/tools/Convert.java
@@ -530,14 +530,12 @@ public final class Convert {
if (toClass.isPrimitive()) {
// Characters default to the "zero" character
- if (toClass == char.class) {
+ if (toClass == char.class)
return (U) Character.valueOf((char) 0);
- }
// All others can be converted from (int) 0
- else {
+ else
return convert(0, toClass);
- }
}
@@ -592,21 +590,17 @@ public final class Convert {
// [#3062] [#5796] Default collections if no specific collection type was requested
if (Collection.class.isAssignableFrom(toClass) &&
- toClass.isAssignableFrom(ArrayList.class)) {
+ toClass.isAssignableFrom(ArrayList.class))
return (U) new ArrayList<>(Arrays.asList(fromArray));
- }
else if (Collection.class.isAssignableFrom(toClass) &&
- toClass.isAssignableFrom(LinkedHashSet.class)) {
+ toClass.isAssignableFrom(LinkedHashSet.class))
return (U) new LinkedHashSet<>(Arrays.asList(fromArray));
- }
// [#3443] Conversion from Object[] to JDBC Array
- else if (toClass == java.sql.Array.class) {
+ else if (toClass == java.sql.Array.class)
return (U) new MockArray(null, fromArray, fromClass);
- }
- else {
+ else
return (U) convertArray(fromArray, toClass);
- }
}
// [#3062] Default collections if no specific collection type was requested
diff --git a/jOOQ/src/main/java/org/jooq/tools/jdbc/MockConfiguration.java b/jOOQ/src/main/java/org/jooq/tools/jdbc/MockConfiguration.java
index 8c8a0e9669..c913d814a6 100644
--- a/jOOQ/src/main/java/org/jooq/tools/jdbc/MockConfiguration.java
+++ b/jOOQ/src/main/java/org/jooq/tools/jdbc/MockConfiguration.java
@@ -44,6 +44,7 @@ import java.util.concurrent.Executor;
import javax.sql.DataSource;
+import org.jooq.CharsetProvider;
import org.jooq.Configuration;
import org.jooq.ConnectionProvider;
import org.jooq.ConverterProvider;
@@ -205,6 +206,11 @@ public class MockConfiguration implements Configuration {
return delegate.unwrapperProvider();
}
+ @Override
+ public CharsetProvider charsetProvider() {
+ return delegate.charsetProvider();
+ }
+
@Override
public ConverterProvider converterProvider() {
return delegate.converterProvider();
@@ -367,6 +373,11 @@ public class MockConfiguration implements Configuration {
return delegate.set(newUnwrapperProvider);
}
+ @Override
+ public Configuration set(CharsetProvider newCharsetProvider) {
+ return delegate.set(newCharsetProvider);
+ }
+
@Override
public Configuration set(ConverterProvider newConverterProvider) {
return delegate.set(newConverterProvider);
@@ -524,6 +535,11 @@ public class MockConfiguration implements Configuration {
return delegate.derive(newUnwrapperProvider);
}
+ @Override
+ public Configuration derive(CharsetProvider newCharsetProvider) {
+ return delegate.derive(newCharsetProvider);
+ }
+
@Override
public Configuration derive(ConverterProvider newConverterProvider) {
return delegate.derive(newConverterProvider);