Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Slow compilation with jOOQ 3.6+, plain SQL, and the javac compiler [duplicate]

The following bug was reported to the jOOQ user group. It really seems to be a bug in the javac compiler related to rather "complex" type inference work done by the compiler in the context of using an internal DSL like jOOQ is.

Given the general nature of the bug, I'm documenting it here on Stack Overflow for others to help apply workarounds if they run into it. On a high level, it seems to be a compiler performance regression due to JEP 101: Generalized Target-Type Inference, which was introduced in Java 8 and has caused 1-2 issues in the past.

The following relatively harmless class takes around 20 seconds to compile with jdk 1.8.0_60 or 1.8.0_66 on Windows using Maven and jOOQ 3.7:

import static org.jooq.impl.DSL.field;

import org.jooq.SQLDialect;
import org.jooq.impl.DSL;

public class Test {
    public void method() {
        DSL.using(SQLDialect.MYSQL)
           .select()
           .where(DSL.trueCondition())
           .and(field("client.id").eq(field("client_id")))
           .and(field("client.id").eq(field("client_id")))
           .and(field("client.id").eq(field("client_id")))
           .and(field("client.id").eq(field("client_id")))
           .and(field("client.id").eq(field("client_id")))
           .and(field("client.id").eq(field("client_id")))
           .and(field("client.id").eq(field("client_id")))
           .and(field("client.id").eq(field("client_id")))
           .and(field("client.id").eq(field("client_id")))
           .and(field("client.id").eq(field("client_id")))
        ;
    }
}

pom.xml:

<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>compilation-issues</groupId>
    <artifactId>compilation-issues</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <build>
        <sourceDirectory>src</sourceDirectory>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.3</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>org.jooq</groupId>
            <artifactId>jooq</artifactId>
            <version>3.7.1</version>
        </dependency>
    </dependencies>
</project>

Configurations when this issue doesn't appear:

  • Using jOOQ 3.5 (anything prior to 3.6.0)
  • Using jOOQ with generated classes rather than the above "plain SQL" API
  • Using Java 7
  • Using the Eclipse compiler
like image 662
Lukas Eder Avatar asked Dec 11 '15 12:12

Lukas Eder


1 Answers

Explanation

In jOOQ 3.6 (when this problem first appears), the DSL.field() API saw 22 new overloads taking different Row types as arguments:

  • DSL.field(Row1<T1>)
  • DSL.field(Row2<T1, T2>)
  • DSL.field(Row3<T1, T2, T3>)
  • ...

It appears that with this particular API usage above, the new overloads cause a lot of trouble when the javac compiler tries to find the most specific overload among all the possible overloads. The following workaround compiles instantly:

Fix

A fix is under way for releases 3.9.0, 3.8.1, 3.7.4, 3.6.5, removing these methods again from the public API, and providing a renamed substitute that does not cause any overloading issues.

Workarounds

1. Helping the compiler select the most specific DSL.field() overload

import static org.jooq.impl.DSL.field;

import org.jooq.Field;
import org.jooq.SQLDialect;
import org.jooq.impl.DSL;

public class Test {
    public void method() {
        Field<Object> f1 = field("client.id");
        Field<Object> f2 = field("client_id");
        DSL.using(SQLDialect.MYSQL)
           .select()
           .where(DSL.trueCondition())
           .and(f1.eq(f2))
           .and(f1.eq(f2))
           .and(f1.eq(f2))
           .and(f1.eq(f2))
           .and(f1.eq(f2))
           .and(f1.eq(f2))
           .and(f1.eq(f2))
           .and(f1.eq(f2))
           .and(f1.eq(f2))
           .and(f1.eq(f2))
        ;
    }
}

2. Preventing target type inference in the context of the and() method entirely

import static org.jooq.impl.DSL.field;

import org.jooq.Condition;
import org.jooq.SQLDialect;
import org.jooq.impl.DSL;

public class Test {
    public void method() {
        Condition condition = field("client.id").eq(field("client_id"));
        DSL.using(SQLDialect.MYSQL)
           .select()
           .where(DSL.trueCondition())
           .and(condition)
           .and(condition)
           .and(condition)
           .and(condition)
           .and(condition)
           .and(condition)
           .and(condition)
           .and(condition)
           .and(condition)
           .and(condition)
        ;
    }
}

More info

This has actually been reported on Stack Overflow before:

  • Troubleshoot slow compilation
  • http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8086048

And it has been discussed also on the jOOQ user group:

  • https://groups.google.com/forum/#!topic/jooq-user/vuaG9d9krDk
  • https://groups.google.com/forum/#!topic/jooq-user/grv6Wu_sFtA
like image 79
Lukas Eder Avatar answered Oct 02 '22 20:10

Lukas Eder