diff --git a/jOOQ-examples/jOOQ-jpa-example/pom.xml b/jOOQ-examples/jOOQ-jpa-example/pom.xml
index 8b93b8c932..bb2379a4cc 100644
--- a/jOOQ-examples/jOOQ-jpa-example/pom.xml
+++ b/jOOQ-examples/jOOQ-jpa-example/pom.xml
@@ -138,13 +138,6 @@
.*
-
-
- java.time.Year
- org.jooq.Converter.of(Integer.class, Year.class, new org.jooq.example.jpa.converters.YearConverter()::convertToEntityAttribute, new org.jooq.example.jpa.converters.YearConverter()::convertToDatabaseColumn)
- RELEASE_YEAR
-
-
diff --git a/jOOQ-examples/jOOQ-jpa-example/src/main/java/org/jooq/example/jpa/jooq/Public.java b/jOOQ-examples/jOOQ-jpa-example/src/main/java/org/jooq/example/jpa/jooq/Public.java
index ab283f442f..6b8181e2cd 100644
--- a/jOOQ-examples/jOOQ-jpa-example/src/main/java/org/jooq/example/jpa/jooq/Public.java
+++ b/jOOQ-examples/jOOQ-jpa-example/src/main/java/org/jooq/example/jpa/jooq/Public.java
@@ -33,7 +33,7 @@ import org.jooq.impl.SchemaImpl;
@SuppressWarnings({ "all", "unchecked", "rawtypes" })
public class Public extends SchemaImpl {
- private static final long serialVersionUID = 1252977499;
+ private static final long serialVersionUID = 897816362;
/**
* The reference instance of PUBLIC
@@ -85,9 +85,9 @@ public class Public extends SchemaImpl {
private final List> getSequences0() {
return Arrays.>asList(
- Sequences.SYSTEM_SEQUENCE_5B4EAFE5_365F_441D_BC0D_72B0BA27E6CC,
- Sequences.SYSTEM_SEQUENCE_65506620_5C73_4217_9913_7AB008A3F158,
- Sequences.SYSTEM_SEQUENCE_805FDF72_C4BB_4AA3_86DB_0EA4233F1A7C);
+ Sequences.SYSTEM_SEQUENCE_89CD2855_22EA_4F63_95A8_18A79F6EC782,
+ Sequences.SYSTEM_SEQUENCE_BE504C6E_CD12_493D_BEC3_FE5DEDA7FE1A,
+ Sequences.SYSTEM_SEQUENCE_C6201643_1CF6_4072_8443_E47AC449BE9D);
}
@Override
diff --git a/jOOQ-examples/jOOQ-jpa-example/src/main/java/org/jooq/example/jpa/jooq/Sequences.java b/jOOQ-examples/jOOQ-jpa-example/src/main/java/org/jooq/example/jpa/jooq/Sequences.java
index 1cd091ec9b..7b36b13bec 100644
--- a/jOOQ-examples/jOOQ-jpa-example/src/main/java/org/jooq/example/jpa/jooq/Sequences.java
+++ b/jOOQ-examples/jOOQ-jpa-example/src/main/java/org/jooq/example/jpa/jooq/Sequences.java
@@ -24,17 +24,17 @@ import org.jooq.impl.SequenceImpl;
public class Sequences {
/**
- * The sequence PUBLIC.SYSTEM_SEQUENCE_5B4EAFE5_365F_441D_BC0D_72B0BA27E6CC
+ * The sequence PUBLIC.SYSTEM_SEQUENCE_89CD2855_22EA_4F63_95A8_18A79F6EC782
*/
- public static final Sequence SYSTEM_SEQUENCE_5B4EAFE5_365F_441D_BC0D_72B0BA27E6CC = new SequenceImpl("SYSTEM_SEQUENCE_5B4EAFE5_365F_441D_BC0D_72B0BA27E6CC", Public.PUBLIC, org.jooq.impl.SQLDataType.BIGINT);
+ public static final Sequence SYSTEM_SEQUENCE_89CD2855_22EA_4F63_95A8_18A79F6EC782 = new SequenceImpl("SYSTEM_SEQUENCE_89CD2855_22EA_4F63_95A8_18A79F6EC782", Public.PUBLIC, org.jooq.impl.SQLDataType.BIGINT);
/**
- * The sequence PUBLIC.SYSTEM_SEQUENCE_65506620_5C73_4217_9913_7AB008A3F158
+ * The sequence PUBLIC.SYSTEM_SEQUENCE_BE504C6E_CD12_493D_BEC3_FE5DEDA7FE1A
*/
- public static final Sequence SYSTEM_SEQUENCE_65506620_5C73_4217_9913_7AB008A3F158 = new SequenceImpl("SYSTEM_SEQUENCE_65506620_5C73_4217_9913_7AB008A3F158", Public.PUBLIC, org.jooq.impl.SQLDataType.BIGINT);
+ public static final Sequence SYSTEM_SEQUENCE_BE504C6E_CD12_493D_BEC3_FE5DEDA7FE1A = new SequenceImpl("SYSTEM_SEQUENCE_BE504C6E_CD12_493D_BEC3_FE5DEDA7FE1A", Public.PUBLIC, org.jooq.impl.SQLDataType.BIGINT);
/**
- * The sequence PUBLIC.SYSTEM_SEQUENCE_805FDF72_C4BB_4AA3_86DB_0EA4233F1A7C
+ * The sequence PUBLIC.SYSTEM_SEQUENCE_C6201643_1CF6_4072_8443_E47AC449BE9D
*/
- public static final Sequence SYSTEM_SEQUENCE_805FDF72_C4BB_4AA3_86DB_0EA4233F1A7C = new SequenceImpl("SYSTEM_SEQUENCE_805FDF72_C4BB_4AA3_86DB_0EA4233F1A7C", Public.PUBLIC, org.jooq.impl.SQLDataType.BIGINT);
+ public static final Sequence SYSTEM_SEQUENCE_C6201643_1CF6_4072_8443_E47AC449BE9D = new SequenceImpl("SYSTEM_SEQUENCE_C6201643_1CF6_4072_8443_E47AC449BE9D", Public.PUBLIC, org.jooq.impl.SQLDataType.BIGINT);
}
diff --git a/jOOQ-examples/jOOQ-jpa-example/src/main/java/org/jooq/example/jpa/jooq/tables/Film.java b/jOOQ-examples/jOOQ-jpa-example/src/main/java/org/jooq/example/jpa/jooq/tables/Film.java
index c4e59ec296..e7df2c63cb 100644
--- a/jOOQ-examples/jOOQ-jpa-example/src/main/java/org/jooq/example/jpa/jooq/tables/Film.java
+++ b/jOOQ-examples/jOOQ-jpa-example/src/main/java/org/jooq/example/jpa/jooq/tables/Film.java
@@ -40,7 +40,7 @@ import org.jooq.impl.TableImpl;
@SuppressWarnings({ "all", "unchecked", "rawtypes" })
public class Film extends TableImpl {
- private static final long serialVersionUID = 1113845742;
+ private static final long serialVersionUID = 1030256935;
/**
* The reference instance of PUBLIC.FILM
@@ -68,7 +68,7 @@ public class Film extends TableImpl {
/**
* The column PUBLIC.FILM.RELEASE_YEAR.
*/
- public final TableField RELEASE_YEAR = createField("RELEASE_YEAR", org.jooq.impl.SQLDataType.INTEGER, this, "", org.jooq.Converter.of(Integer.class, Year.class, new org.jooq.example.jpa.converters.YearConverter()::convertToEntityAttribute, new org.jooq.example.jpa.converters.YearConverter()::convertToDatabaseColumn));
+ public final TableField RELEASE_YEAR = createField("RELEASE_YEAR", org.jooq.impl.SQLDataType.INTEGER, this, "", new org.jooq.impl.JPAConverter(org.jooq.example.jpa.converters.YearConverter.class));
/**
* The column PUBLIC.FILM.TITLE.
diff --git a/jOOQ-manual/src/main/resources/org/jooq/web/manual-3.10.xml b/jOOQ-manual/src/main/resources/org/jooq/web/manual-3.10.xml
index eb9b034b41..e5e8deee13 100644
--- a/jOOQ-manual/src/main/resources/org/jooq/web/manual-3.10.xml
+++ b/jOOQ-manual/src/main/resources/org/jooq/web/manual-3.10.xml
@@ -17673,6 +17673,14 @@ public class Book {
packages
com.example.entities
+
+
+
+ use-attribute-converters
+ true
+
]]>
diff --git a/jOOQ-meta-extensions/src/main/java/org/jooq/util/jpa/JPADatabase.java b/jOOQ-meta-extensions/src/main/java/org/jooq/util/jpa/JPADatabase.java
index 25ae3ff4ce..a514b15449 100644
--- a/jOOQ-meta-extensions/src/main/java/org/jooq/util/jpa/JPADatabase.java
+++ b/jOOQ-meta-extensions/src/main/java/org/jooq/util/jpa/JPADatabase.java
@@ -37,22 +37,30 @@ package org.jooq.util.jpa;
import static org.jooq.tools.StringUtils.defaultIfBlank;
import static org.jooq.tools.StringUtils.isBlank;
+import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.List;
+import java.util.Map.Entry;
+import javax.persistence.AttributeConverter;
import javax.persistence.Entity;
import org.jooq.DSLContext;
+import org.jooq.Name;
+import org.jooq.SQLDialect;
import org.jooq.exception.DataAccessException;
import org.jooq.impl.DSL;
+import org.jooq.impl.JPAConverter;
import org.jooq.tools.JooqLogger;
import org.jooq.util.SchemaDefinition;
import org.jooq.util.h2.H2Database;
+import org.jooq.util.jaxb.ForcedType;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
@@ -84,11 +92,11 @@ import org.springframework.core.type.filter.AnnotationTypeFilter;
*/
public class JPADatabase extends H2Database {
- private static final JooqLogger log = JooqLogger.getLogger(JPADatabase.class);
+ static final String HIBERNATE_DIALECT = SQLDialect.H2.thirdParty().hibernateDialect();
+ static final JooqLogger log = JooqLogger.getLogger(JPADatabase.class);
- private Connection connection;
+ private Connection connection;
- @SuppressWarnings("serial")
@Override
protected DSLContext create0() {
if (connection == null) {
@@ -99,38 +107,19 @@ public class JPADatabase extends H2Database {
log.warn("No packages defined", "It is highly recommended that you provide explicit packages to scan");
}
+ boolean useAttributeConverters = Boolean.valueOf(getProperties().getProperty("use-attribute-converters", "true"));
+
try {
connection = DriverManager.getConnection("jdbc:h2:mem:jooq-meta-extensions", "sa", "");
MetadataSources metadata = new MetadataSources(
new StandardServiceRegistryBuilder()
- .applySetting("hibernate.dialect", "org.hibernate.dialect.H2Dialect")
+ .applySetting("hibernate.dialect", HIBERNATE_DIALECT)
.applySetting("javax.persistence.schema-generation-connection", connection)
.applySetting("javax.persistence.create-database-schemas", true)
// [#5607] JPADatabase causes warnings - This prevents them
- .applySetting(AvailableSettings.CONNECTION_PROVIDER, new ConnectionProvider() {
- @SuppressWarnings("rawtypes")
- @Override
- public boolean isUnwrappableAs(Class unwrapType) {
- return false;
- }
- @Override
- public T unwrap(Class unwrapType) {
- return null;
- }
- @Override
- public Connection getConnection() {
- return connection;
- }
- @Override
- public void closeConnection(Connection conn) throws SQLException {}
-
- @Override
- public boolean supportsAggressiveRelease() {
- return true;
- }
- })
+ .applySetting(AvailableSettings.CONNECTION_PROVIDER, connectionProvider())
.build()
);
@@ -154,6 +143,9 @@ public class JPADatabase extends H2Database {
// Hibernate 5.2 broke 5.0 API again. Here's how to do this now:
SchemaExport export = new SchemaExport();
export.create(EnumSet.of(TargetType.DATABASE), metadata.buildMetadata());
+
+ if (useAttributeConverters)
+ loadAttributeConverters(metadata.getAnnotatedClasses());
}
catch (Exception e) {
throw new DataAccessException("Error while exporting schema", e);
@@ -163,6 +155,71 @@ public class JPADatabase extends H2Database {
return DSL.using(connection);
}
+ @SuppressWarnings("serial")
+ ConnectionProvider connectionProvider() {
+ return new ConnectionProvider() {
+ @SuppressWarnings("rawtypes")
+ @Override
+ public boolean isUnwrappableAs(Class unwrapType) {
+ return false;
+ }
+ @Override
+ public T unwrap(Class unwrapType) {
+ return null;
+ }
+ @Override
+ public Connection getConnection() {
+ return connection;
+ }
+ @Override
+ public void closeConnection(Connection conn) {}
+
+ @Override
+ public boolean supportsAggressiveRelease() {
+ return true;
+ }
+ };
+ }
+
+ private final void loadAttributeConverters(Collection extends Class>> classes) {
+ try {
+ AttributeConverterExtractor extractor = new AttributeConverterExtractor(this, classes);
+
+ attributesLoop:
+ for (Entry> entry : extractor.extract().entrySet()) {
+ Class> convertToEntityAttribute = null;
+
+ for (Method method : entry.getValue().getClass().getMethods())
+ if ("convertToEntityAttribute".equals(method.getName()))
+ convertToEntityAttribute = method.getReturnType();
+
+ if (convertToEntityAttribute == null) {
+ log.info("AttributeConverter", "Cannot use AttributeConverter: " + entry.getValue().getClass().getName());
+ continue attributesLoop;
+ }
+
+ // Tables can be fully or partially or not at all qualified. Let's just accept any prefix
+ // to the available qualification
+ String regex = "(.*?\\.)?" + entry.getKey().unquotedName().toString().replace(".", "\\.");
+ ForcedType forcedType = new ForcedType()
+ .withExpression("(?i:" + regex + ")")
+ .withUserType(convertToEntityAttribute.getName())
+ .withConverter(String.format("new %s(%s.class)",
+ JPAConverter.class.getName(),
+ entry.getValue().getClass().getName()
+ ));
+
+ log.info("AttributeConverter", "Configuring JPA AttributeConverter: " + toString(forcedType));
+ getConfiguredForcedTypes().add(forcedType);
+ }
+ }
+
+ // AttributeConverter is part of JPA 2.1. Older JPA providers may not have this type, yet
+ catch (NoClassDefFoundError e) {
+ log.info("AttributeConverter", "Cannot load AttributeConverters: " + e.getMessage());
+ }
+ }
+
@Override
protected List getSchemata0() throws SQLException {
List result = new ArrayList(super.getSchemata0());
diff --git a/jOOQ-meta/src/main/java/org/jooq/util/AbstractDatabase.java b/jOOQ-meta/src/main/java/org/jooq/util/AbstractDatabase.java
index d4251d2f69..0877492abe 100644
--- a/jOOQ-meta/src/main/java/org/jooq/util/AbstractDatabase.java
+++ b/jOOQ-meta/src/main/java/org/jooq/util/AbstractDatabase.java
@@ -997,7 +997,7 @@ public abstract class AbstractDatabase implements Database {
}
@SuppressWarnings({ "unchecked", "rawtypes" })
- static final String toString(final Object object) {
+ protected static final String toString(final Object object) {
final StringWriter writer = new StringWriter();
try {