From a47284df8dad3678bc0c0613299067168cbceadb Mon Sep 17 00:00:00 2001 From: Lukas Eder Date: Sun, 4 Mar 2012 15:55:00 +0000 Subject: [PATCH] [#650] Add a data type registry "org.jooq.impl.DataTypes" for cleaner DataType referencing [#1217] Add EnumConverter as a base type for custom enum converters --- .../org/jooq/test/_/MyEnumNumericMapper.java | 5 + .../org/jooq/test/_/MyEnumStringMapper.java | 7 +- .../jooq/test/_/testcases/DataTypeTests.java | 1 + jOOQ/src/main/java/org/jooq/Converter.java | 10 +- .../main/java/org/jooq/impl/DataTypes.java | 132 ++++++++++++++++++ .../java/org/jooq/impl/EnumConverter.java | 121 ++++++++++++++++ .../src/main/java/org/jooq/tools/Convert.java | 6 + 7 files changed, 277 insertions(+), 5 deletions(-) create mode 100644 jOOQ/src/main/java/org/jooq/impl/DataTypes.java create mode 100644 jOOQ/src/main/java/org/jooq/impl/EnumConverter.java diff --git a/jOOQ-test/src/org/jooq/test/_/MyEnumNumericMapper.java b/jOOQ-test/src/org/jooq/test/_/MyEnumNumericMapper.java index f605b3b917..032d98987f 100644 --- a/jOOQ-test/src/org/jooq/test/_/MyEnumNumericMapper.java +++ b/jOOQ-test/src/org/jooq/test/_/MyEnumNumericMapper.java @@ -40,6 +40,11 @@ import org.jooq.Converter; public class MyEnumNumericMapper implements Converter { + /** + * Generated UID + */ + private static final long serialVersionUID = -4252074829213730476L; + public static final MyEnumNumericMapper INSTANCE = new MyEnumNumericMapper(); @Override diff --git a/jOOQ-test/src/org/jooq/test/_/MyEnumStringMapper.java b/jOOQ-test/src/org/jooq/test/_/MyEnumStringMapper.java index 0aaa1b8264..901d12e341 100644 --- a/jOOQ-test/src/org/jooq/test/_/MyEnumStringMapper.java +++ b/jOOQ-test/src/org/jooq/test/_/MyEnumStringMapper.java @@ -39,7 +39,12 @@ import org.jooq.Converter; public class MyEnumStringMapper implements Converter { - public static final MyEnumStringMapper INSTANCE = new MyEnumStringMapper(); + /** + * Generated UID + */ + private static final long serialVersionUID = -4252074829213730476L; + + public static final MyEnumStringMapper INSTANCE = new MyEnumStringMapper(); @Override public MyEnum from(String t) { diff --git a/jOOQ-test/src/org/jooq/test/_/testcases/DataTypeTests.java b/jOOQ-test/src/org/jooq/test/_/testcases/DataTypeTests.java index dfcbe482ec..1a54b3c979 100644 --- a/jOOQ-test/src/org/jooq/test/_/testcases/DataTypeTests.java +++ b/jOOQ-test/src/org/jooq/test/_/testcases/DataTypeTests.java @@ -274,6 +274,7 @@ extends BaseTest converter = new Converter() { diff --git a/jOOQ/src/main/java/org/jooq/Converter.java b/jOOQ/src/main/java/org/jooq/Converter.java index 5c3f2a454f..08823529b9 100644 --- a/jOOQ/src/main/java/org/jooq/Converter.java +++ b/jOOQ/src/main/java/org/jooq/Converter.java @@ -35,6 +35,8 @@ */ package org.jooq; +import java.io.Serializable; + import org.jooq.impl.SQLDataType; /** @@ -49,17 +51,17 @@ import org.jooq.impl.SQLDataType; *
  • to store user types converting them to database types "TO" the database. * Hence, {@link #toType()} is the user-defined type
  • * - * + * * @author Lukas Eder * @param The database type - i.e. any type available from * {@link SQLDataType} * @param The user type */ -public interface Converter { +public interface Converter extends Serializable { /** * Convert a database object to a user object - * + * * @param databaseObject The database object * @return The user object */ @@ -67,7 +69,7 @@ public interface Converter { /** * Convert a user object to a database object - * + * * @param userObject The user object * @return The database object */ diff --git a/jOOQ/src/main/java/org/jooq/impl/DataTypes.java b/jOOQ/src/main/java/org/jooq/impl/DataTypes.java new file mode 100644 index 0000000000..7257f6e071 --- /dev/null +++ b/jOOQ/src/main/java/org/jooq/impl/DataTypes.java @@ -0,0 +1,132 @@ +/** + * Copyright (c) 2009-2012, Lukas Eder, lukas.eder@gmail.com + * All rights reserved. + * + * This software is licensed to you under the Apache License, Version 2.0 + * (the "License"); You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name "jOOQ" nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package org.jooq.impl; + +import java.util.HashMap; +import java.util.Map; + +import org.jooq.Converter; +import org.jooq.DataType; +import org.jooq.Field; +import org.jooq.Record; +import org.jooq.Result; +import org.jooq.exception.DataTypeException; + +/** + * A central {@link DataType} registry + * + * @author Lukas Eder + */ +public final class DataTypes { + + private static final Object INIT_LOCK = new Object(); + private static final Map, Converter> CONVERTERS = new HashMap, Converter>(); + + // ------------------------------------------------------------------------ + // XXX: Public API used for initialisation from generated artefacts + // ------------------------------------------------------------------------ + + /** + * Register a Converter for a custom type + *

    + * This registers a {@link Converter} for a custom type. This converter will + * be used by jOOQ to recognise custom types and to transform them back to + * well-known database types (as defined in {@link Converter#fromType()}) in + * rendering and binding steps + *

    + * A custom type can be registered only once. Duplicate registrations will + * be ignored + *

    + * The converter class must provide a default constructor. + * + * @see #registerConverter(Class, Converter) + */ + public static final synchronized void registerConverter(Class customType, + Class> converter) { + + try { + converter.getConstructor().setAccessible(true); + registerConverter(customType, converter.newInstance()); + } + catch (Exception e) { + throw new DataTypeException("Cannot register converter", e); + } + } + + /** + * Register a Converter for a custom type + *

    + * This registers a {@link Converter} for a custom type. This converter will + * be used by jOOQ to recognise custom types and to transform them back to + * well-known database types (as defined in {@link Converter#fromType()}) in + * rendering and binding steps + *

    + * A custom type can be registered only once. Duplicate registrations will + * be ignored + */ + public static final synchronized void registerConverter(Class customType, Converter converter) { + + // A converter can be registered only once + if (!CONVERTERS.containsKey(customType)) { + CONVERTERS.put(customType, converter); + } + } + + /** + * Register a Converter for a field + *

    + * This registers a converter for a specific field in your generated schema. + * This converter will be used by jOOQ to convert database types to your own + * custom types and deliver those types in {@link Record} and {@link Result} + */ + public static final synchronized void registerConverter(Field field, Converter converter) { + + } + + // ------------------------------------------------------------------------ + // XXX: Internal API + // ------------------------------------------------------------------------ + + @SuppressWarnings("unchecked") + static final Converter converter(Class customType) { + return (Converter) CONVERTERS.get(customType); + } + + /** + * No instances + */ + private DataTypes() {} +} diff --git a/jOOQ/src/main/java/org/jooq/impl/EnumConverter.java b/jOOQ/src/main/java/org/jooq/impl/EnumConverter.java new file mode 100644 index 0000000000..21feacaf7a --- /dev/null +++ b/jOOQ/src/main/java/org/jooq/impl/EnumConverter.java @@ -0,0 +1,121 @@ +/** + * Copyright (c) 2009-2012, Lukas Eder, lukas.eder@gmail.com + * All rights reserved. + * + * This software is licensed to you under the Apache License, Version 2.0 + * (the "License"); You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name "jOOQ" nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package org.jooq.impl; + +import static org.jooq.tools.Convert.convert; + +import java.util.LinkedHashMap; +import java.util.Map; + +import org.jooq.Converter; + +/** + * A base class for enum conversion. + * + * @author Lukas Eder + */ +public class EnumConverter> implements Converter { + + /** + * Generated UID + */ + private static final long serialVersionUID = -6094337837408829491L; + + private final Class fromType; + private final Class toType; + private final Map lookup; + private final EnumType enumType; + + public EnumConverter(Class fromType, Class toType) { + this.fromType = fromType; + this.toType = toType; + this.enumType = Number.class.isAssignableFrom(fromType) ? EnumType.ORDINAL : EnumType.STRING; + + this.lookup = new LinkedHashMap(); + for (U u : toType.getEnumConstants()) { + this.lookup.put(to(u), u); + } + } + + @Override + public final U from(T databaseObject) { + return lookup.get(databaseObject); + } + + /** + * Subclasses may override this method to provide a custom reverse mapping + * implementation + *

    + * {@inheritDoc} + */ + @Override + public T to(U userObject) { + if (enumType == EnumType.ORDINAL) { + return convert(userObject.ordinal(), fromType); + } + else { + return convert(userObject.name(), fromType); + } + } + + @Override + public final Class fromType() { + return fromType; + } + + @Override + public final Class toType() { + return toType; + } + + /** + * The type of the converted Enum. + *

    + * This corresponds to JPA's EnumType + */ + enum EnumType { + + /** + * Ordinal enum type + */ + ORDINAL, + + /** + * String enum type + */ + STRING + } +} diff --git a/jOOQ/src/main/java/org/jooq/tools/Convert.java b/jOOQ/src/main/java/org/jooq/tools/Convert.java index 901b1ae312..a8f0a8b72b 100644 --- a/jOOQ/src/main/java/org/jooq/tools/Convert.java +++ b/jOOQ/src/main/java/org/jooq/tools/Convert.java @@ -310,6 +310,11 @@ public final class Convert { */ private static class ConvertAll implements Converter { + /** + * Generated UID + */ + private static final long serialVersionUID = 2508560107067092501L; + private final Class toClass; ConvertAll(Class toClass) { @@ -465,6 +470,7 @@ public final class Convert { return Object.class; } + @SuppressWarnings("unchecked") @Override public Class toType() { return (Class) toClass;