Add a Dialect report
Also added * H2Dialect#getMinimumSupportedVersion * DerbyDialect#getMinimumSupportedVersion
This commit is contained in:
parent
3ae07666ab
commit
c6389efb1b
|
@ -267,6 +267,33 @@ tasks.register('renderLoggingReport', AsciidoctorTask) { task ->
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.register('renderDialectReport', AsciidoctorTask) { task ->
|
||||||
|
group 'Documentation'
|
||||||
|
description = 'Renders the ORM Dialect report in HTML format using Asciidoctor.'
|
||||||
|
dependsOn tasks.generateDialectReport
|
||||||
|
tasks.renderOrmReports.dependsOn task
|
||||||
|
inputs.property "version", project.ormVersion
|
||||||
|
|
||||||
|
sourceDir = layout.buildDirectory.dir('orm/reports')
|
||||||
|
sources {
|
||||||
|
include 'dialect.adoc'
|
||||||
|
}
|
||||||
|
|
||||||
|
outputDir = project.layout.buildDirectory.dir('asciidoc/dialect')
|
||||||
|
|
||||||
|
attributes linkcss: true,
|
||||||
|
stylesheet: "css/hibernate.css"
|
||||||
|
|
||||||
|
resources {
|
||||||
|
from('src/main/style/asciidoctor') {
|
||||||
|
include 'images/**'
|
||||||
|
}
|
||||||
|
from('src/main/style/asciidoctor') {
|
||||||
|
include 'css/**'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
|
@ -130,6 +130,11 @@ public class DerbyDialect extends Dialect {
|
||||||
super(info);
|
super(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected DatabaseVersion getMinimumSupportedVersion() {
|
||||||
|
return MINIMUM_VERSION;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String columnType(int sqlTypeCode) {
|
protected String columnType(int sqlTypeCode) {
|
||||||
switch ( sqlTypeCode ) {
|
switch ( sqlTypeCode ) {
|
||||||
|
|
|
@ -74,7 +74,6 @@ import org.hibernate.type.descriptor.jdbc.TimeUtcAsJdbcTimeJdbcType;
|
||||||
import org.hibernate.type.descriptor.jdbc.TimestampUtcAsInstantJdbcType;
|
import org.hibernate.type.descriptor.jdbc.TimestampUtcAsInstantJdbcType;
|
||||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||||
import org.hibernate.type.descriptor.jdbc.TimeUtcAsOffsetTimeJdbcType;
|
import org.hibernate.type.descriptor.jdbc.TimeUtcAsOffsetTimeJdbcType;
|
||||||
import org.hibernate.type.descriptor.jdbc.TimestampWithTimeZoneJdbcType;
|
|
||||||
import org.hibernate.type.descriptor.jdbc.UUIDJdbcType;
|
import org.hibernate.type.descriptor.jdbc.UUIDJdbcType;
|
||||||
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
|
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
|
||||||
import org.hibernate.type.descriptor.sql.internal.DdlTypeImpl;
|
import org.hibernate.type.descriptor.sql.internal.DdlTypeImpl;
|
||||||
|
@ -139,6 +138,9 @@ public class H2Dialect extends Dialect {
|
||||||
this( MINIMUM_VERSION );
|
this( MINIMUM_VERSION );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
System.out.println( new H2Dialect().getMinimumSupportedVersion() );
|
||||||
|
}
|
||||||
public H2Dialect(DatabaseVersion version) {
|
public H2Dialect(DatabaseVersion version) {
|
||||||
super(version);
|
super(version);
|
||||||
|
|
||||||
|
@ -177,6 +179,11 @@ public class H2Dialect extends Dialect {
|
||||||
return bits.length > 2 ? Integer.parseInt( bits[2] ) : 0;
|
return bits.length > 2 ? Integer.parseInt( bits[2] ) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected DatabaseVersion getMinimumSupportedVersion() {
|
||||||
|
return MINIMUM_VERSION;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean getDefaultNonContextualLobCreation() {
|
public boolean getDefaultNonContextualLobCreation() {
|
||||||
// http://code.google.com/p/h2database/issues/detail?id=235
|
// http://code.google.com/p/h2database/issues/detail?id=235
|
||||||
|
|
|
@ -0,0 +1,261 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html.
|
||||||
|
*/
|
||||||
|
package org.hibernate.orm.post;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import org.gradle.api.Project;
|
||||||
|
import org.gradle.api.tasks.SourceSet;
|
||||||
|
import org.gradle.api.tasks.SourceSetContainer;
|
||||||
|
import org.gradle.api.tasks.TaskAction;
|
||||||
|
|
||||||
|
import org.hibernate.orm.env.HibernateVersion;
|
||||||
|
|
||||||
|
import org.jboss.jandex.ClassInfo;
|
||||||
|
import org.jboss.jandex.Index;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a report on Dialect information
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public abstract class DialectReportTask extends AbstractJandexAwareTask {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public DialectReportTask(IndexManager indexManager, Project project) {
|
||||||
|
super(
|
||||||
|
indexManager,
|
||||||
|
project.getLayout().getBuildDirectory().file( "orm/reports/dialect.adoc" )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TaskAction
|
||||||
|
public void generateDialectReport() {
|
||||||
|
// the ones we want are all in the hibernate-core project
|
||||||
|
final Project coreProject = getProject().getRootProject().project( "hibernate-core" );
|
||||||
|
final SourceSetContainer sourceSets = coreProject.getExtensions().getByType( SourceSetContainer.class );
|
||||||
|
final SourceSet sourceSet = sourceSets.getByName( SourceSet.MAIN_SOURCE_SET_NAME );
|
||||||
|
final ClassLoader classLoader = Helper.asClassLoader( sourceSet, coreProject.getConfigurations().getByName( "testRuntimeClasspath" ) );
|
||||||
|
|
||||||
|
final DialectClassDelegate dialectClassDelegate = new DialectClassDelegate( classLoader );
|
||||||
|
|
||||||
|
final Index index = getIndexManager().getIndex();
|
||||||
|
final Collection<ClassInfo> allDialectClasses = index.getAllKnownSubclasses( DialectClassDelegate.DIALECT_CLASS_NAME );
|
||||||
|
if ( allDialectClasses.isEmpty() ) {
|
||||||
|
throw new RuntimeException( "Unable to find Dialects" );
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<DialectDelegate> dialectDelegates = collectDialectInfo( dialectClassDelegate, allDialectClasses );
|
||||||
|
generateReport( dialectDelegates );
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<DialectDelegate> collectDialectInfo(
|
||||||
|
DialectClassDelegate dialectClassDelegate,
|
||||||
|
Collection<ClassInfo> allDialectClasses) {
|
||||||
|
final List<DialectDelegate> results = new ArrayList<>();
|
||||||
|
|
||||||
|
allDialectClasses.forEach( (dialectImplClassInfo) -> {
|
||||||
|
final String dialectImplClassName = dialectImplClassInfo.name().toString();
|
||||||
|
final DialectDelegate dialectDelegate = dialectClassDelegate.createDialectDelegate( dialectImplClassName );
|
||||||
|
if ( dialectDelegate == null ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
results.add( dialectDelegate );
|
||||||
|
} );
|
||||||
|
|
||||||
|
results.sort( Comparator.comparing( DialectDelegate::getSimpleName ) );
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void generateReport(List<DialectDelegate> dialectDelegates) {
|
||||||
|
final File reportFile = prepareReportFile();
|
||||||
|
try ( final OutputStreamWriter fileWriter = new OutputStreamWriter( new FileOutputStream( reportFile ) ) ) {
|
||||||
|
writeDialectReport( dialectDelegates, fileWriter );
|
||||||
|
}
|
||||||
|
catch (FileNotFoundException e) {
|
||||||
|
throw new RuntimeException( "Should never happen" );
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
throw new RuntimeException( "Error writing to report file", e );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeDialectReport(
|
||||||
|
List<DialectDelegate> dialectDelegates,
|
||||||
|
OutputStreamWriter fileWriter) {
|
||||||
|
writeDialectReportHeader( fileWriter );
|
||||||
|
|
||||||
|
dialectDelegates.forEach( (dialectDelegate) -> writeDialectReportEntry( dialectDelegate, fileWriter ) );
|
||||||
|
|
||||||
|
writeDialectReportFooter( fileWriter );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeDialectReportHeader(OutputStreamWriter fileWriter) {
|
||||||
|
try {
|
||||||
|
fileWriter.write( "= Supported Dialects\n\n" );
|
||||||
|
fileWriter.write( "Supported Dialects along with the minimum supported version of the underlying database.\n\n\n" );
|
||||||
|
|
||||||
|
HibernateVersion ormVersion = (HibernateVersion) getProject().getRootProject().getExtensions().getByName( "ormVersion" );
|
||||||
|
fileWriter.write( "NOTE: Hibernate version " + ormVersion.getFamily() + "\n\n" );
|
||||||
|
|
||||||
|
fileWriter.write( "[cols=\"a,a\", options=\"header\"]\n" );
|
||||||
|
fileWriter.write( "|===\n" );
|
||||||
|
fileWriter.write( "|Dialect |Minimum Database Version\n" );
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
throw new RuntimeException( "Error writing report header", e );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeDialectReportEntry(DialectDelegate dialectDelegate, OutputStreamWriter fileWriter) {
|
||||||
|
try {
|
||||||
|
final String version = dialectDelegate.getMinimumVersion();
|
||||||
|
fileWriter.write( '|' );
|
||||||
|
fileWriter.write( dialectDelegate.getDialectImplClass().getSimpleName() );
|
||||||
|
fileWriter.write( '|' );
|
||||||
|
fileWriter.write( version );
|
||||||
|
fileWriter.write( "\n" );
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
throw new RuntimeException( "Unable to access Dialect : " + dialectDelegate.getDialectReference(), e );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeDialectReportFooter(OutputStreamWriter fileWriter) {
|
||||||
|
try {
|
||||||
|
fileWriter.write( "|===\n" );
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
throw new RuntimeException( "Error writing report footer", e );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class DialectClassDelegate {
|
||||||
|
public static final String DIALECT_CLASS_NAME = "org.hibernate.dialect.Dialect";
|
||||||
|
public static final String MIN_VERSION_METHOD_NAME = "getMinimumSupportedVersion";
|
||||||
|
|
||||||
|
private final Class<?> loadedDialectClass;
|
||||||
|
private final Method versionMethod;
|
||||||
|
private final ClassLoader classLoader;
|
||||||
|
|
||||||
|
public DialectClassDelegate(ClassLoader classLoader) {
|
||||||
|
this.classLoader = classLoader;
|
||||||
|
try {
|
||||||
|
loadedDialectClass = classLoader.loadClass( DIALECT_CLASS_NAME );
|
||||||
|
versionMethod = loadedDialectClass.getDeclaredMethod( MIN_VERSION_METHOD_NAME );
|
||||||
|
versionMethod.setAccessible( true );
|
||||||
|
}
|
||||||
|
catch (ClassNotFoundException e) {
|
||||||
|
throw new RuntimeException( "Could not load " + DIALECT_CLASS_NAME, e );
|
||||||
|
}
|
||||||
|
catch (NoSuchMethodException e) {
|
||||||
|
throw new RuntimeException( "Could not locate method " + MIN_VERSION_METHOD_NAME, e );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public DialectDelegate createDialectDelegate(String dialectImplClassName) {
|
||||||
|
if ( dialectImplClassName.endsWith( "DialectDelegateWrapper" ) ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
final Class<?> dialectImplClass;
|
||||||
|
try {
|
||||||
|
dialectImplClass = classLoader.loadClass( dialectImplClassName );
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
// assume it is from project other than hibernate-core
|
||||||
|
getLogger().debug( "Skipping Dialect " + dialectImplClassName + " - could not instantiate", e );
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( Modifier.isAbstract( dialectImplClass.getModifiers() ) ) {
|
||||||
|
getLogger().debug( "Skipping Dialect " + dialectImplClassName + " - abstract" );
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( dialectImplClass.isAnnotationPresent( Deprecated.class ) ) {
|
||||||
|
getLogger().debug( "Skipping Dialect " + dialectImplClassName + " - deprecated" );
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DialectDelegate.from( dialectImplClass, this );
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
throw new RuntimeException( "Unable to access Dialect class : " + dialectImplClassName, e );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Class<?> getLoadedDialectClass() {
|
||||||
|
return loadedDialectClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Method getVersionMethod() {
|
||||||
|
return versionMethod;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class DialectDelegate {
|
||||||
|
private final Class<?> dialectImplClass;
|
||||||
|
private final DialectClassDelegate dialectClassDelegate;
|
||||||
|
|
||||||
|
private final Object dialectRef;
|
||||||
|
|
||||||
|
public static DialectDelegate from(Class<?> dialectImplClass, DialectClassDelegate dialectClassDelegate) {
|
||||||
|
return new DialectDelegate( dialectImplClass, dialectClassDelegate );
|
||||||
|
}
|
||||||
|
|
||||||
|
public DialectDelegate(Class<?> dialectImplClass, DialectClassDelegate dialectClassDelegate) {
|
||||||
|
this.dialectImplClass = dialectImplClass;
|
||||||
|
this.dialectClassDelegate = dialectClassDelegate;
|
||||||
|
try {
|
||||||
|
this.dialectRef = dialectImplClass.getConstructor().newInstance();
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
throw new RuntimeException( "Unable to create DialectDelegate for " + dialectImplClass.getName(), e );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSimpleName() {
|
||||||
|
return dialectImplClass.getSimpleName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public DialectClassDelegate getDialectClassDelegate() {
|
||||||
|
return dialectClassDelegate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Class<?> getDialectImplClass() {
|
||||||
|
return dialectImplClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getDialectReference() {
|
||||||
|
return dialectRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMinimumVersion() {
|
||||||
|
try {
|
||||||
|
final Object versionRef = dialectClassDelegate.getVersionMethod().invoke( dialectRef );
|
||||||
|
return versionRef.toString();
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
throw new RuntimeException( "Unable to access " + DialectClassDelegate.MIN_VERSION_METHOD_NAME + " for " + dialectClassDelegate.loadedDialectClass.getName(), e );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html.
|
||||||
|
*/
|
||||||
|
package org.hibernate.orm.post;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLClassLoader;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.gradle.api.Project;
|
||||||
|
import org.gradle.api.artifacts.Configuration;
|
||||||
|
import org.gradle.api.file.Directory;
|
||||||
|
import org.gradle.api.tasks.SourceSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class Helper {
|
||||||
|
public static ClassLoader asClassLoader(SourceSet sourceSet, Configuration gradleClasspath) {
|
||||||
|
final List<URL> urls = new ArrayList<>();
|
||||||
|
|
||||||
|
final Directory classesDirectory = sourceSet.getJava().getClassesDirectory().get();
|
||||||
|
final File classesDir = classesDirectory.getAsFile();
|
||||||
|
addElement( urls, classesDir );
|
||||||
|
|
||||||
|
for ( File dependencyFile : gradleClasspath.resolve() ) {
|
||||||
|
addElement( urls, dependencyFile );
|
||||||
|
}
|
||||||
|
|
||||||
|
return new URLClassLoader( urls.toArray( new URL[0] ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void addElement(List<URL> urls, File element) {
|
||||||
|
try {
|
||||||
|
urls.add( element.toURI().toURL() );
|
||||||
|
}
|
||||||
|
catch (MalformedURLException e) {
|
||||||
|
throw new RuntimeException( "Unable to create URL for ClassLoader: " + element.getAbsolutePath(), e );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -66,5 +66,13 @@ public class ReportGenerationPlugin implements Plugin<Project> {
|
||||||
);
|
);
|
||||||
loggingTask.dependsOn( indexerTask );
|
loggingTask.dependsOn( indexerTask );
|
||||||
groupingTask.dependsOn( loggingTask );
|
groupingTask.dependsOn( loggingTask );
|
||||||
|
|
||||||
|
final DialectReportTask dialectTask = project.getTasks().create(
|
||||||
|
"generateDialectReport",
|
||||||
|
DialectReportTask.class,
|
||||||
|
indexManager
|
||||||
|
);
|
||||||
|
dialectTask.dependsOn( indexerTask );
|
||||||
|
groupingTask.dependsOn( dialectTask );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue