[jOOQ/jOOQ#13961] Add ScopedConverter, a Converter subtype that receives a ConverterScope in from() and to() methods
See also [jOOQ/jOOQ#13801]
This commit is contained in:
parent
d2850a4695
commit
1bf4199b32
@ -39,39 +39,39 @@ package org.jooq;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
|
||||
import org.jooq.impl.AbstractConverter;
|
||||
import org.jooq.impl.AbstractScopedConverter;
|
||||
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
final class ArrayComponentConverter<T, U> extends AbstractConverter<T, U> {
|
||||
final class ArrayComponentConverter<T, U> extends AbstractScopedConverter<T, U> {
|
||||
|
||||
final Converter<T[], U[]> converter;
|
||||
final ScopedConverter<T[], U[]> converter;
|
||||
|
||||
public ArrayComponentConverter(Converter<T[], U[]> converter) {
|
||||
public ArrayComponentConverter(ScopedConverter<T[], U[]> converter) {
|
||||
super((Class<T>) converter.fromType().getComponentType(), (Class<U>) converter.toType().getComponentType());
|
||||
|
||||
this.converter = converter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final U from(T t) {
|
||||
public final U from(T t, ConverterScope scope) {
|
||||
if (t == null)
|
||||
return null;
|
||||
|
||||
T[] a = (T[]) Array.newInstance(fromType(), 1);
|
||||
a[0] = t;
|
||||
return converter.from(a)[0];
|
||||
return converter.from(a, scope)[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public final T to(U u) {
|
||||
public final T to(U u, ConverterScope scope) {
|
||||
if (u == null)
|
||||
return null;
|
||||
|
||||
U[] a = (U[]) Array.newInstance(fromType(), 1);
|
||||
a[0] = u;
|
||||
return converter.to(a)[0];
|
||||
return converter.to(a, scope)[0];
|
||||
}
|
||||
}
|
||||
|
||||
@ -39,7 +39,7 @@ package org.jooq;
|
||||
|
||||
import static org.jooq.impl.Internal.arrayType;
|
||||
|
||||
import org.jooq.impl.AbstractConverter;
|
||||
import org.jooq.impl.AbstractScopedConverter;
|
||||
import org.jooq.tools.Convert;
|
||||
|
||||
/**
|
||||
@ -48,12 +48,12 @@ import org.jooq.tools.Convert;
|
||||
*
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
final class ArrayConverter<T, U> extends AbstractConverter<T[], U[]> {
|
||||
final class ArrayConverter<T, U> extends AbstractScopedConverter<T[], U[]> {
|
||||
|
||||
final Converter<T, U> converter;
|
||||
final Converter<U, T> inverse;
|
||||
final ScopedConverter<T, U> converter;
|
||||
final ScopedConverter<U, T> inverse;
|
||||
|
||||
public ArrayConverter(Converter<T, U> converter) {
|
||||
public ArrayConverter(ScopedConverter<T, U> converter) {
|
||||
super(arrayType(converter.fromType()), arrayType(converter.toType()));
|
||||
|
||||
this.converter = converter;
|
||||
@ -61,12 +61,12 @@ final class ArrayConverter<T, U> extends AbstractConverter<T[], U[]> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public final U[] from(T[] t) {
|
||||
public final U[] from(T[] t, ConverterScope scope) {
|
||||
return Convert.convertArray(t, converter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final T[] to(U[] t) {
|
||||
public final T[] to(U[] t, ConverterScope scope) {
|
||||
return Convert.convertArray(t, inverse);
|
||||
}
|
||||
}
|
||||
|
||||
@ -98,4 +98,9 @@ import java.sql.SQLOutput;
|
||||
*/
|
||||
public interface BindingScope extends Scope {
|
||||
|
||||
/**
|
||||
* Get the {@link ConverterScope} from the context of this
|
||||
* {@link BindingScope}.
|
||||
*/
|
||||
ConverterScope converterScope();
|
||||
}
|
||||
|
||||
@ -45,6 +45,7 @@ import java.util.function.Function;
|
||||
|
||||
import org.jooq.exception.DataTypeException;
|
||||
import org.jooq.impl.AbstractConverter;
|
||||
import org.jooq.impl.AbstractScopedConverter;
|
||||
import org.jooq.impl.SQLDataType;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@ -171,15 +172,15 @@ public interface Converter<T, U> extends Serializable {
|
||||
Function<? super T, ? extends U> from,
|
||||
Function<? super U, ? extends T> to
|
||||
) {
|
||||
return new AbstractConverter<T, U>(fromType, toType) {
|
||||
return new AbstractScopedConverter<T, U>(fromType, toType) {
|
||||
|
||||
@Override
|
||||
public final U from(T t) {
|
||||
public final U from(T t, ConverterScope scope) {
|
||||
return from.apply(t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final T to(U u) {
|
||||
public final T to(U u, ConverterScope scope) {
|
||||
return to.apply(u);
|
||||
}
|
||||
};
|
||||
|
||||
48
jOOQ/src/main/java/org/jooq/ConverterScope.java
Normal file
48
jOOQ/src/main/java/org/jooq/ConverterScope.java
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* A {@link Scope} that models the life cycle of a data type conversion call to
|
||||
* {@link Converter#from(Object)} or {@link Converter#to(Object)}.
|
||||
* <p>
|
||||
* Implementations
|
||||
*/
|
||||
public interface ConverterScope extends Scope {
|
||||
|
||||
}
|
||||
@ -38,10 +38,12 @@
|
||||
package org.jooq;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.jooq.exception.DataTypeException;
|
||||
import org.jooq.impl.AbstractConverter;
|
||||
import org.jooq.impl.AbstractScopedConverter;
|
||||
import org.jooq.impl.IdentityConverter;
|
||||
import org.jooq.impl.SQLDataType;
|
||||
|
||||
@ -57,15 +59,15 @@ import org.jetbrains.annotations.NotNull;
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public class Converters<T, U> extends AbstractConverter<T, U> {
|
||||
public final class Converters<T, U> extends AbstractScopedConverter<T, U> {
|
||||
|
||||
final Converter[] chain;
|
||||
final ScopedConverter[] chain;
|
||||
|
||||
/**
|
||||
* Create an identity converter.
|
||||
*/
|
||||
@NotNull
|
||||
public static <T> Converter<T, T> identity(final Class<T> type) {
|
||||
public static <T> ScopedConverter<T, T> identity(final Class<T> type) {
|
||||
return new IdentityConverter<T>(type);
|
||||
}
|
||||
|
||||
@ -77,7 +79,7 @@ public class Converters<T, U> extends AbstractConverter<T, U> {
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "3.14")
|
||||
@NotNull
|
||||
public static <T, U> Converter<T, U> of() {
|
||||
public static <T, U> ScopedConverter<T, U> of() {
|
||||
return new Converters();
|
||||
}
|
||||
|
||||
@ -89,44 +91,63 @@ public class Converters<T, U> extends AbstractConverter<T, U> {
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "3.14")
|
||||
@NotNull
|
||||
public static <T, U> Converter<T, U> of(Converter<T, U> converter) {
|
||||
return new Converters(converter);
|
||||
public static <T, U> ScopedConverter<T, U> of(Converter<T, U> converter) {
|
||||
return new Converters(ScopedConverter.scoped(converter));
|
||||
}
|
||||
|
||||
/**
|
||||
* Chain two converters.
|
||||
*/
|
||||
@NotNull
|
||||
public static <T, X1, U> Converter<T, U> of(Converter<T, ? extends X1> c1, Converter<? super X1, U> c2) {
|
||||
return new Converters(c1, c2);
|
||||
public static <T, X1, U> ScopedConverter<T, U> of(Converter<T, ? extends X1> c1, Converter<? super X1, U> c2) {
|
||||
return new Converters(
|
||||
ScopedConverter.scoped(c1),
|
||||
ScopedConverter.scoped(c2)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Chain three converters.
|
||||
*/
|
||||
@NotNull
|
||||
public static <T, X1, X2, U> Converter<T, U> of(Converter<T, ? extends X1> c1, Converter<? super X1, ? extends X2> c2, Converter<? super X2, U> c3) {
|
||||
return new Converters(c1, c2, c3);
|
||||
public static <T, X1, X2, U> ScopedConverter<T, U> of(Converter<T, ? extends X1> c1, Converter<? super X1, ? extends X2> c2, Converter<? super X2, U> c3) {
|
||||
return new Converters(
|
||||
ScopedConverter.scoped(c1),
|
||||
ScopedConverter.scoped(c2),
|
||||
ScopedConverter.scoped(c3)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Chain four converters.
|
||||
*/
|
||||
@NotNull
|
||||
public static <T, X1, X2, X3, U> Converter<T, U> of(Converter<T, ? extends X1> c1, Converter<? super X1, ? extends X2> c2, Converter<? super X2, ? extends X3> c3, Converter<? super X3, U> c4) {
|
||||
return new Converters(c1, c2, c3, c4);
|
||||
public static <T, X1, X2, X3, U> ScopedConverter<T, U> of(Converter<T, ? extends X1> c1, Converter<? super X1, ? extends X2> c2, Converter<? super X2, ? extends X3> c3, Converter<? super X3, U> c4) {
|
||||
return new Converters(
|
||||
ScopedConverter.scoped(c1),
|
||||
ScopedConverter.scoped(c2),
|
||||
ScopedConverter.scoped(c3),
|
||||
ScopedConverter.scoped(c4)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inverse a converter.
|
||||
*/
|
||||
public static <T, U> Converter<U, T> inverse(final Converter<T, U> converter) {
|
||||
return inverse(ScopedConverter.scoped(converter));
|
||||
}
|
||||
|
||||
// [#11099] Allow instanceof checks on IdentityConverter for performance reasons
|
||||
if (converter instanceof IdentityConverter)
|
||||
return (Converter<U, T>) converter;
|
||||
/**
|
||||
* Inverse a converter.
|
||||
*/
|
||||
public static <T, U> ScopedConverter<U, T> inverse(final ScopedConverter<T, U> converter) {
|
||||
|
||||
// [#11099] Allow instanceof checks on IdentityConverter for performance reasons
|
||||
if (converter instanceof IdentityConverter)
|
||||
return (ScopedConverter<U, T>) converter;
|
||||
else
|
||||
return Converter.of(converter.toType(), converter.fromType(), converter::to, converter::from);
|
||||
return ScopedConverter.of(converter.toType(), converter.fromType(), converter::to, converter::from);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -134,6 +155,14 @@ public class Converters<T, U> extends AbstractConverter<T, U> {
|
||||
* the argument converter's types.
|
||||
*/
|
||||
public static <T, U> Converter<T[], U[]> forArrays(Converter<T, U> converter) {
|
||||
return forArrays(ScopedConverter.scoped(converter));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a converter that can convert arrays with the component types being
|
||||
* the argument converter's types.
|
||||
*/
|
||||
public static <T, U> ScopedConverter<T[], U[]> forArrays(ScopedConverter<T, U> converter) {
|
||||
if (converter instanceof ArrayComponentConverter<T, U> a)
|
||||
return a.converter;
|
||||
else
|
||||
@ -145,35 +174,42 @@ public class Converters<T, U> extends AbstractConverter<T, U> {
|
||||
* converter, which converts array types.
|
||||
*/
|
||||
public static <T, U> Converter<T, U> forArrayComponents(Converter<T[], U[]> converter) {
|
||||
return forArrayComponents(ScopedConverter.scoped(converter));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a converter that can convert component types based on the argument
|
||||
* converter, which converts array types.
|
||||
*/
|
||||
public static <T, U> Converter<T, U> forArrayComponents(ScopedConverter<T[], U[]> converter) {
|
||||
if (converter instanceof ArrayConverter<T, U> a)
|
||||
return a.converter;
|
||||
else
|
||||
return new ArrayComponentConverter<>(converter);
|
||||
}
|
||||
|
||||
|
||||
Converters(Converter... chain) {
|
||||
Converters(ScopedConverter... chain) {
|
||||
super(chain[0].fromType(), chain[chain.length - 1].toType());
|
||||
|
||||
this.chain = chain;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final U from(T t) {
|
||||
public final U from(T t, ConverterScope scope) {
|
||||
Object result = t;
|
||||
|
||||
for (int i = 0; i < chain.length; i++)
|
||||
result = chain[i].from(result);
|
||||
result = chain[i].from(result, scope);
|
||||
|
||||
return (U) result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final T to(U u) {
|
||||
public final T to(U u, ConverterScope scope) {
|
||||
Object result = u;
|
||||
|
||||
for (int i = chain.length - 1; i >= 0; i--)
|
||||
result = chain[i].to(result);
|
||||
result = chain[i].to(result, scope);
|
||||
|
||||
return (T) result;
|
||||
}
|
||||
@ -201,6 +237,12 @@ public class Converters<T, U> extends AbstractConverter<T, U> {
|
||||
: f.apply(t) : t -> t == null ? null : f.apply(t);
|
||||
}
|
||||
|
||||
static final <T, U> BiFunction<T, ConverterScope, U> nullable(BiFunction<? super T, ? super ConverterScope, ? extends U> f) {
|
||||
return f instanceof Serializable
|
||||
? (BiFunction<T, ConverterScope, U> & Serializable) (t, x) -> t == null ? null
|
||||
: f.apply(t, x) : (t, x) -> t == null ? null : f.apply(t, x);
|
||||
}
|
||||
|
||||
static final <T, U> Function<T, U> notImplemented() {
|
||||
return t -> { throw new DataTypeException("Conversion function not implemented"); };
|
||||
}
|
||||
|
||||
@ -139,7 +139,7 @@ public interface DataType<T> extends Named {
|
||||
* Get the converter associated with this data type.
|
||||
*/
|
||||
@NotNull
|
||||
Converter<?, T> getConverter();
|
||||
ScopedConverter<?, T> getConverter();
|
||||
|
||||
/**
|
||||
* Retrieve the Java type associated with this data type.
|
||||
|
||||
@ -71,6 +71,12 @@ import org.jetbrains.annotations.Nullable;
|
||||
*/
|
||||
public interface ExecuteContext extends Scope {
|
||||
|
||||
/**
|
||||
* Get a {@link ConverterScope} for the scope of this
|
||||
* {@link ExecuteContext}.
|
||||
*/
|
||||
ConverterScope converterScope();
|
||||
|
||||
/**
|
||||
* The connection to be used in this execute context.
|
||||
* <p>
|
||||
|
||||
@ -44,6 +44,12 @@ import org.jetbrains.annotations.Nullable;
|
||||
*/
|
||||
public interface ExecuteScope extends Scope {
|
||||
|
||||
/**
|
||||
* Get the {@link ConverterScope} from the context of this
|
||||
* {@link ExecuteScope}.
|
||||
*/
|
||||
ConverterScope converterScope();
|
||||
|
||||
/**
|
||||
* The {@link ExecuteContext} that created this scope.
|
||||
*
|
||||
|
||||
186
jOOQ/src/main/java/org/jooq/ScopedConverter.java
Normal file
186
jOOQ/src/main/java/org/jooq/ScopedConverter.java
Normal file
@ -0,0 +1,186 @@
|
||||
/*
|
||||
* 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 static org.jooq.Converters.nullable;
|
||||
import static org.jooq.impl.Internal.converterScope;
|
||||
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.jooq.impl.AbstractConverter;
|
||||
import org.jooq.impl.AbstractScopedConverter;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* A special type of {@link Converter} with alternative
|
||||
* {@link #from(Object, ConverterScope)} and {@link #to(Object, ConverterScope)}
|
||||
* methods.
|
||||
* <p>
|
||||
* This special converter type can be used wherever an ordinary
|
||||
* {@link Converter} is used. jOOQ internal call sites will call the alternative
|
||||
* {@link #from(Object, ConverterScope)} and {@link #to(Object, ConverterScope)}
|
||||
* methods, instead of {@link #from(Object)} and {@link #to(Object)}, allowing
|
||||
* for accessing global {@link Configuration#data()} content.
|
||||
*/
|
||||
public interface ScopedConverter<T, U> extends Converter<T, U> {
|
||||
|
||||
/**
|
||||
* Construct a new converter from functions.
|
||||
*
|
||||
* @param <T> the database type.
|
||||
* @param <U> the user type.
|
||||
* @param fromType The database type.
|
||||
* @param toType The user type.
|
||||
* @param from A function converting from T to U when reading from the
|
||||
* database.
|
||||
* @param to A function converting from U to T when writing to the database.
|
||||
* @return The converter.
|
||||
* @see Converter
|
||||
*/
|
||||
@NotNull
|
||||
static <T, U> ScopedConverter<T, U> of(
|
||||
Class<T> fromType,
|
||||
Class<U> toType,
|
||||
BiFunction<? super T, ? super ConverterScope, ? extends U> from,
|
||||
BiFunction<? super U, ? super ConverterScope, ? extends T> to
|
||||
) {
|
||||
return new AbstractScopedConverter<T, U>(fromType, toType) {
|
||||
|
||||
@Override
|
||||
public final U from(T t, ConverterScope scope) {
|
||||
return from.apply(t, scope);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final T to(U u, ConverterScope scope) {
|
||||
return to.apply(u, scope);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new converter from functions.
|
||||
* <p>
|
||||
* This works like {@link Converter#of(Class, Class, Function, Function)},
|
||||
* except that both conversion {@link Function}s are decorated with a
|
||||
* function that always returns <code>null</code> for <code>null</code>
|
||||
* inputs.
|
||||
* <p>
|
||||
* Example:
|
||||
* <p>
|
||||
* <pre><code>
|
||||
* Converter<String, Integer> converter =
|
||||
* Converter.ofNullable(String.class, Integer.class, Integer::parseInt, Object::toString);
|
||||
*
|
||||
* // No exceptions thrown
|
||||
* assertNull(converter.from(null));
|
||||
* assertNull(converter.to(null));
|
||||
* </code></pre>
|
||||
*
|
||||
* @param <T> the database type
|
||||
* @param <U> the user type
|
||||
* @param fromType The database type
|
||||
* @param toType The user type
|
||||
* @param from A function converting from T to U when reading from the
|
||||
* database.
|
||||
* @param to A function converting from U to T when writing to the database.
|
||||
* @return The converter.
|
||||
* @see Converter
|
||||
*/
|
||||
@NotNull
|
||||
static <T, U> ScopedConverter<T, U> ofNullable(
|
||||
Class<T> fromType,
|
||||
Class<U> toType,
|
||||
BiFunction<? super T, ? super ConverterScope, ? extends U> from,
|
||||
BiFunction<? super U, ? super ConverterScope, ? extends T> to
|
||||
) {
|
||||
return of(fromType, toType, nullable(from), nullable(to));
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn a {@link Converter} into a {@link ScopedConverter}.
|
||||
*/
|
||||
@NotNull
|
||||
static <T, U> ScopedConverter<T, U> scoped(Converter<T, U> converter) {
|
||||
if (converter instanceof ScopedConverter<T, U> s)
|
||||
return s;
|
||||
else
|
||||
return new AbstractScopedConverter<T, U>(converter.fromType(), converter.toType()) {
|
||||
@Override
|
||||
public U from(T t, ConverterScope scope) {
|
||||
return converter.from(t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T to(U u, ConverterScope scope) {
|
||||
return converter.to(u);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Read and convert a database object to a user object.
|
||||
*
|
||||
* @param databaseObject The database object.
|
||||
* @param scope The scope of this conversion.
|
||||
* @return The user object.
|
||||
*/
|
||||
U from(T databaseObject, ConverterScope scope);
|
||||
|
||||
/**
|
||||
* Convert and write a user object to a database object.
|
||||
*
|
||||
* @param userObject The user object.
|
||||
* @param scope The scope of this conversion.
|
||||
* @return The database object.
|
||||
*/
|
||||
T to(U userObject, ConverterScope scope);
|
||||
|
||||
@Override
|
||||
default T to(U userObject) {
|
||||
return to(userObject, converterScope());
|
||||
}
|
||||
|
||||
@Override
|
||||
default U from(T databaseObject) {
|
||||
return from(databaseObject, converterScope());
|
||||
}
|
||||
}
|
||||
@ -62,7 +62,7 @@ public interface Typed<T> extends QueryPart {
|
||||
* the generated object.
|
||||
*/
|
||||
@NotNull
|
||||
Converter<?, T> getConverter();
|
||||
ScopedConverter<?, T> getConverter();
|
||||
|
||||
/**
|
||||
* The object's underlying {@link Binding}.
|
||||
|
||||
@ -78,6 +78,7 @@ import org.jooq.Clause;
|
||||
import org.jooq.Condition;
|
||||
import org.jooq.Configuration;
|
||||
import org.jooq.Context;
|
||||
import org.jooq.ConverterScope;
|
||||
import org.jooq.DSLContext;
|
||||
import org.jooq.ExecuteContext;
|
||||
import org.jooq.Field;
|
||||
@ -235,6 +236,11 @@ abstract class AbstractContext<C extends Context<C>> extends AbstractScope imple
|
||||
// ExecuteScope API
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public final ConverterScope converterScope() {
|
||||
return ctx != null ? ctx.converterScope() : Tools.converterScope(configuration());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final ExecuteContext executeContext() {
|
||||
return ctx;
|
||||
|
||||
@ -106,6 +106,7 @@ import org.jooq.Result;
|
||||
import org.jooq.Row;
|
||||
import org.jooq.SQLDialect;
|
||||
import org.jooq.Schema;
|
||||
import org.jooq.ScopedConverter;
|
||||
import org.jooq.Table;
|
||||
import org.jooq.XML;
|
||||
import org.jooq.impl.QOM.GenerationLocation;
|
||||
@ -114,6 +115,8 @@ import org.jooq.impl.QOM.UEmpty;
|
||||
import org.jooq.types.Interval;
|
||||
import org.jooq.types.UNumber;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
// ...
|
||||
|
||||
/**
|
||||
@ -563,8 +566,8 @@ implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Converter<?, T> getConverter() {
|
||||
return getBinding().converter();
|
||||
public final ScopedConverter<?, T> getConverter() {
|
||||
return (@NotNull ScopedConverter<?, T>) ScopedConverter.scoped(getBinding().converter());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -37,6 +37,7 @@
|
||||
*/
|
||||
package org.jooq.impl;
|
||||
|
||||
import org.jooq.ConverterScope;
|
||||
import org.jooq.ExecuteContext;
|
||||
import org.jooq.ExecuteScope;
|
||||
|
||||
@ -55,6 +56,11 @@ abstract class AbstractExecuteScope extends AbstractScope implements ExecuteScop
|
||||
this.ctx = ctx;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final ConverterScope converterScope() {
|
||||
return ctx.converterScope();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExecuteContext executeContext() {
|
||||
return ctx;
|
||||
|
||||
@ -40,9 +40,11 @@ package org.jooq.impl;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.Collections.emptyList;
|
||||
import static org.jooq.ScopedConverter.scoped;
|
||||
import static org.jooq.conf.SettingsTools.updatablePrimaryKeys;
|
||||
import static org.jooq.impl.Tools.EMPTY_FIELD;
|
||||
import static org.jooq.impl.Tools.converterOrFail;
|
||||
import static org.jooq.impl.Tools.converterScope;
|
||||
import static org.jooq.impl.Tools.embeddedFields;
|
||||
import static org.jooq.impl.Tools.indexFail;
|
||||
import static org.jooq.impl.Tools.indexOrFail;
|
||||
@ -102,7 +104,6 @@ import org.jooq.XMLFormat;
|
||||
import org.jooq.exception.IOException;
|
||||
import org.jooq.exception.InvalidResultException;
|
||||
import org.jooq.exception.MappingException;
|
||||
import org.jooq.tools.JooqLogger;
|
||||
import org.jooq.tools.StringUtils;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@ -335,12 +336,12 @@ abstract class AbstractRecord extends AbstractStore implements Record {
|
||||
@Override
|
||||
public final <U> U get(Field<?> field, Class<? extends U> type) {
|
||||
Object t = get(field);
|
||||
return (U) converterOrFail(this, t, (Class) field.getType(), type).from(t);
|
||||
return (U) converterOrFail(this, t, (Class) field.getType(), type).from(t, converterScope(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T, U> U get(Field<T> field, Converter<? super T, ? extends U> converter) {
|
||||
return converter.from(get(field));
|
||||
return scoped(converter).from(get(field), converterScope(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -351,7 +352,7 @@ abstract class AbstractRecord extends AbstractStore implements Record {
|
||||
@Override
|
||||
public final <U> U get(int index, Class<? extends U> type) {
|
||||
Object t = get(index);
|
||||
return (U) converterOrFail(this, t, (Class) field(safeIndex(index)).getType(), type).from(t);
|
||||
return (U) converterOrFail(this, t, (Class) field(safeIndex(index)).getType(), type).from(t, converterScope(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -474,7 +475,7 @@ abstract class AbstractRecord extends AbstractStore implements Record {
|
||||
|
||||
@Override
|
||||
public final <T, U> void set(Field<T> field, U value, Converter<? extends T, ? super U> converter) {
|
||||
set(field, converter.to(value));
|
||||
set(field, scoped(converter).to(value, converterScope(this)));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -64,6 +64,7 @@ import org.jooq.Record;
|
||||
import org.jooq.Row;
|
||||
import org.jooq.Row1;
|
||||
import org.jooq.Row2;
|
||||
import org.jooq.ScopedConverter;
|
||||
import org.jooq.SelectField;
|
||||
// ...
|
||||
import org.jooq.impl.QOM.UnmodifiableList;
|
||||
@ -151,7 +152,7 @@ abstract class AbstractRow<R extends Record> extends AbstractQueryPart implement
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Converter<?, R> getConverter() {
|
||||
public final ScopedConverter<?, R> getConverter() {
|
||||
return rf().getConverter();
|
||||
}
|
||||
|
||||
|
||||
@ -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.impl;
|
||||
|
||||
import org.jooq.ScopedConverter;
|
||||
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
public abstract class AbstractScopedConverter<T, U> extends AbstractConverter<T, U> implements ScopedConverter<T, U> {
|
||||
|
||||
public AbstractScopedConverter(Class<T> fromType, Class<U> toType) {
|
||||
super(fromType, toType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ScopedConverter [ " + fromType().getName() + " -> " + toType().getName() + " ]";
|
||||
}
|
||||
}
|
||||
@ -107,6 +107,7 @@ import org.jooq.Row;
|
||||
import org.jooq.RowId;
|
||||
import org.jooq.SQL;
|
||||
import org.jooq.Schema;
|
||||
import org.jooq.ScopedConverter;
|
||||
import org.jooq.Select;
|
||||
import org.jooq.SelectField;
|
||||
import org.jooq.Table;
|
||||
@ -203,7 +204,7 @@ implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Converter<?, R> getConverter() {
|
||||
public final ScopedConverter<?, R> getConverter() {
|
||||
return getDataType().getConverter();
|
||||
}
|
||||
|
||||
|
||||
@ -46,6 +46,7 @@ import org.jooq.DataType;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.Generator;
|
||||
import org.jooq.Name;
|
||||
import org.jooq.ScopedConverter;
|
||||
import org.jooq.Typed;
|
||||
|
||||
/**
|
||||
@ -71,7 +72,7 @@ abstract class AbstractTypedNamed<T> extends AbstractNamed implements Typed<T> {
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public final Converter<?, T> getConverter() {
|
||||
public final ScopedConverter<?, T> getConverter() {
|
||||
return getDataType().getConverter();
|
||||
}
|
||||
|
||||
|
||||
@ -56,6 +56,7 @@ import jakarta.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.namespace.QName;
|
||||
|
||||
import org.jooq.Converter;
|
||||
import org.jooq.ConverterScope;
|
||||
import org.jooq.XML;
|
||||
|
||||
/**
|
||||
@ -80,21 +81,21 @@ public class AbstractXMLasObjectBinding<T> extends AbstractXMLBinding<T> {
|
||||
return converter;
|
||||
}
|
||||
|
||||
private static final class XMLasObjectConverter<T> implements Converter<XML, T> {
|
||||
private static final class XMLasObjectConverter<T> extends AbstractScopedConverter<XML, T> {
|
||||
|
||||
Class<T> type;
|
||||
XmlRootElement root;
|
||||
transient JAXBContext ctx;
|
||||
XmlRootElement root;
|
||||
transient JAXBContext ctx;
|
||||
|
||||
private XMLasObjectConverter(Class<T> type) {
|
||||
this.type = type;
|
||||
super(XML.class, type);
|
||||
|
||||
this.root = type.getAnnotation(XmlRootElement.class);
|
||||
this.ctx = initCtx();
|
||||
}
|
||||
|
||||
private final JAXBContext initCtx() {
|
||||
try {
|
||||
return JAXBContext.newInstance(type);
|
||||
return JAXBContext.newInstance(toType());
|
||||
}
|
||||
catch (JAXBException e) {
|
||||
throw new DataBindingException(e);
|
||||
@ -102,15 +103,15 @@ public class AbstractXMLasObjectBinding<T> extends AbstractXMLBinding<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public T from(XML t) {
|
||||
public T from(XML t, ConverterScope scope) {
|
||||
if (t == null)
|
||||
return null;
|
||||
|
||||
return JAXB.unmarshal(new StringReader("" + t), type);
|
||||
return JAXB.unmarshal(new StringReader("" + t), toType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public XML to(T u) {
|
||||
public XML to(T u, ConverterScope scope) {
|
||||
if (u == null)
|
||||
return null;
|
||||
|
||||
@ -118,9 +119,8 @@ public class AbstractXMLasObjectBinding<T> extends AbstractXMLBinding<T> {
|
||||
StringWriter s = new StringWriter();
|
||||
|
||||
Object o = u;
|
||||
if (root == null) {
|
||||
o = new JAXBElement<>(new QName(decapitalize(type.getSimpleName())), type, u);
|
||||
}
|
||||
if (root == null)
|
||||
o = new JAXBElement<>(new QName(decapitalize(toType().getSimpleName())), toType(), u);
|
||||
|
||||
Marshaller m = ctx.createMarshaller();
|
||||
m.setProperty(Marshaller.JAXB_FRAGMENT, true);
|
||||
@ -132,16 +132,6 @@ public class AbstractXMLasObjectBinding<T> extends AbstractXMLBinding<T> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<XML> fromType() {
|
||||
return XML.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<T> toType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
private void writeObject(ObjectOutputStream oos) throws IOException {
|
||||
oos.defaultWriteObject();
|
||||
}
|
||||
|
||||
@ -40,7 +40,9 @@ package org.jooq.impl;
|
||||
import static java.time.temporal.ChronoField.INSTANT_SECONDS;
|
||||
import static java.time.temporal.ChronoField.MILLI_OF_DAY;
|
||||
import static java.time.temporal.ChronoField.MILLI_OF_SECOND;
|
||||
import static org.jooq.ScopedConverter.scoped;
|
||||
import static org.jooq.impl.Internal.arrayType;
|
||||
import static org.jooq.impl.Internal.converterScope;
|
||||
import static org.jooq.impl.Tools.configuration;
|
||||
import static org.jooq.impl.Tools.emulateMultiset;
|
||||
import static org.jooq.tools.reflect.Reflect.accessible;
|
||||
@ -90,11 +92,10 @@ import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import jakarta.xml.bind.JAXB;
|
||||
|
||||
// ...
|
||||
import org.jooq.Converter;
|
||||
import org.jooq.ConverterProvider;
|
||||
import org.jooq.ConverterScope;
|
||||
import org.jooq.EnumType;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.JSON;
|
||||
@ -124,6 +125,8 @@ import org.jooq.types.ULong;
|
||||
import org.jooq.types.UShort;
|
||||
import org.jooq.util.xml.jaxb.InformationSchema;
|
||||
|
||||
import jakarta.xml.bind.JAXB;
|
||||
|
||||
/**
|
||||
* Utility methods for type conversions
|
||||
* <p>
|
||||
@ -400,7 +403,7 @@ final class Convert {
|
||||
}
|
||||
|
||||
static final <U> U[] convertCollection(Collection from, Class<? extends U[]> to){
|
||||
return new ConvertAll<U[]>(to).from(from);
|
||||
return new ConvertAll<U[]>(to).from(from, converterScope());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -430,10 +433,10 @@ final class Convert {
|
||||
Class<T> fromType = converter.fromType();
|
||||
|
||||
if (fromType == Object.class)
|
||||
return converter.from((T) from);
|
||||
return scoped(converter).from((T) from, converterScope());
|
||||
|
||||
ConvertAll<T> convertAll = new ConvertAll<>(fromType);
|
||||
return converter.from(convertAll.from(from));
|
||||
return scoped(converter).from(convertAll.from(from, converterScope()), converterScope());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -544,7 +547,7 @@ final class Convert {
|
||||
List<U> result = new ArrayList<>(collection.size());
|
||||
|
||||
for (Object o : collection)
|
||||
result.add(convert(all.from(o), converter));
|
||||
result.add(convert(all.from(o, converterScope()), converter));
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -557,17 +560,20 @@ final class Convert {
|
||||
/**
|
||||
* The converter to convert them all.
|
||||
*/
|
||||
private static class ConvertAll<U> implements Converter<Object, U> {
|
||||
private static final class ConvertAll<U> extends AbstractScopedConverter<Object, U> {
|
||||
|
||||
private final Class<? extends U> toClass;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
ConvertAll(Class<? extends U> toClass) {
|
||||
super(Object.class, (Class<U>) toClass);
|
||||
|
||||
this.toClass = toClass;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
@Override
|
||||
public U from(Object from) {
|
||||
public U from(Object from, ConverterScope scope) {
|
||||
if (from == null) {
|
||||
|
||||
// [#936] If types are converted to primitives, the result must not
|
||||
@ -608,7 +614,7 @@ final class Convert {
|
||||
|
||||
// [#12557] Anything can be unwrapped from Optional
|
||||
else if (fromClass == Optional.class)
|
||||
return from(((Optional) from).orElse(null));
|
||||
return from(((Optional) from).orElse(null), scope);
|
||||
|
||||
// Regular checks
|
||||
else if (fromClass == byte[].class) {
|
||||
@ -1396,21 +1402,10 @@ final class Convert {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object to(U to) {
|
||||
public Object to(U to, ConverterScope scope) {
|
||||
return to;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Object> fromType() {
|
||||
return Object.class;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Class<U> toType() {
|
||||
return (Class<U>) toClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a long timestamp (millis) to any date type.
|
||||
*/
|
||||
|
||||
@ -37,6 +37,8 @@
|
||||
*/
|
||||
package org.jooq.impl;
|
||||
|
||||
import static org.jooq.impl.Internal.converterScope;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@ -54,6 +56,7 @@ import org.jooq.Record;
|
||||
import org.jooq.Result;
|
||||
import org.jooq.Row;
|
||||
import org.jooq.SQLDialect;
|
||||
import org.jooq.ScopedConverter;
|
||||
import org.jooq.exception.DataTypeException;
|
||||
import org.jooq.impl.DefaultBinding.InternalBinding;
|
||||
import org.jooq.impl.QOM.GenerationLocation;
|
||||
@ -306,7 +309,7 @@ final class ConvertedDataType<T, U> extends AbstractDataTypeX<U> {
|
||||
|
||||
// [#3200] Try to convert arbitrary objects to T
|
||||
else
|
||||
return ((Converter<T, U>) getConverter()).from(delegate.convert(object));
|
||||
return ((ScopedConverter<T, U>) getConverter()).from(delegate.convert(object), converterScope());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -84,6 +84,7 @@ import org.jooq.Field;
|
||||
// ...
|
||||
import org.jooq.Record;
|
||||
import org.jooq.Result;
|
||||
import org.jooq.ScopedConverter;
|
||||
import org.jooq.exception.ControlFlowSignal;
|
||||
import org.jooq.tools.JooqLogger;
|
||||
import org.jooq.tools.jdbc.JDBC41ResultSet;
|
||||
@ -1570,7 +1571,7 @@ final class CursorImpl<R extends Record> extends AbstractCursor<R> {
|
||||
|
||||
// [#7100] TODO: Is there a more elegant way to do this?
|
||||
if (f != field)
|
||||
value = ((Converter<Object, T>) field.getConverter()).from(value);
|
||||
value = ((ScopedConverter<Object, T>) field.getConverter()).from(value, ctx.converterScope());
|
||||
|
||||
offset += operation.offset - nestedOffset + nested.size() - 1;
|
||||
}
|
||||
|
||||
@ -42,6 +42,7 @@ import java.time.LocalDate;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.jooq.Converter;
|
||||
import org.jooq.ConverterScope;
|
||||
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
@ -51,19 +52,19 @@ import org.jooq.Converter;
|
||||
* <code>Converter.ofNullable(Date.class, LocalDate.class, Date::toLocalDate, Date::valueOf)</code>.
|
||||
*/
|
||||
@Deprecated
|
||||
public final class DateToLocalDateConverter extends AbstractConverter<Date, LocalDate> {
|
||||
public final class DateToLocalDateConverter extends AbstractScopedConverter<Date, LocalDate> {
|
||||
|
||||
public DateToLocalDateConverter() {
|
||||
super(Date.class, LocalDate.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final LocalDate from(Date t) {
|
||||
public final LocalDate from(Date t, ConverterScope scope) {
|
||||
return t == null ? null : t.toLocalDate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Date to(LocalDate u) {
|
||||
public final Date to(LocalDate u, ConverterScope scope) {
|
||||
return u == null ? null : Date.valueOf(u);
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,6 +82,7 @@ import static org.jooq.SQLDialect.SQLITE;
|
||||
// ...
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.YUGABYTEDB;
|
||||
import static org.jooq.ScopedConverter.scoped;
|
||||
import static org.jooq.conf.ParamType.INLINED;
|
||||
import static org.jooq.impl.Convert.convert;
|
||||
import static org.jooq.impl.Convert.patchIso8601Timestamp;
|
||||
@ -211,6 +212,7 @@ import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.regex.Pattern;
|
||||
@ -223,11 +225,13 @@ import org.jooq.BindingGetSQLInputContext;
|
||||
import org.jooq.BindingGetStatementContext;
|
||||
import org.jooq.BindingRegisterContext;
|
||||
import org.jooq.BindingSQLContext;
|
||||
import org.jooq.BindingScope;
|
||||
import org.jooq.BindingSetSQLOutputContext;
|
||||
import org.jooq.BindingSetStatementContext;
|
||||
import org.jooq.Configuration;
|
||||
import org.jooq.Context;
|
||||
import org.jooq.Converter;
|
||||
import org.jooq.ConverterScope;
|
||||
import org.jooq.Converters;
|
||||
import org.jooq.DataType;
|
||||
import org.jooq.EnumType;
|
||||
@ -250,6 +254,7 @@ import org.jooq.RowId;
|
||||
import org.jooq.SQLDialect;
|
||||
import org.jooq.Schema;
|
||||
import org.jooq.Scope;
|
||||
import org.jooq.ScopedConverter;
|
||||
import org.jooq.Source;
|
||||
import org.jooq.Spatial;
|
||||
import org.jooq.TableRecord;
|
||||
@ -370,31 +375,31 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
|
||||
else if (type == LocalDate.class)
|
||||
return (Binding<T, U>) new DelegatingBinding<>(
|
||||
(DataType<LocalDate>) dataType,
|
||||
Converter.ofNullable(Date.class, LocalDate.class,
|
||||
(Function<Date, LocalDate> & Serializable) Date::toLocalDate,
|
||||
(Function<LocalDate, Date> & Serializable) Date::valueOf
|
||||
ScopedConverter.ofNullable(Date.class, LocalDate.class,
|
||||
(BiFunction<Date, ConverterScope, LocalDate> & Serializable) (t, x) -> t.toLocalDate(),
|
||||
(BiFunction<LocalDate, ConverterScope, Date> & Serializable) (t, x) -> Date.valueOf(t)
|
||||
),
|
||||
(Converter<LocalDate, U>) converter,
|
||||
(ScopedConverter<LocalDate, U>) converter,
|
||||
c -> new DefaultDateBinding<>(DATE, c)
|
||||
);
|
||||
else if (type == LocalDateTime.class)
|
||||
return (Binding<T, U>) new DelegatingBinding<>(
|
||||
(DataType<LocalDateTime>) dataType,
|
||||
Converter.ofNullable(Timestamp.class, LocalDateTime.class,
|
||||
(Function<Timestamp, LocalDateTime> & Serializable) Timestamp::toLocalDateTime,
|
||||
(Function<LocalDateTime, Timestamp> & Serializable) Timestamp::valueOf
|
||||
ScopedConverter.ofNullable(Timestamp.class, LocalDateTime.class,
|
||||
(BiFunction<Timestamp, ConverterScope, LocalDateTime> & Serializable) (t, x) -> t.toLocalDateTime(),
|
||||
(BiFunction<LocalDateTime, ConverterScope, Timestamp> & Serializable) (t, x) -> Timestamp.valueOf(t)
|
||||
),
|
||||
(Converter<LocalDateTime, U>) converter,
|
||||
(ScopedConverter<LocalDateTime, U>) converter,
|
||||
c -> new DefaultTimestampBinding<>(TIMESTAMP, c)
|
||||
);
|
||||
else if (type == LocalTime.class)
|
||||
return (Binding<T, U>) new DelegatingBinding<>(
|
||||
(DataType<LocalTime>) dataType,
|
||||
Converter.ofNullable(Time.class, LocalTime.class,
|
||||
(Function<Time, LocalTime> & Serializable) Time::toLocalTime,
|
||||
(Function<LocalTime, Time> & Serializable) Time::valueOf
|
||||
ScopedConverter.ofNullable(Time.class, LocalTime.class,
|
||||
(BiFunction<Time, ConverterScope, LocalTime> & Serializable) (t, x) -> t.toLocalTime(),
|
||||
(BiFunction<LocalTime, ConverterScope, Time> & Serializable) (t, x) -> Time.valueOf(t)
|
||||
),
|
||||
(Converter<LocalTime, U>) converter,
|
||||
(ScopedConverter<LocalTime, U>) converter,
|
||||
c -> new DefaultTimeBinding<>(TIME, c)
|
||||
);
|
||||
else if (type == Long.class || type == long.class)
|
||||
@ -424,41 +429,41 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
|
||||
else if (type == UByte.class)
|
||||
return (Binding<T, U>) new DelegatingBinding<>(
|
||||
(DataType<UByte>) dataType,
|
||||
Converter.ofNullable(Short.class, UByte.class,
|
||||
(Function<Short, UByte> & Serializable) UByte::valueOf,
|
||||
(Function<UByte, Short> & Serializable) UByte::shortValue
|
||||
ScopedConverter.ofNullable(Short.class, UByte.class,
|
||||
(BiFunction<Short, ConverterScope, UByte> & Serializable) (t, x) -> UByte.valueOf(t),
|
||||
(BiFunction<UByte, ConverterScope, Short> & Serializable) (t, x) -> t.shortValue()
|
||||
),
|
||||
(Converter<UByte, U>) converter,
|
||||
(ScopedConverter<UByte, U>) converter,
|
||||
c -> new DefaultShortBinding<>(SMALLINT, c)
|
||||
);
|
||||
else if (type == UInteger.class)
|
||||
return (Binding<T, U>) new DelegatingBinding<>(
|
||||
(DataType<UInteger>) dataType,
|
||||
Converter.ofNullable(Long.class, UInteger.class,
|
||||
(Function<Long, UInteger> & Serializable) UInteger::valueOf,
|
||||
(Function<UInteger, Long> & Serializable) UInteger::longValue
|
||||
ScopedConverter.ofNullable(Long.class, UInteger.class,
|
||||
(BiFunction<Long, ConverterScope, UInteger> & Serializable) (t, x) -> UInteger.valueOf(t),
|
||||
(BiFunction<UInteger, ConverterScope, Long> & Serializable) (t, x) -> t.longValue()
|
||||
),
|
||||
(Converter<UInteger, U>) converter,
|
||||
(ScopedConverter<UInteger, U>) converter,
|
||||
c -> new DefaultLongBinding<>(BIGINT, c)
|
||||
);
|
||||
else if (type == ULong.class)
|
||||
return (Binding<T, U>) new DelegatingBinding<>(
|
||||
(DataType<ULong>) dataType,
|
||||
Converter.ofNullable(BigInteger.class, ULong.class,
|
||||
(Function<BigInteger, ULong> & Serializable) ULong::valueOf,
|
||||
(Function<ULong, BigInteger> & Serializable) ULong::toBigInteger
|
||||
ScopedConverter.ofNullable(BigInteger.class, ULong.class,
|
||||
(BiFunction<BigInteger, ConverterScope, ULong> & Serializable) (t, x) -> ULong.valueOf(t),
|
||||
(BiFunction<ULong, ConverterScope, BigInteger> & Serializable) (t, x) -> t.toBigInteger()
|
||||
),
|
||||
(Converter<ULong, U>) converter,
|
||||
(ScopedConverter<ULong, U>) converter,
|
||||
c -> new DefaultBigIntegerBinding<>(DECIMAL_INTEGER, c)
|
||||
);
|
||||
else if (type == UShort.class)
|
||||
return (Binding<T, U>) new DelegatingBinding<>(
|
||||
(DataType<UShort>) dataType,
|
||||
Converter.ofNullable(Integer.class, UShort.class,
|
||||
(Function<Integer, UShort> & Serializable) UShort::valueOf,
|
||||
(Function<UShort, Integer> & Serializable) UShort::intValue
|
||||
ScopedConverter.ofNullable(Integer.class, UShort.class,
|
||||
(BiFunction<Integer, ConverterScope, UShort> & Serializable) (t, x) -> UShort.valueOf(t),
|
||||
(BiFunction<UShort, ConverterScope, Integer> & Serializable) (t, x) -> t.intValue()
|
||||
),
|
||||
(Converter<UShort, U>) converter,
|
||||
(ScopedConverter<UShort, U>) converter,
|
||||
c -> new DefaultIntegerBinding<>(INTEGER, c)
|
||||
);
|
||||
else if (type == UUID.class)
|
||||
@ -515,12 +520,12 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
|
||||
theBinding = (Binding) binding;
|
||||
}
|
||||
else if (binding == null) {
|
||||
theBinding = binding(dataType, (Converter<T, U>) converter);
|
||||
theBinding = binding(dataType, (ScopedConverter<T, U>) scoped(converter));
|
||||
}
|
||||
else {
|
||||
theBinding = new Binding<T, U>() {
|
||||
|
||||
final Converter<T, U> theConverter = Converters.of(binding.converter(), converter);
|
||||
final ScopedConverter<T, U> theConverter = Converters.of(binding.converter(), converter);
|
||||
|
||||
@Override
|
||||
public Converter<T, U> converter() {
|
||||
@ -696,12 +701,12 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
|
||||
|
||||
|
||||
final DataType<T> dataType;
|
||||
final Converter<T, U> converter;
|
||||
final ScopedConverter<T, U> converter;
|
||||
final boolean attachable;
|
||||
|
||||
InternalBinding(DataType<T> dataType, Converter<T, U> converter) {
|
||||
this.dataType = dataType;
|
||||
this.converter = converter;
|
||||
this.converter = ScopedConverter.scoped(converter);
|
||||
|
||||
// [#11099] Caching this per binding seems to have a considerable performance effect.
|
||||
// We must be careful to short circuit instanceof Attachable checks only if we *know*
|
||||
@ -711,7 +716,7 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Converter<T, U> converter() {
|
||||
public final ScopedConverter<T, U> converter() {
|
||||
return converter;
|
||||
}
|
||||
|
||||
@ -935,7 +940,7 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
|
||||
|
||||
@Override
|
||||
public final void sql(BindingSQLContext<U> ctx) throws SQLException {
|
||||
T converted = converter().to(ctx.value());
|
||||
T converted = converter().to(ctx.value(), ctx.converterScope());
|
||||
|
||||
// Casting can be enforced or prevented
|
||||
switch (ctx.render().castMode()) {
|
||||
@ -995,7 +1000,7 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
|
||||
|
||||
@Override
|
||||
public final void set(BindingSetStatementContext<U> ctx) throws SQLException {
|
||||
T value = converter().to(ctx.value());
|
||||
T value = converter().to(ctx.value(), ctx.converterScope());
|
||||
|
||||
if (!FALSE.equals(ctx.settings().isExecuteLogging()))
|
||||
if (log.isTraceEnabled())
|
||||
@ -1012,7 +1017,7 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
|
||||
|
||||
@Override
|
||||
public final void set(BindingSetSQLOutputContext<U> ctx) throws SQLException {
|
||||
T value = converter().to(ctx.value());
|
||||
T value = converter().to(ctx.value(), ctx.converterScope());
|
||||
|
||||
if (value == null)
|
||||
ctx.output().writeObject(null);
|
||||
@ -1022,7 +1027,7 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
|
||||
|
||||
@Override
|
||||
public final void get(BindingGetResultSetContext<U> ctx) throws SQLException {
|
||||
U value = converter().from(get0(ctx));
|
||||
U value = converter().from(get0(ctx), ctx.converterScope());
|
||||
|
||||
if (attachable)
|
||||
value = attach(value, ctx.configuration());
|
||||
@ -1032,7 +1037,7 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
|
||||
|
||||
@Override
|
||||
public final void get(BindingGetStatementContext<U> ctx) throws SQLException {
|
||||
U value = converter().from(get0(ctx));
|
||||
U value = converter().from(get0(ctx), ctx.converterScope());
|
||||
|
||||
if (attachable)
|
||||
value = attach(value, ctx.configuration());
|
||||
@ -1042,7 +1047,7 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
|
||||
|
||||
@Override
|
||||
public final void get(BindingGetSQLInputContext<U> ctx) throws SQLException {
|
||||
U value = converter().from(get0(ctx));
|
||||
U value = converter().from(get0(ctx), ctx.converterScope());
|
||||
|
||||
if (attachable)
|
||||
value = attach(value, ctx.configuration());
|
||||
@ -1107,14 +1112,14 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
|
||||
|
||||
static final class DelegatingBinding<X, T, U> extends InternalBinding<X, U> {
|
||||
|
||||
private final Converter<T, X> delegatingConverter;
|
||||
private final ScopedConverter<T, X> delegatingConverter;
|
||||
private final InternalBinding<T, U> delegatingBinding;
|
||||
|
||||
DelegatingBinding(
|
||||
DataType<X> originalDataType,
|
||||
Converter<T, X> delegatingConverter,
|
||||
Converter<X, U> originalConverter,
|
||||
Function<? super Converter<T, U>, ? extends InternalBinding<T, U>> f
|
||||
ScopedConverter<T, X> delegatingConverter,
|
||||
ScopedConverter<X, U> originalConverter,
|
||||
Function<? super ScopedConverter<T, U>, ? extends InternalBinding<T, U>> f
|
||||
) {
|
||||
super(originalDataType, originalConverter);
|
||||
|
||||
@ -1124,17 +1129,17 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
|
||||
|
||||
@Override
|
||||
final void sqlInline0(BindingSQLContext<U> ctx, X value) throws SQLException {
|
||||
delegatingBinding.sqlInline0(ctx, delegatingConverter.to(value));
|
||||
delegatingBinding.sqlInline0(ctx, delegatingConverter.to(value, ctx.converterScope()));
|
||||
}
|
||||
|
||||
@Override
|
||||
final void sqlBind0(BindingSQLContext<U> ctx, X value) throws SQLException {
|
||||
delegatingBinding.sqlBind0(ctx, delegatingConverter.to(value));
|
||||
delegatingBinding.sqlBind0(ctx, delegatingConverter.to(value, ctx.converterScope()));
|
||||
}
|
||||
|
||||
@Override
|
||||
final void set0(BindingSetStatementContext<U> ctx, X value) throws SQLException {
|
||||
delegatingBinding.set0(ctx, delegatingConverter.to(value));
|
||||
delegatingBinding.set0(ctx, delegatingConverter.to(value, ctx.converterScope()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -1144,22 +1149,22 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
|
||||
|
||||
@Override
|
||||
final void set0(BindingSetSQLOutputContext<U> ctx, X value) throws SQLException {
|
||||
delegatingBinding.set0(ctx, delegatingConverter.to(value));
|
||||
delegatingBinding.set0(ctx, delegatingConverter.to(value, ctx.converterScope()));
|
||||
}
|
||||
|
||||
@Override
|
||||
final X get0(BindingGetResultSetContext<U> ctx) throws SQLException {
|
||||
return delegatingConverter.from(delegatingBinding.get0(ctx));
|
||||
return delegatingConverter.from(delegatingBinding.get0(ctx), ctx.converterScope());
|
||||
}
|
||||
|
||||
@Override
|
||||
final X get0(BindingGetStatementContext<U> ctx) throws SQLException {
|
||||
return delegatingConverter.from(delegatingBinding.get0(ctx));
|
||||
return delegatingConverter.from(delegatingBinding.get0(ctx), ctx.converterScope());
|
||||
}
|
||||
|
||||
@Override
|
||||
final X get0(BindingGetSQLInputContext<U> ctx) throws SQLException {
|
||||
return delegatingConverter.from(delegatingBinding.get0(ctx));
|
||||
return delegatingConverter.from(delegatingBinding.get0(ctx), ctx.converterScope());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -3454,11 +3459,12 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
|
||||
|
||||
static final class DefaultInstantBinding<U> extends InternalBinding<Instant, U> {
|
||||
|
||||
private static final Converter<OffsetDateTime, Instant> CONVERTER = Converter.ofNullable(
|
||||
@SuppressWarnings("unchecked")
|
||||
private static final ScopedConverter<OffsetDateTime, Instant> CONVERTER = ScopedConverter.ofNullable(
|
||||
OffsetDateTime.class,
|
||||
Instant.class,
|
||||
(Function<OffsetDateTime, Instant> & Serializable) OffsetDateTime::toInstant,
|
||||
(Function<Instant, OffsetDateTime> & Serializable) i -> OffsetDateTime.ofInstant(i, ZoneOffset.UTC)
|
||||
(BiFunction<OffsetDateTime, ConverterScope, Instant> & Serializable) (t, x) -> t.toInstant(),
|
||||
(BiFunction<Instant, ConverterScope, OffsetDateTime> & Serializable) (i, x) -> OffsetDateTime.ofInstant(i, ZoneOffset.UTC)
|
||||
);
|
||||
|
||||
private final DefaultOffsetDateTimeBinding<U> delegate;
|
||||
@ -3476,32 +3482,32 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
|
||||
|
||||
@Override
|
||||
final void sqlInline0(BindingSQLContext<U> ctx, Instant value) throws SQLException {
|
||||
delegate.sqlInline0(ctx, CONVERTER.to(value));
|
||||
delegate.sqlInline0(ctx, CONVERTER.to(value, ctx.converterScope()));
|
||||
}
|
||||
|
||||
@Override
|
||||
final void set0(BindingSetStatementContext<U> ctx, Instant value) throws SQLException {
|
||||
delegate.set0(ctx, CONVERTER.to(value));
|
||||
delegate.set0(ctx, CONVERTER.to(value, ctx.converterScope()));
|
||||
}
|
||||
|
||||
@Override
|
||||
final void set0(BindingSetSQLOutputContext<U> ctx, Instant value) throws SQLException {
|
||||
delegate.set0(ctx, CONVERTER.to(value));
|
||||
delegate.set0(ctx, CONVERTER.to(value, ctx.converterScope()));
|
||||
}
|
||||
|
||||
@Override
|
||||
final Instant get0(BindingGetResultSetContext<U> ctx) throws SQLException {
|
||||
return CONVERTER.from(delegate.get0(ctx));
|
||||
return CONVERTER.from(delegate.get0(ctx), ctx.converterScope());
|
||||
}
|
||||
|
||||
@Override
|
||||
final Instant get0(BindingGetStatementContext<U> ctx) throws SQLException {
|
||||
return CONVERTER.from(delegate.get0(ctx));
|
||||
return CONVERTER.from(delegate.get0(ctx), ctx.converterScope());
|
||||
}
|
||||
|
||||
@Override
|
||||
final Instant get0(BindingGetSQLInputContext<U> ctx) throws SQLException {
|
||||
return CONVERTER.from(delegate.get0(ctx));
|
||||
return CONVERTER.from(delegate.get0(ctx), ctx.converterScope());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -3841,8 +3847,8 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static final <T, U> U pgFromString(Scope ctx, Field<U> field, String string) {
|
||||
Converter<T, U> converter = (Converter<T, U>) field.getConverter();
|
||||
private static final <T, U> U pgFromString(BindingScope ctx, Field<U> field, String string) {
|
||||
ScopedConverter<T, U> converter = (ScopedConverter<T, U>) field.getConverter();
|
||||
Class<?> type = wrapper(converter.fromType());
|
||||
|
||||
if (string == null)
|
||||
@ -3850,88 +3856,88 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
|
||||
else if (type == Blob.class)
|
||||
; // Not supported
|
||||
else if (type == Boolean.class)
|
||||
return converter.from((T) Convert.convert(string, Boolean.class));
|
||||
return converter.from((T) Convert.convert(string, Boolean.class), ctx.converterScope());
|
||||
else if (type == BigInteger.class)
|
||||
return converter.from((T) new BigInteger(string));
|
||||
return converter.from((T) new BigInteger(string), ctx.converterScope());
|
||||
else if (type == BigDecimal.class)
|
||||
return converter.from((T) new BigDecimal(string));
|
||||
return converter.from((T) new BigDecimal(string), ctx.converterScope());
|
||||
else if (type == Byte.class)
|
||||
return converter.from((T) Byte.valueOf(string));
|
||||
return converter.from((T) Byte.valueOf(string), ctx.converterScope());
|
||||
else if (type == byte[].class)
|
||||
return converter.from((T) PostgresUtils.toBytes(string));
|
||||
return converter.from((T) PostgresUtils.toBytes(string), ctx.converterScope());
|
||||
else if (type == Clob.class)
|
||||
; // Not supported
|
||||
else if (type == Date.class)
|
||||
return converter.from((T) Date.valueOf(string));
|
||||
return converter.from((T) Date.valueOf(string), ctx.converterScope());
|
||||
else if (type == Double.class)
|
||||
return converter.from((T) Double.valueOf(string));
|
||||
return converter.from((T) Double.valueOf(string), ctx.converterScope());
|
||||
else if (type == Float.class)
|
||||
return converter.from((T) Float.valueOf(string));
|
||||
return converter.from((T) Float.valueOf(string), ctx.converterScope());
|
||||
else if (type == Integer.class)
|
||||
return converter.from((T) Integer.valueOf(string));
|
||||
return converter.from((T) Integer.valueOf(string), ctx.converterScope());
|
||||
else if (type == Long.class)
|
||||
return converter.from((T) Long.valueOf(string));
|
||||
return converter.from((T) Long.valueOf(string), ctx.converterScope());
|
||||
else if (type == Short.class)
|
||||
return converter.from((T) Short.valueOf(string));
|
||||
return converter.from((T) Short.valueOf(string), ctx.converterScope());
|
||||
else if (type == String.class)
|
||||
return converter.from((T) string);
|
||||
return converter.from((T) string, ctx.converterScope());
|
||||
else if (type == Time.class)
|
||||
return converter.from((T) Time.valueOf(string));
|
||||
return converter.from((T) Time.valueOf(string), ctx.converterScope());
|
||||
else if (type == Timestamp.class)
|
||||
return converter.from((T) Timestamp.valueOf(patchIso8601Timestamp(string, false)));
|
||||
return converter.from((T) Timestamp.valueOf(patchIso8601Timestamp(string, false)), ctx.converterScope());
|
||||
else if (type == LocalTime.class)
|
||||
return converter.from((T) LocalTime.parse(string));
|
||||
return converter.from((T) LocalTime.parse(string), ctx.converterScope());
|
||||
else if (type == LocalDate.class)
|
||||
return converter.from((T) LocalDate.parse(string));
|
||||
return converter.from((T) LocalDate.parse(string), ctx.converterScope());
|
||||
else if (type == LocalDateTime.class)
|
||||
return converter.from((T) LocalDateTime.parse(patchIso8601Timestamp(string, true)));
|
||||
return converter.from((T) LocalDateTime.parse(patchIso8601Timestamp(string, true)), ctx.converterScope());
|
||||
else if (type == OffsetTime.class)
|
||||
return converter.from((T) OffsetDateTimeParser.offsetTime(string));
|
||||
return converter.from((T) OffsetDateTimeParser.offsetTime(string), ctx.converterScope());
|
||||
else if (type == OffsetDateTime.class)
|
||||
return converter.from((T) OffsetDateTimeParser.offsetDateTime(string));
|
||||
return converter.from((T) OffsetDateTimeParser.offsetDateTime(string), ctx.converterScope());
|
||||
else if (type == Instant.class)
|
||||
return converter.from((T) OffsetDateTimeParser.offsetDateTime(string).toInstant());
|
||||
return converter.from((T) OffsetDateTimeParser.offsetDateTime(string).toInstant(), ctx.converterScope());
|
||||
else if (type == JSON.class)
|
||||
return converter.from((T) JSON.json(string));
|
||||
return converter.from((T) JSON.json(string), ctx.converterScope());
|
||||
else if (type == JSONB.class)
|
||||
return converter.from((T) JSONB.jsonb(string));
|
||||
return converter.from((T) JSONB.jsonb(string), ctx.converterScope());
|
||||
else if (type == UByte.class)
|
||||
return converter.from((T) UByte.valueOf(string));
|
||||
return converter.from((T) UByte.valueOf(string), ctx.converterScope());
|
||||
else if (type == UShort.class)
|
||||
return converter.from((T) UShort.valueOf(string));
|
||||
return converter.from((T) UShort.valueOf(string), ctx.converterScope());
|
||||
else if (type == UInteger.class)
|
||||
return converter.from((T) UInteger.valueOf(string));
|
||||
return converter.from((T) UInteger.valueOf(string), ctx.converterScope());
|
||||
else if (type == ULong.class)
|
||||
return converter.from((T) ULong.valueOf(string));
|
||||
return converter.from((T) ULong.valueOf(string), ctx.converterScope());
|
||||
else if (type == UUID.class)
|
||||
return converter.from((T) UUID.fromString(string));
|
||||
return converter.from((T) UUID.fromString(string), ctx.converterScope());
|
||||
else if (type == XML.class)
|
||||
return converter.from((T) XML.xml(string));
|
||||
return converter.from((T) XML.xml(string), ctx.converterScope());
|
||||
else if (type.isArray())
|
||||
return converter.from((T) pgNewArray(ctx, field, type, string));
|
||||
return converter.from((T) pgNewArray(ctx, field, type, string), ctx.converterScope());
|
||||
|
||||
|
||||
|
||||
|
||||
else if (EnumType.class.isAssignableFrom(type))
|
||||
return converter.from((T) DefaultEnumTypeBinding.getEnumType((Class<EnumType>) type, string));
|
||||
return converter.from((T) DefaultEnumTypeBinding.getEnumType((Class<EnumType>) type, string), ctx.converterScope());
|
||||
else if (Result.class.isAssignableFrom(type))
|
||||
if (string.startsWith("<"))
|
||||
return converter.from((T) readMultisetXML(ctx, (AbstractRow<Record>) field.getDataType().getRow(), (Class<Record>) field.getDataType().getRecordType(), string));
|
||||
return converter.from((T) readMultisetXML(ctx, (AbstractRow<Record>) field.getDataType().getRow(), (Class<Record>) field.getDataType().getRecordType(), string), ctx.converterScope());
|
||||
else
|
||||
return converter.from((T) readMultisetJSON(ctx, (AbstractRow<Record>) field.getDataType().getRow(), (Class<Record>) field.getDataType().getRecordType(), string));
|
||||
return converter.from((T) readMultisetJSON(ctx, (AbstractRow<Record>) field.getDataType().getRow(), (Class<Record>) field.getDataType().getRecordType(), string), ctx.converterScope());
|
||||
else if (Record.class.isAssignableFrom(type)
|
||||
|
||||
// [#11812] UDTRecords/TableRecords or InternalRecords that don't have an explicit converter
|
||||
&& (!InternalRecord.class.isAssignableFrom(type) || type == converter.fromType()))
|
||||
return converter.from((T) pgNewRecord(ctx, type, (AbstractRow<?>) field.getDataType().getRow(), string));
|
||||
return converter.from((T) pgNewRecord(ctx, type, (AbstractRow<?>) field.getDataType().getRow(), string), ctx.converterScope());
|
||||
else if (type == Object.class)
|
||||
return converter.from((T) string);
|
||||
return converter.from((T) string, ctx.converterScope());
|
||||
|
||||
// [#4964] [#6058] Recurse only if we have a meaningful converter, not the identity converter,
|
||||
// which would cause a StackOverflowError, here!
|
||||
else if (type != wrapper(converter.toType())) {
|
||||
return converter.from((T) pgFromString(ctx, field("converted_field", ((ConvertedDataType<?, ?>) field.getDataType()).delegate()), string));
|
||||
return converter.from((T) pgFromString(ctx, field("converted_field", ((ConvertedDataType<?, ?>) field.getDataType()).delegate()), string), ctx.converterScope());
|
||||
}
|
||||
|
||||
throw new UnsupportedOperationException("Class " + type + " is not supported");
|
||||
@ -3949,7 +3955,7 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
|
||||
* @return The converted {@link UDTRecord}
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
static final Record pgNewRecord(Scope ctx, Class<?> type, AbstractRow<?> fields, Object object) {
|
||||
static final Record pgNewRecord(BindingScope ctx, Class<?> type, AbstractRow<?> fields, Object object) {
|
||||
if (object == null)
|
||||
return null;
|
||||
|
||||
@ -3980,7 +3986,7 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
|
||||
});
|
||||
}
|
||||
|
||||
private static final <T> void pgSetValue(Scope ctx, Record record, Field<T> field, String value) {
|
||||
private static final <T> void pgSetValue(BindingScope ctx, Record record, Field<T> field, String value) {
|
||||
record.set(field, pgFromString(ctx, field, value));
|
||||
}
|
||||
|
||||
@ -3993,7 +3999,7 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
|
||||
* @param string A String representation of an array
|
||||
* @return The converted array
|
||||
*/
|
||||
private static final Object[] pgNewArray(Scope ctx, Field<?> field, Class<?> type, String string) {
|
||||
private static final Object[] pgNewArray(BindingScope ctx, Field<?> field, Class<?> type, String string) {
|
||||
if (string == null)
|
||||
return null;
|
||||
|
||||
@ -5410,7 +5416,7 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
|
||||
@Override
|
||||
void sqlInline0(BindingSQLContext<U> ctx, JSONB value) throws SQLException {
|
||||
if (EMULATE_AS_BLOB.contains(ctx.dialect())) {
|
||||
bytes(ctx.configuration()).sqlInline0(ctx, bytesConverter(ctx.configuration()).to(value));
|
||||
bytes(ctx.configuration()).sqlInline0(ctx, bytesConverter(ctx.configuration()).to(value, ctx.converterScope()));
|
||||
}
|
||||
else {
|
||||
super.sqlInline0(ctx, value);
|
||||
@ -5431,7 +5437,7 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
|
||||
@Override
|
||||
final void set0(BindingSetStatementContext<U> ctx, JSONB value) throws SQLException {
|
||||
if (EMULATE_AS_BLOB.contains(ctx.dialect()))
|
||||
bytes(ctx.configuration()).set0(ctx, bytesConverter(ctx.configuration()).to(value));
|
||||
bytes(ctx.configuration()).set0(ctx, bytesConverter(ctx.configuration()).to(value, ctx.converterScope()));
|
||||
else
|
||||
ctx.statement().setString(ctx.index(), value.data());
|
||||
}
|
||||
@ -5439,7 +5445,7 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
|
||||
@Override
|
||||
final void set0(BindingSetSQLOutputContext<U> ctx, JSONB value) throws SQLException {
|
||||
if (EMULATE_AS_BLOB.contains(ctx.dialect()))
|
||||
bytes(ctx.configuration()).set0(ctx, bytesConverter(ctx.configuration()).to(value));
|
||||
bytes(ctx.configuration()).set0(ctx, bytesConverter(ctx.configuration()).to(value, ctx.converterScope()));
|
||||
else
|
||||
ctx.output().writeString(value.data());
|
||||
}
|
||||
@ -5447,7 +5453,7 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
|
||||
@Override
|
||||
final JSONB get0(BindingGetResultSetContext<U> ctx) throws SQLException {
|
||||
if (EMULATE_AS_BLOB.contains(ctx.dialect()))
|
||||
return bytesConverter(ctx.configuration()).from(bytes(ctx.configuration()).get0(ctx));
|
||||
return bytesConverter(ctx.configuration()).from(bytes(ctx.configuration()).get0(ctx), ctx.converterScope());
|
||||
|
||||
String string = ctx.resultSet().getString(ctx.index());
|
||||
return string == null ? null : JSONB.valueOf(string);
|
||||
@ -5456,7 +5462,7 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
|
||||
@Override
|
||||
final JSONB get0(BindingGetStatementContext<U> ctx) throws SQLException {
|
||||
if (EMULATE_AS_BLOB.contains(ctx.dialect()))
|
||||
return bytesConverter(ctx.configuration()).from(bytes(ctx.configuration()).get0(ctx));
|
||||
return bytesConverter(ctx.configuration()).from(bytes(ctx.configuration()).get0(ctx), ctx.converterScope());
|
||||
|
||||
String string = ctx.statement().getString(ctx.index());
|
||||
return string == null ? null : JSONB.valueOf(string);
|
||||
@ -5465,7 +5471,7 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
|
||||
@Override
|
||||
final JSONB get0(BindingGetSQLInputContext<U> ctx) throws SQLException {
|
||||
if (EMULATE_AS_BLOB.contains(ctx.dialect()))
|
||||
return bytesConverter(ctx.configuration()).from(bytes(ctx.configuration()).get0(ctx));
|
||||
return bytesConverter(ctx.configuration()).from(bytes(ctx.configuration()).get0(ctx), ctx.converterScope());
|
||||
|
||||
String string = ctx.input().readString();
|
||||
return string == null ? null : JSONB.valueOf(string);
|
||||
@ -5479,10 +5485,10 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
|
||||
return Types.VARCHAR;
|
||||
}
|
||||
|
||||
private final Converter<byte[], JSONB> bytesConverter(final Configuration configuration) {
|
||||
return Converter.ofNullable(byte[].class, JSONB.class,
|
||||
t -> JSONB.valueOf(new String(t, configuration.charsetProvider().provide())),
|
||||
u -> u.toString().getBytes(configuration.charsetProvider().provide())
|
||||
private final ScopedConverter<byte[], JSONB> bytesConverter(final Configuration configuration) {
|
||||
return ScopedConverter.ofNullable(byte[].class, JSONB.class,
|
||||
(t, x) -> JSONB.valueOf(new String(t, configuration.charsetProvider().provide())),
|
||||
(u, x) -> u.toString().getBytes(configuration.charsetProvider().provide())
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -37,6 +37,8 @@
|
||||
*/
|
||||
package org.jooq.impl;
|
||||
|
||||
import static org.jooq.ScopedConverter.scoped;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
|
||||
import org.jooq.BindingGetResultSetContext;
|
||||
@ -101,7 +103,7 @@ class DefaultBindingGetResultSetContext<U> extends AbstractExecuteScope implemen
|
||||
return new DefaultBindingGetResultSetContext<T>(ctx, resultSet, index) {
|
||||
@Override
|
||||
public void value(T v) {
|
||||
outer.value(converter.from(v));
|
||||
outer.value(scoped(converter).from(v, converterScope()));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -37,6 +37,8 @@
|
||||
*/
|
||||
package org.jooq.impl;
|
||||
|
||||
import static org.jooq.ScopedConverter.scoped;
|
||||
|
||||
import java.sql.SQLInput;
|
||||
|
||||
import org.jooq.BindingGetSQLInputContext;
|
||||
@ -78,7 +80,7 @@ class DefaultBindingGetSQLInputContext<U> extends AbstractExecuteScope implement
|
||||
return new DefaultBindingGetSQLInputContext<T>(ctx, input) {
|
||||
@Override
|
||||
public void value(T v) {
|
||||
outer.value(converter.from(v));
|
||||
outer.value(scoped(converter).from(v, converterScope()));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -37,11 +37,14 @@
|
||||
*/
|
||||
package org.jooq.impl;
|
||||
|
||||
import static org.jooq.ScopedConverter.scoped;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
|
||||
import org.jooq.BindingGetStatementContext;
|
||||
import org.jooq.Converter;
|
||||
import org.jooq.ExecuteContext;
|
||||
import org.jooq.ScopedConverter;
|
||||
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
@ -85,7 +88,7 @@ class DefaultBindingGetStatementContext<U> extends AbstractExecuteScope implemen
|
||||
return new DefaultBindingGetStatementContext<T>(ctx, statement, index) {
|
||||
@Override
|
||||
public void value(T v) {
|
||||
outer.value(converter.from(v));
|
||||
outer.value(scoped(converter).from(v, converterScope()));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -37,11 +37,14 @@
|
||||
*/
|
||||
package org.jooq.impl;
|
||||
|
||||
import static org.jooq.ScopedConverter.scoped;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.jooq.BindingSQLContext;
|
||||
import org.jooq.Configuration;
|
||||
import org.jooq.Converter;
|
||||
import org.jooq.ConverterScope;
|
||||
import org.jooq.RenderContext;
|
||||
|
||||
/**
|
||||
@ -65,6 +68,11 @@ class DefaultBindingSQLContext<U> extends AbstractScope implements BindingSQLCon
|
||||
this.variable = variable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final ConverterScope converterScope() {
|
||||
return render.converterScope();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final RenderContext render() {
|
||||
return render;
|
||||
@ -82,7 +90,7 @@ class DefaultBindingSQLContext<U> extends AbstractScope implements BindingSQLCon
|
||||
|
||||
@Override
|
||||
public <T> BindingSQLContext<T> convert(Converter<? extends T, ? super U> converter) {
|
||||
return new DefaultBindingSQLContext<>(configuration, data, render, converter.to(value), variable);
|
||||
return new DefaultBindingSQLContext<>(configuration, data, render, scoped(converter).to(value, converterScope()), variable);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -37,6 +37,8 @@
|
||||
*/
|
||||
package org.jooq.impl;
|
||||
|
||||
import static org.jooq.ScopedConverter.scoped;
|
||||
|
||||
import java.sql.SQLOutput;
|
||||
|
||||
import org.jooq.BindingSetSQLOutputContext;
|
||||
@ -70,7 +72,7 @@ class DefaultBindingSetSQLOutputContext<U> extends AbstractExecuteScope implemen
|
||||
|
||||
@Override
|
||||
public final <T> BindingSetSQLOutputContext<T> convert(Converter<? extends T, ? super U> converter) {
|
||||
return new DefaultBindingSetSQLOutputContext<>(ctx, output, converter.to(value));
|
||||
return new DefaultBindingSetSQLOutputContext<>(ctx, output, scoped(converter).to(value, converterScope()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -37,6 +37,8 @@
|
||||
*/
|
||||
package org.jooq.impl;
|
||||
|
||||
import static org.jooq.ScopedConverter.scoped;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
|
||||
import org.jooq.BindingSetStatementContext;
|
||||
@ -77,7 +79,7 @@ class DefaultBindingSetStatementContext<U> extends AbstractExecuteScope implemen
|
||||
|
||||
@Override
|
||||
public final <T> BindingSetStatementContext<T> convert(Converter<? extends T, ? super U> converter) {
|
||||
return new DefaultBindingSetStatementContext<>(ctx, statement, index, converter.to(value));
|
||||
return new DefaultBindingSetStatementContext<>(ctx, statement, index, scoped(converter).to(value, converterScope()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
57
jOOQ/src/main/java/org/jooq/impl/DefaultConverterScope.java
Normal file
57
jOOQ/src/main/java/org/jooq/impl/DefaultConverterScope.java
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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.util.Map;
|
||||
|
||||
import org.jooq.Configuration;
|
||||
import org.jooq.ConverterScope;
|
||||
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
final class DefaultConverterScope extends AbstractScope implements ConverterScope {
|
||||
|
||||
DefaultConverterScope(Configuration configuration) {
|
||||
super(configuration, new DataMap());
|
||||
}
|
||||
|
||||
DefaultConverterScope(Configuration configuration, Map<Object, Object> data) {
|
||||
super(configuration, data);
|
||||
}
|
||||
}
|
||||
@ -61,6 +61,7 @@ import java.util.Map;
|
||||
import org.jooq.Configuration;
|
||||
import org.jooq.ConnectionProvider;
|
||||
import org.jooq.Constants;
|
||||
import org.jooq.ConverterScope;
|
||||
import org.jooq.DDLQuery;
|
||||
import org.jooq.DSLContext;
|
||||
import org.jooq.Delete;
|
||||
@ -94,6 +95,7 @@ class DefaultExecuteContext implements ExecuteContext {
|
||||
private static final JooqLogger log = JooqLogger.getLogger(DefaultExecuteContext.class);
|
||||
|
||||
// Persistent attributes (repeatable)
|
||||
private final ConverterScope converterScope;
|
||||
private final Instant creationTime;
|
||||
private final Configuration originalConfiguration;
|
||||
private final Configuration derivedConfiguration;
|
||||
@ -335,6 +337,7 @@ class DefaultExecuteContext implements ExecuteContext {
|
||||
this.data = new DataMap();
|
||||
this.query = query;
|
||||
this.routine = routine;
|
||||
this.converterScope = new DefaultConverterScope(derivedConfiguration, data);
|
||||
|
||||
if (routine != null) {
|
||||
this.batch = false;
|
||||
@ -366,6 +369,11 @@ class DefaultExecuteContext implements ExecuteContext {
|
||||
clean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final ConverterScope converterScope() {
|
||||
return converterScope;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Instant creationTime() {
|
||||
return creationTime;
|
||||
|
||||
@ -37,26 +37,37 @@
|
||||
*/
|
||||
package org.jooq.impl;
|
||||
|
||||
import org.jooq.Converter;
|
||||
import org.jooq.ConverterScope;
|
||||
import org.jooq.ScopedConverter;
|
||||
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
public class DelegatingConverter<T, U> extends AbstractConverter<T, U> {
|
||||
public class DelegatingConverter<T, U> extends AbstractScopedConverter<T, U> {
|
||||
|
||||
private final Converter<T, U> delegate;
|
||||
private final ScopedConverter<T, U> delegate;
|
||||
|
||||
public DelegatingConverter(Converter<T, U> delegate) {
|
||||
public DelegatingConverter(ScopedConverter<T, U> delegate) {
|
||||
super(delegate.fromType(), delegate.toType());
|
||||
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final U from(T t, ConverterScope scope) {
|
||||
return delegate.from(t, scope);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final U from(T t) {
|
||||
return delegate.from(t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final T to(U u, ConverterScope scope) {
|
||||
return delegate.to(u, scope);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final T to(U u) {
|
||||
return delegate.to(u);
|
||||
|
||||
@ -55,6 +55,7 @@ import org.jooq.Function1;
|
||||
import org.jooq.Function2;
|
||||
import org.jooq.Name;
|
||||
import org.jooq.Schema;
|
||||
import org.jooq.ScopedConverter;
|
||||
import org.jooq.QueryPart;
|
||||
import org.jooq.impl.QOM.UNotYetImplemented;
|
||||
|
||||
@ -92,7 +93,7 @@ class DomainImpl<T> extends AbstractNamed implements Domain<T>, UNotYetImplement
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Converter<?, T> getConverter() {
|
||||
public final ScopedConverter<?, T> getConverter() {
|
||||
return type.getConverter();
|
||||
}
|
||||
|
||||
|
||||
@ -38,18 +38,21 @@
|
||||
package org.jooq.impl;
|
||||
|
||||
import static org.jooq.impl.Convert.convert;
|
||||
import static org.jooq.impl.Internal.converterScope;
|
||||
import static org.jooq.tools.reflect.Reflect.wrapper;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.jooq.ConverterScope;
|
||||
|
||||
/**
|
||||
* A base class for enum conversion.
|
||||
*
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
public class EnumConverter<T, U extends Enum<U>> extends AbstractConverter<T, U> {
|
||||
public /* non-final */ class EnumConverter<T, U extends Enum<U>> extends AbstractConverter<T, U> {
|
||||
|
||||
private final Map<T, U> lookup;
|
||||
private final Function<? super U, ? extends T> to;
|
||||
@ -77,8 +80,8 @@ public class EnumConverter<T, U extends Enum<U>> extends AbstractConverter<T, U>
|
||||
}
|
||||
|
||||
@Override
|
||||
public final U from(T databaseObject) {
|
||||
return lookup.get(databaseObject);
|
||||
public final U from(T t) {
|
||||
return lookup.get(t);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -88,11 +91,11 @@ public class EnumConverter<T, U extends Enum<U>> extends AbstractConverter<T, U>
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public T to(U userObject) {
|
||||
if (userObject == null)
|
||||
public T to(U u) {
|
||||
if (u == null)
|
||||
return null;
|
||||
else
|
||||
return to.apply(userObject);
|
||||
return to.apply(u);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -38,13 +38,15 @@
|
||||
package org.jooq.impl;
|
||||
|
||||
import org.jooq.Converter;
|
||||
import org.jooq.ConverterScope;
|
||||
import org.jooq.ScopedConverter;
|
||||
|
||||
/**
|
||||
* A converter that doesn't convert anything.
|
||||
*
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
public final class IdentityConverter<T> implements Converter<T, T> {
|
||||
public final class IdentityConverter<T> implements ScopedConverter<T, T> {
|
||||
private final Class<T> type;
|
||||
|
||||
public IdentityConverter(Class<T> type) {
|
||||
@ -52,12 +54,12 @@ public final class IdentityConverter<T> implements Converter<T, T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public final T from(T t) {
|
||||
public final T from(T t, ConverterScope scope) {
|
||||
return t;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final T to(T t) {
|
||||
public final T to(T t, ConverterScope scope) {
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
@ -53,6 +53,7 @@ import org.jooq.Binding;
|
||||
import org.jooq.Check;
|
||||
import org.jooq.Comment;
|
||||
import org.jooq.Converter;
|
||||
import org.jooq.ConverterScope;
|
||||
import org.jooq.DDLExportConfiguration;
|
||||
import org.jooq.DataType;
|
||||
import org.jooq.Domain;
|
||||
@ -628,4 +629,10 @@ public final class Internal {
|
||||
else
|
||||
return 0x7FFFFFF & object.hashCode();
|
||||
}
|
||||
|
||||
private static final ConverterScope CONVERTER_SCOPE = new DefaultConverterScope(CONFIG);
|
||||
|
||||
public static final ConverterScope converterScope() {
|
||||
return CONVERTER_SCOPE;
|
||||
}
|
||||
}
|
||||
|
||||
@ -41,6 +41,7 @@ import java.lang.reflect.Method;
|
||||
|
||||
import jakarta.persistence.AttributeConverter;
|
||||
|
||||
import org.jooq.ConverterScope;
|
||||
import org.jooq.exception.MappingException;
|
||||
import org.jooq.tools.JooqLogger;
|
||||
import org.jooq.tools.reflect.Reflect;
|
||||
@ -58,8 +59,9 @@ import org.jooq.tools.reflect.Reflect;
|
||||
*
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
public final class JPAConverter<T, U> extends AbstractConverter<T, U> {
|
||||
private static final JooqLogger log = JooqLogger.getLogger(JPAConverter.class);
|
||||
public final class JPAConverter<T, U> extends AbstractScopedConverter<T, U> {
|
||||
|
||||
private static final JooqLogger log = JooqLogger.getLogger(JPAConverter.class);
|
||||
|
||||
private final AttributeConverter<U, T> delegate;
|
||||
|
||||
@ -115,12 +117,12 @@ public final class JPAConverter<T, U> extends AbstractConverter<T, U> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public final U from(T t) {
|
||||
public final U from(T t, ConverterScope scope) {
|
||||
return delegate.convertToEntityAttribute(t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final T to(U u) {
|
||||
public final T to(U u, ConverterScope scope) {
|
||||
return delegate.convertToDatabaseColumn(u);
|
||||
}
|
||||
}
|
||||
|
||||
@ -37,11 +37,14 @@
|
||||
*/
|
||||
package org.jooq.impl;
|
||||
|
||||
import static org.jooq.impl.Internal.converterScope;
|
||||
|
||||
import org.jooq.Binding;
|
||||
import org.jooq.Configuration;
|
||||
import org.jooq.Converter;
|
||||
import org.jooq.DataType;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.ScopedConverter;
|
||||
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
@ -96,7 +99,7 @@ final class LegacyConvertedDataType<T, U> extends DefaultDataType<U> {
|
||||
|
||||
// [#3200] Try to convert arbitrary objects to T
|
||||
else
|
||||
return ((Converter<T, U>) getConverter()).from(delegate.convert(object));
|
||||
return ((ScopedConverter<T, U>) getConverter()).from(delegate.convert(object), converterScope());
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
|
||||
@ -38,11 +38,13 @@
|
||||
package org.jooq.impl;
|
||||
|
||||
// ...
|
||||
import static org.jooq.ScopedConverter.scoped;
|
||||
import static org.jooq.conf.ParamType.NAMED;
|
||||
import static org.jooq.impl.Internal.subscriber;
|
||||
import static org.jooq.impl.Tools.EMPTY_PARAM;
|
||||
import static org.jooq.impl.Tools.abstractDMLQuery;
|
||||
import static org.jooq.impl.Tools.abstractResultQuery;
|
||||
import static org.jooq.impl.Tools.converterScope;
|
||||
import static org.jooq.impl.Tools.fields;
|
||||
import static org.jooq.impl.Tools.recordFactory;
|
||||
import static org.jooq.impl.Tools.translate;
|
||||
@ -91,6 +93,7 @@ import org.jooq.Param;
|
||||
import org.jooq.Query;
|
||||
import org.jooq.Record;
|
||||
import org.jooq.SQLDialect;
|
||||
import org.jooq.ScopedConverter;
|
||||
import org.jooq.TransactionalPublishable;
|
||||
import org.jooq.XML;
|
||||
import org.jooq.conf.Settings;
|
||||
@ -1237,7 +1240,7 @@ final class R2DBC {
|
||||
if (converter == null)
|
||||
throw new DataTypeException("Cannot convert from " + o.getClass() + " to " + uType + ". Please report an issue here: https://github.com/jOOQ/jOOQ/issues/new. As a workaround, you can implement a ConverterProvider.");
|
||||
else
|
||||
return converter.from(o);
|
||||
return scoped(converter).from(o, converterScope(c));
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
@ -42,11 +42,11 @@ import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLWarning;
|
||||
import java.time.Instant;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jooq.Configuration;
|
||||
import org.jooq.ConnectionProvider;
|
||||
import org.jooq.ConverterScope;
|
||||
import org.jooq.ExecuteContext;
|
||||
import org.jooq.ExecuteType;
|
||||
import org.jooq.Query;
|
||||
@ -67,6 +67,11 @@ final class SimpleExecuteContext extends AbstractScope implements ExecuteContext
|
||||
super(configuration, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final ConverterScope converterScope() {
|
||||
return Tools.converterScope(configuration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Connection connection() {
|
||||
throw new UnsupportedOperationException("Not implemented");
|
||||
|
||||
@ -42,6 +42,7 @@ import java.time.LocalTime;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.jooq.Converter;
|
||||
import org.jooq.ConverterScope;
|
||||
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
@ -51,19 +52,19 @@ import org.jooq.Converter;
|
||||
* <code>Converter.ofNullable(Time.class, LocalTime.class, Time::toLocalTime, Time::valueOf)</code>.
|
||||
*/
|
||||
@Deprecated
|
||||
public final class TimeToLocalTimeConverter extends AbstractConverter<Time, LocalTime> {
|
||||
public final class TimeToLocalTimeConverter extends AbstractScopedConverter<Time, LocalTime> {
|
||||
|
||||
public TimeToLocalTimeConverter() {
|
||||
super(Time.class, LocalTime.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final LocalTime from(Time t) {
|
||||
public final LocalTime from(Time t, ConverterScope scope) {
|
||||
return t == null ? null : t.toLocalTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Time to(LocalTime u) {
|
||||
public final Time to(LocalTime u, ConverterScope scope) {
|
||||
return u == null ? null : Time.valueOf(u);
|
||||
}
|
||||
}
|
||||
|
||||
@ -39,23 +39,26 @@ package org.jooq.impl;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
|
||||
import org.jooq.ConverterScope;
|
||||
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
final class TimestampToJavaUtilDateConverter extends AbstractConverter<Timestamp, java.util.Date> {
|
||||
static final TimestampToJavaUtilDateConverter INSTANCE = new TimestampToJavaUtilDateConverter();
|
||||
final class TimestampToJavaUtilDateConverter extends AbstractScopedConverter<Timestamp, java.util.Date> {
|
||||
|
||||
static final TimestampToJavaUtilDateConverter INSTANCE = new TimestampToJavaUtilDateConverter();
|
||||
|
||||
private TimestampToJavaUtilDateConverter () {
|
||||
super(Timestamp.class, java.util.Date.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final java.util.Date from(Timestamp t) {
|
||||
public final java.util.Date from(Timestamp t, ConverterScope scope) {
|
||||
return t == null ? null : new java.util.Date(t.getTime());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Timestamp to(java.util.Date u) {
|
||||
public final Timestamp to(java.util.Date u, ConverterScope scope) {
|
||||
return u == null ? null : new Timestamp(u.getTime());
|
||||
}
|
||||
}
|
||||
@ -42,6 +42,7 @@ import java.time.LocalDateTime;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.jooq.Converter;
|
||||
import org.jooq.ConverterScope;
|
||||
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
@ -51,19 +52,19 @@ import org.jooq.Converter;
|
||||
* <code>Converter.ofNullable(Timestamp.class, LocalDateTime.class, Timestamp::toLocalDateTime, Timestamp::valueOf)</code>.
|
||||
*/
|
||||
@Deprecated
|
||||
public final class TimestampToLocalDateTimeConverter extends AbstractConverter<Timestamp, LocalDateTime> {
|
||||
public final class TimestampToLocalDateTimeConverter extends AbstractScopedConverter<Timestamp, LocalDateTime> {
|
||||
|
||||
public TimestampToLocalDateTimeConverter() {
|
||||
super(Timestamp.class, LocalDateTime.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final LocalDateTime from(Timestamp t) {
|
||||
public final LocalDateTime from(Timestamp t, ConverterScope scope) {
|
||||
return t == null ? null : t.toLocalDateTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Timestamp to(LocalDateTime u) {
|
||||
public final Timestamp to(LocalDateTime u, ConverterScope scope) {
|
||||
return u == null ? null : Timestamp.valueOf(u);
|
||||
}
|
||||
}
|
||||
|
||||
@ -75,6 +75,7 @@ import static org.jooq.SQLDialect.SQLITE;
|
||||
// ...
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.YUGABYTEDB;
|
||||
import static org.jooq.ScopedConverter.scoped;
|
||||
import static org.jooq.conf.BackslashEscaping.DEFAULT;
|
||||
import static org.jooq.conf.BackslashEscaping.ON;
|
||||
import static org.jooq.conf.ParamType.INLINED;
|
||||
@ -219,7 +220,6 @@ import java.util.AbstractMap.SimpleImmutableEntry;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumMap;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
@ -263,6 +263,7 @@ import org.jooq.Configuration;
|
||||
import org.jooq.Context;
|
||||
import org.jooq.Converter;
|
||||
import org.jooq.ConverterProvider;
|
||||
import org.jooq.ConverterScope;
|
||||
import org.jooq.Converters;
|
||||
import org.jooq.Cursor;
|
||||
import org.jooq.DSLContext;
|
||||
@ -294,7 +295,6 @@ import org.jooq.Record1;
|
||||
import org.jooq.RecordQualifier;
|
||||
import org.jooq.RenderContext;
|
||||
import org.jooq.RenderContext.CastMode;
|
||||
// ...
|
||||
import org.jooq.Result;
|
||||
import org.jooq.ResultOrRows;
|
||||
import org.jooq.ResultQuery;
|
||||
@ -302,8 +302,8 @@ import org.jooq.Results;
|
||||
import org.jooq.Row;
|
||||
import org.jooq.SQLDialect;
|
||||
import org.jooq.Schema;
|
||||
import org.jooq.SchemaMapping;
|
||||
import org.jooq.Scope;
|
||||
import org.jooq.ScopedConverter;
|
||||
import org.jooq.Select;
|
||||
import org.jooq.SelectFieldOrAsterisk;
|
||||
import org.jooq.SortField;
|
||||
@ -311,7 +311,6 @@ import org.jooq.Source;
|
||||
import org.jooq.Table;
|
||||
import org.jooq.TableField;
|
||||
import org.jooq.TableRecord;
|
||||
// ...
|
||||
import org.jooq.UDT;
|
||||
import org.jooq.UpdatableRecord;
|
||||
import org.jooq.WindowSpecification;
|
||||
@ -334,7 +333,6 @@ import org.jooq.exception.MappingException;
|
||||
import org.jooq.exception.NoDataFoundException;
|
||||
import org.jooq.exception.TemplatingException;
|
||||
import org.jooq.exception.TooManyRowsException;
|
||||
import org.jooq.impl.QOM.GenerationOption;
|
||||
import org.jooq.impl.QOM.UEmpty;
|
||||
import org.jooq.impl.ResultsImpl.ResultOrRowsImpl;
|
||||
import org.jooq.tools.Ints;
|
||||
@ -1466,7 +1464,7 @@ final class Tools {
|
||||
* Get a converter from a {@link ConverterProvider} or <code>null</code> if
|
||||
* no converter could be provided.
|
||||
*/
|
||||
static final <T, U> Converter<T, U> converter(Configuration configuration, T instance, Class<T> tType, Class<U> uType) {
|
||||
static final <T, U> ScopedConverter<T, U> converter(Configuration configuration, T instance, Class<T> tType, Class<U> uType) {
|
||||
Converter<T, U> result = configuration(configuration).converterProvider().provide(tType, uType);
|
||||
|
||||
if (result == null)
|
||||
@ -1479,15 +1477,15 @@ final class Tools {
|
||||
if (result == null && tType == Converters.UnknownType.class)
|
||||
result = converter(configuration, instance, (Class<T>) (instance == null ? Object.class : instance.getClass()), uType);
|
||||
|
||||
return result;
|
||||
return result == null ? null : scoped(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a converter from a {@link ConverterProvider} or <code>null</code> if
|
||||
* no converter could be provided.
|
||||
*/
|
||||
static final <T, U> Converter<T, U> converterOrFail(Configuration configuration, T instance, Class<T> tType, Class<U> uType) {
|
||||
Converter<T, U> result = converter(configuration, instance, tType, uType);
|
||||
static final <T, U> ScopedConverter<T, U> converterOrFail(Configuration configuration, T instance, Class<T> tType, Class<U> uType) {
|
||||
ScopedConverter<T, U> result = converter(configuration, instance, tType, uType);
|
||||
|
||||
if (result == null)
|
||||
throw new DataTypeException("No Converter found for types " + tType.getName() + " and " + uType.getName());
|
||||
@ -1498,7 +1496,7 @@ final class Tools {
|
||||
/**
|
||||
* Get a converter from a {@link ConverterProvider}.
|
||||
*/
|
||||
static final <T, U> Converter<T, U> converterOrFail(Attachable attachable, T instance, Class<T> tType, Class<U> uType) {
|
||||
static final <T, U> ScopedConverter<T, U> converterOrFail(Attachable attachable, T instance, Class<T> tType, Class<U> uType) {
|
||||
return converterOrFail(configuration(attachable), instance, tType, uType);
|
||||
}
|
||||
|
||||
@ -7105,4 +7103,12 @@ final class Tools {
|
||||
|
||||
return dataType;
|
||||
}
|
||||
|
||||
static final ConverterScope converterScope(Attachable attachable) {
|
||||
return new DefaultConverterScope(configuration(attachable));
|
||||
}
|
||||
|
||||
static final ConverterScope converterScope(Configuration configuration) {
|
||||
return new DefaultConverterScope(configuration(configuration));
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,6 +40,7 @@ package org.jooq.impl;
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
|
||||
import org.jooq.ConverterScope;
|
||||
import org.jooq.XML;
|
||||
|
||||
import jakarta.xml.bind.JAXB;
|
||||
@ -56,21 +57,21 @@ public class XMLtoJAXBConverter<U> extends AbstractConverter<XML, U> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public U from(XML databaseObject) {
|
||||
if (databaseObject == null)
|
||||
public U from(XML t) {
|
||||
if (t == null)
|
||||
return null;
|
||||
else
|
||||
return JAXB.unmarshal(new StringReader(databaseObject.data()), toType());
|
||||
return JAXB.unmarshal(new StringReader(t.data()), toType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public XML to(U userObject) {
|
||||
if (userObject == null) {
|
||||
public XML to(U u) {
|
||||
if (u == null) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
StringWriter w = new StringWriter();
|
||||
JAXB.marshal(userObject, w);
|
||||
JAXB.marshal(u, w);
|
||||
return XML.xml(w.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,7 +40,9 @@ package org.jooq.tools;
|
||||
import static java.time.temporal.ChronoField.INSTANT_SECONDS;
|
||||
import static java.time.temporal.ChronoField.MILLI_OF_DAY;
|
||||
import static java.time.temporal.ChronoField.MILLI_OF_SECOND;
|
||||
import static org.jooq.ScopedConverter.scoped;
|
||||
import static org.jooq.impl.Internal.arrayType;
|
||||
import static org.jooq.impl.Internal.converterScope;
|
||||
import static org.jooq.tools.reflect.Reflect.accessible;
|
||||
import static org.jooq.tools.reflect.Reflect.wrapper;
|
||||
import static org.jooq.types.Unsigned.ubyte;
|
||||
@ -91,6 +93,7 @@ import jakarta.xml.bind.JAXB;
|
||||
// ...
|
||||
import org.jooq.Converter;
|
||||
import org.jooq.ConverterProvider;
|
||||
import org.jooq.ConverterScope;
|
||||
import org.jooq.DataType;
|
||||
import org.jooq.EnumType;
|
||||
import org.jooq.Field;
|
||||
@ -100,9 +103,13 @@ import org.jooq.QualifiedRecord;
|
||||
import org.jooq.Record;
|
||||
import org.jooq.Result;
|
||||
import org.jooq.SQLDialect;
|
||||
import org.jooq.ScopedConverter;
|
||||
import org.jooq.XML;
|
||||
import org.jooq.exception.DataTypeException;
|
||||
import org.jooq.impl.AbstractConverter;
|
||||
import org.jooq.impl.AbstractScopedConverter;
|
||||
import org.jooq.impl.IdentityConverter;
|
||||
import org.jooq.impl.Internal;
|
||||
import org.jooq.tools.jdbc.MockArray;
|
||||
import org.jooq.tools.jdbc.MockResultSet;
|
||||
import org.jooq.tools.reflect.Reflect;
|
||||
@ -370,7 +377,7 @@ public final class Convert {
|
||||
}
|
||||
|
||||
public static final <U> U[] convertCollection(Collection from, Class<? extends U[]> to){
|
||||
return new ConvertAll<U[]>(to).from(from);
|
||||
return new ConvertAll<U[]>(to).from(from, converterScope());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -400,10 +407,10 @@ public final class Convert {
|
||||
Class<T> fromType = converter.fromType();
|
||||
|
||||
if (fromType == Object.class)
|
||||
return converter.from((T) from);
|
||||
return scoped(converter).from((T) from, converterScope());
|
||||
|
||||
ConvertAll<T> convertAll = new ConvertAll<>(fromType);
|
||||
return converter.from(convertAll.from(from));
|
||||
return scoped(converter).from(convertAll.from(from, converterScope()), converterScope());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -514,7 +521,7 @@ public final class Convert {
|
||||
List<U> result = new ArrayList<>(collection.size());
|
||||
|
||||
for (Object o : collection)
|
||||
result.add(convert(all.from(o), converter));
|
||||
result.add(convert(all.from(o, converterScope()), converter));
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -527,17 +534,20 @@ public final class Convert {
|
||||
/**
|
||||
* The converter to convert them all.
|
||||
*/
|
||||
private static class ConvertAll<U> implements Converter<Object, U> {
|
||||
private static final class ConvertAll<U> extends AbstractScopedConverter<Object, U> {
|
||||
|
||||
private final Class<? extends U> toClass;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
ConvertAll(Class<? extends U> toClass) {
|
||||
super(Object.class, (Class<U>) toClass);
|
||||
|
||||
this.toClass = toClass;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
@Override
|
||||
public U from(Object from) {
|
||||
public U from(Object from, ConverterScope scope) {
|
||||
if (from == null) {
|
||||
|
||||
// [#936] If types are converted to primitives, the result must not
|
||||
@ -1239,22 +1249,10 @@ public final class Convert {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object to(U to) {
|
||||
public Object to(U to, ConverterScope scope) {
|
||||
return to;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Object> fromType() {
|
||||
return Object.class;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Class<U> toType() {
|
||||
return (Class<U>) toClass;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a long timestamp (millis) to any date type.
|
||||
*/
|
||||
|
||||
@ -38,6 +38,8 @@
|
||||
package org.jooq.tools.jdbc;
|
||||
|
||||
import static org.jooq.SQLDialect.DEFAULT;
|
||||
import static org.jooq.ScopedConverter.scoped;
|
||||
import static org.jooq.impl.Internal.converterScope;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
@ -71,8 +73,10 @@ import org.jooq.Converters;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.Record;
|
||||
import org.jooq.Result;
|
||||
import org.jooq.ScopedConverter;
|
||||
import org.jooq.impl.DSL;
|
||||
import org.jooq.impl.DefaultConfiguration;
|
||||
import org.jooq.impl.Internal;
|
||||
import org.jooq.tools.StringUtils;
|
||||
|
||||
/**
|
||||
@ -457,7 +461,7 @@ public class MockResultSet extends JDBC41ResultSet implements ResultSet, Seriali
|
||||
.converterProvider()
|
||||
.provide(value == null ? Object.class : (Class<Object>) value.getClass(), type);
|
||||
|
||||
T converted = converter == null ? null : converter.from(value);
|
||||
T converted = converter == null ? null : scoped(converter).from(value, converterScope());
|
||||
wasNull = (converted == null);
|
||||
return converted;
|
||||
}
|
||||
|
||||
@ -38,6 +38,7 @@
|
||||
package org.jooq.util.postgres;
|
||||
|
||||
import static java.lang.Integer.toOctalString;
|
||||
import static org.jooq.impl.Internal.converterScope;
|
||||
import static org.jooq.tools.StringUtils.leftPad;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
@ -52,6 +53,7 @@ import java.util.List;
|
||||
import org.jooq.Converter;
|
||||
import org.jooq.EnumType;
|
||||
import org.jooq.Record;
|
||||
import org.jooq.ScopedConverter;
|
||||
import org.jooq.exception.DataTypeException;
|
||||
import org.jooq.tools.StringUtils;
|
||||
import org.jooq.types.DayToSecond;
|
||||
@ -529,7 +531,7 @@ public class PostgresUtils {
|
||||
String separator = "";
|
||||
for (int i = 0; i < r.size(); i++) {
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
Object a = ((Converter) r.field(i).getConverter()).to(r.get(i));
|
||||
Object a = ((ScopedConverter) r.field(i).getConverter()).to(r.get(i), converterScope());
|
||||
sb.append(separator);
|
||||
|
||||
// [#753] null must not be set as a literal
|
||||
|
||||
Loading…
Reference in New Issue
Block a user