JetBrains / Exposed

Kotlin SQL Framework
http://jetbrains.github.io/Exposed/
Apache License 2.0
8.37k stars 694 forks source link

exposed-java-time.jar unusable with java module system #853

Closed kenolson closed 1 year ago

kenolson commented 4 years ago

Using exposed-java-time.jar with JPMS results in an exception during initial classloading. Exception in thread "main" java.lang.NoClassDefFoundError: org/jetbrains/exposed/sql/java-time/JavaDateColumnTypeKt

When using exposed in a project using the java module system (module-info.java present), the exposed-java-time.jar file fails to load as a module because the package name of its classes is not a valid java package name. During module loading the jar file is scanned to discover all the packages contained in the jar (so the JVM can construct a package to module map).

For each class found the package name is extracted and validated (path through JVM is ModulePath.deriveModuleDescriptor() -> ModulePath.toPackageName() -> Checks.isPackageName() -> Checks.isTypeName() -> Checks.isJavaIdentifier()) which fails due to the hyphen in "java-time" segment of the package name.

The jar file works when not used in a project using the java module system because this validation is not performed or needed. The exposed-jodatime.jar file works with the java module system because its package name is valid.

Please rename / duplicate or otherwise correct the package name (add an additional jar such as exposed-javatime with valid package names to preserve backward compatibility?) so that exposed can be fully used with the java module system.

Sample code to reproduce the issue below.

main.kt

package icu.kenolson.trial

import org.jetbrains.exposed.sql.Database
import org.jetbrains.exposed.sql.SchemaUtils
import org.jetbrains.exposed.sql.Table
//import org.jetbrains.exposed.sql.jodatime.date
//import org.jetbrains.exposed.sql.jodatime.datetime
import org.jetbrains.exposed.sql.`java-time`.date
import org.jetbrains.exposed.sql.`java-time`.datetime
import org.jetbrains.exposed.sql.transactions.TransactionManager
import org.sqlite.SQLiteDataSource
import java.sql.Connection

fun main() {
    val sqlds = SQLiteDataSource()
    sqlds.url = "jdbc:sqlite:exposed_kotlin.db3"
    Database.connect(sqlds)
    with (TransactionManager.currentOrNew(Connection.TRANSACTION_SERIALIZABLE)) {
        SchemaUtils.create(VideoFilesTable)
    }

}

object VideoFilesTable : Table() {
    val fileName = text("FileName")
    val dateCreated = date("DateCreated").nullable()
    val dateAdded = datetime("DateAdded").nullable()
}

module-info.java

module exposedTrial {
    requires exposed.core;
//    requires exposed.jodatime;
    requires exposed.java.time;
    requires exposed.jdbc;
    requires java.sql;
    requires kotlin.stdlib;
    requires sqlite.jdbc;

    exports icu.kenolson.trial;
}

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>exposedTrial</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <exposed.version>0.22.1</exposed.version>
        <java.version>11</java.version>
        <kotlin.compiler.incremental>true</kotlin.compiler.incremental>
        <kotlin.compiler.jvmTarget>11</kotlin.compiler.jvmTarget>
        <kotlin.compiler.languageVersion>1.3</kotlin.compiler.languageVersion>
        <kotlin.version>1.3.61</kotlin.version>
        <maven.compiler.source>${java.version}</maven.compiler.source>
        <maven.compiler.target>${java.version}</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <sqlite-jdbc.version>3.30.1</sqlite-jdbc.version>
    </properties>

    <repositories>
        <repository>
            <id>jcenter</id>
            <name>jcenter</name>
            <url>https://jcenter.bintray.com</url>
        </repository>
    </repositories>

    <dependencies>
        <dependency>
            <groupId>org.jetbrains.exposed</groupId>
            <artifactId>exposed-core</artifactId>
            <version>${exposed.version}</version>
        </dependency>
        <dependency>
            <groupId>org.jetbrains.exposed</groupId>
            <artifactId>exposed-jdbc</artifactId>
            <version>${exposed.version}</version>
        </dependency>
        <dependency>
            <groupId>org.jetbrains.exposed</groupId>
            <artifactId>exposed-java-time</artifactId>
            <version>${exposed.version}</version>
        </dependency>
        <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-stdlib-jdk8</artifactId>
            <version>${kotlin.version}</version>
        </dependency>
        <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-test</artifactId>
            <version>${kotlin.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.xerial</groupId>
            <artifactId>sqlite-jdbc</artifactId>
            <version>${sqlite-jdbc.version}</version>
        </dependency>
    </dependencies>

    <build>
        <sourceDirectory>src/main/kotlin</sourceDirectory>
        <plugins>
            <plugin>
                <groupId>org.jetbrains.kotlin</groupId>
                <artifactId>kotlin-maven-plugin</artifactId>
                <version>${kotlin.version}</version>
                <executions>
                    <execution>
                        <id>compile</id>
                        <phase>compile</phase>
                        <goals>
                            <goal>compile</goal>
                        </goals>
                        <configuration>
                            <jvmTarget>${java.version}</jvmTarget>
                            <sourceDirs>
                                <sourceDir>${project.basedir}/src/main/kotlin</sourceDir>
                                <sourceDir>${project.basedir}/src/main/java</sourceDir>
                            </sourceDirs>
                        </configuration>
                    </execution>
                    <execution>
                        <id>test-compile</id>
                        <phase>test-compile</phase>
                        <goals>
                            <goal>test-compile</goal>
                        </goals>
                        <configuration>
                            <jvmTarget>${java.version}</jvmTarget>
                            <sourceDirs>
                                <sourceDir>${project.basedir}/src/test/kotlin</sourceDir>
                                <sourceDir>${project.basedir}/src/test/java</sourceDir>
                            </sourceDirs>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <release>${java.version}</release>
                </configuration>
                <executions>
                    <!-- Replacing default-compile as it is treated specially by maven -->
                    <execution>
                        <id>default-compile</id>
                        <phase>none</phase>
                    </execution>
                    <!-- Replacing default-testCompile as it is treated specially by maven -->
                    <execution>
                        <id>default-testCompile</id>
                        <phase>none</phase>
                    </execution>
                    <execution>
                        <id>java-compile</id>
                        <phase>compile</phase>
                        <goals>
                            <goal>compile</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>java-test-compile</id>
                        <phase>test-compile</phase>
                        <goals>
                            <goal>testCompile</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>
RationalityFrontline commented 4 years ago

I‘ve encountered the same problem. Naming a package with hyphen is really a bad idea, hope it could get renamed. Since this issue has been open for 7 months with no updates, I take it that it won't be soon fixed, so I created a temporary library that solves this issue (by renaming the evil "java-time" to "javatime"). For anyone who encountered the same problem, this library might be of help. It's available in maven central, and the usage is below:

repositories {
    mavenCentral()
}

dependencies {
    implementation("org.rationalityfrontline.workaround:exposed-java-time:0.29.1")
}
Kabennsky commented 3 years ago

Have the same issue, still not fixed. Wonder why they havent noticed during development. Would bet they use Intellij, the editor should give warnings and building shouldnt be possible ether with this namespace. Makes exposed unuseable for dao in most cases.

xidsyed commented 1 year ago

Has this still not been fixed? How!!

bog-walk commented 1 year ago

@xidsyed This issue was fixed by this commit and was included in the release of version 0.36.1 in 2021. The issue, unlike its duplicate, was just not closed.

If there is still an issue related to using the package or .jar files, please consider reporting it on YouTrack so we can investigate further.