Itt jársz most: Kezdőlap > Alkalmazásfejlesztés > Egyperces: QueryDSL kódgenerálás Java 21 alatt

Szűrő megjelenítése

Egyperces: QueryDSL kódgenerálás Java 21 alatt

A QueryDSL-t egy korábbi cikkemben már említettem, de emlékeztetőül, ez egy JPA query library, ami teljesen támogatott a Spring Data JPA által (gyakorlatilag része annak), segítségével egészen rugalmasan lehet egyedi lekérdezéseket írni. Mivel a JPA réteg része, működőképes SQL és NoSQL adatbázismotorokkal egyaránt, én MongoDB fölött használom. A bevezetőben említett metaosztályokat fordítási időben generálja, Maven és Gradle támogatása is van (bár Gradle alatt nem annyira egyszerű beállítani mint Maven esetében), problémát egészen Java 17-tel bezárólag nem is tapasztaltam vele. Aztán elkezdtem dolgozni a Java 21-re migráláson.

És itt kezdődtek a bajok. Fontos megjegyezni, hogy a QueryDSL egy ideje már tetszhalott állapotban van: a Spring Boot 3.x által is csomagolt 5.1.0-s verzió idén januárban jelent meg, az előző, 5.0.0-s verzió még 2021-ben. Bár az előbbi viszonylag jó jel, valójában a QueryDSL még mindig Java 11-el van fordítva, ami bizony már egy 6 éves verziója a Java-nak. A kódgeneráláshoz saját APT csomagot ad a library, azon belül pedig a cél adatbázismotornak megfelelő annotation processorral tudjuk generálni a metaosztályokat (Q-classok, a nevük miatt: mind úgy vannak elnevezve, hogy Q<EntityClassNév>). A hivatalos dokumentáció Maven integráláshoz az APT Maven Plugin legfrissebb verzióját ajánlja (com.mysema.maven:apt-maven-plugin:1.1.3), mellyel csupán egy probléma van: 2014-ben adták ki - ismétlem, ez a legfrissebb verzió. Java 21 alatt ez a kombináció már pontosan elég arra, hogy ne tudjon elindulni a metaosztályok generálása, bár meglepő módon pont nem az APT Maven Plugin okozza a problémát, hanem maga a QueryDSL APT modulja, egyszerűen nem tud mit kezdeni a Java 21-es forrásokkal.

Szerencsére több megoldás is rendelkezésünkre áll. Az egyik, talán legkézenfekvőbb a QueryDSL forkja, melyet a Feign REST kliens implementációt is "elkövető" OpenFeign vett gondozásába, és a fork 6.x verziói már támogatják a Java 21 és afölötti verziók használatát is. A probléma ezzel, hogy a fork is az APT Maven Pluginra támaszkodik, ami bár működik, személy szerint nem szívesen bízok friss verziókra támaszkodó, aktívan fejlesztett és karbantartott szoftver projekteket 10+ éves librarykre. A dokumentáció szerint azonban (mármint a QueryDSL eredeti dokumentációja szerint), a kódgenerálás beköthető a Maven Compiler Plugin compile goaljába. Teljesen jól hangzik, elvileg működik is, kivéve, ha Lombok annotációk is jelen vannak. Erre a következő megoldásom született (amiért előre is elnézést kérek, nem a legszebb, de legalább működik):

  1. Először is maradtam a Spring Boot által hozott 5.1.0-s verziónál;
  2. Majd az APT Maven Plugintól végleg megváltam;
  3. Végüli a Maven Compiler Plugin alapú megoldásnál maradtam, de a compilation phaset két executionre bontva, amiben az első csak a metaosztályok generálásáért felel, míg a második a teljeskörű fordításért, beleértve például a Lombok annotációk kezelését is.

A tökéletes eredmény érdekében a QueryDSL APT libraryjét a Maven Compiler Plugin függéseként kell beállítanunk, majd létre kell hoznunk két executiont, mindkettőt a compile goalra kötve, ám az elsőt a generate-sources, míg a másodikat a compile phaseben indítjuk. Az első executionben továbbá definiálni fogjuk a generáláshoz szükséges packageket mint annotation processor path-ok (ez a QueryDSL APT és a Spring Boot Starter Data MongoDB csomagok voltak ez esetemben, SQL adatbázisokhoz valószínűleg a Spring Boot Starter Data JPA kellene, de ezt nem mondom biztosra), majd kiválasztjuk az annotation processort magát (esetemben ez az org.springframework.data.mongodb.repository.support.MongoAnnotationProcessor volt). Nagyon fontos továbbá, hogy a configuration szekció proc kapcsolóját only módra állítjuk, ezzel jelezve a compilernek hogy itt kizárólag annotáció feldolgozással (ez esetben effektíve kódgenerálással) akarunk foglalkozni, ne végezzen fordítást. A második execution configurationjében lényegében visszakapcsolunk mindent alapértelmezettre, tehát a proc kapcsolót full módra állítjuk, a parameters kapcsolót true-ra, illetve a generált források mappáját beállítjuk erre: target/generated-sources/annotations-default. Ezután újra működni fog a QueryDSL Java 21 alatt, az erősen elavult APT plugin nélkül.

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>${maven-compiler-plugin.version}</version>

    <!-- a QueryDSL APT plugint hozzáadjuk mint függés -->
    <dependencies>
        <dependency>
            <groupId>com.querydsl</groupId>
            <artifactId>querydsl-apt</artifactId>
            <version>${querydsl.version}</version>
        </dependency>
    </dependencies>
    <executions>

        <!-- első execution: csak annotáció feldolgozás, itt generáljuk a QueryDSL Q-classokat -->
        <execution>
            <id>run-annotation-processor</id>

            <!-- forrás generálási fázishoz kötjük -->
            <phase>generate-sources</phase>
            <goals>
                <goal>compile</goal>
            </goals>
            <configuration>

                <!-- csak annotáció feldolgozás szeretnénk -->
                <proc>only</proc>

                <!-- itt mondjuk meg a Mavennek, hogy hol találja a szükséges annotation processort -->
                <annotationProcessorPaths>
                    <path>
                        <groupId>com.querydsl</groupId>
                        <artifactId>querydsl-apt</artifactId>
                        <version>${querydsl.version}</version>
                    </path>
                    <path>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-starter-data-mongodb</artifactId>
                    </path>
                </annotationProcessorPaths>
                <annotationProcessors>
                    <processor>org.springframework.data.mongodb.repository.support.MongoAnnotationProcessor</processor>
                </annotationProcessors>

            </configuration>
        </execution>

        <!-- második execution: teljes fordítás, immár a Q-clasokkal együtt -->
        <execution>
            <id>default-compile</id>

            <!-- ahogy eredetileg is történne, ezt már a compile fázisban futtatjuk -->
            <phase>compile</phase>
            <goals>
                <goal>compile</goal>
            </goals>
            <configuration>

                <!-- teljes annotáció feldolgozást vissza kell kapcsolnunk, pl a Lombok miatt -->
                <proc>full</proc>
                <parameters>true</parameters>
                <generatedSourcesDirectory>target/generated-sources/annotations-default</generatedSourcesDirectory>
            </configuration>

        </execution>
    </executions>
</plugin>
Kommentek

Komment írásához jelentkezz be
Bejelentkezés

Még senki nem szólt hozzá ehhez a bejegyzéshez.