Gradle Kasutamine IntelliJ-s¶
See juhend selgitab, kuidas kasutada Gradle'i Java projekti pakendamiseks IntelliJ IDEA keskkonnas
Uue Gradle Projekti Loomine IntelliJ-s¶
IntelliJ IDEA Avamine: Avage IntelliJ IDEA ja valige "Create New Project".
Gradle Projekti Valik: Valikuaknas valige "Gradle" vasakult ja veenduge, et "Java" on valitud paremalt. Vajutage "Next".
Projekti Seadistamine: Sisestage projekti nimi ja asukoht. Vajutage "Finish".
Projekti Struktuuri Seadistamine¶
IntelliJ loob automaatselt Gradle projekti struktuuri, sealhulgas:
src/main/java
Java koodi jaokssrc/main/resources
ressursside jaokssrc/test/java
testide jaoks
build.gradle
Faili Konfigureerimine¶
Leidke build.gradle fail projekti juurkaustas ja lisage järgmine sisu:
NB! Gradle'il on mitmeid erinevaid süntakseid peaaegu iga tegevuse jaoks. Kui leiate juhendist mõne alternatiivse lahenduse, on tõenäoline, et see saavutab sama tulemuse.
Mõnel juhul võivad need süntaksid siiski veidi erineda, seega tasub olla tähelepanelik, et kasutatav süntaks vastaks soovitud tulemusele. Gradle võib olla selles osas kohati segadusttekitav :D
// Mina ei tea täpselt mida see teeb ja teie ei pea ka teadma
// Kui tutorial ütleb, et vaja lisada siia midagi, siis lisa
plugins {
id 'java'
id 'java-library'
}
group 'ee.taltech' // Lihtsalt viisakas öelda, milline on teie rakenduse package prefix
version '1.0' // Samamoodi praegu pigem viisakus
// Siin on defineeritud kõik kohad, kust gradle otsib sinu rakenduse sõltuvusi (lisatud all dependencies plokis)
allprojects {
repositories {
mavenCentral() // Seda tahad sa ilmselt alati lisada, siin on kõike https://mvnrepository.com/repos/central
maven { url 'https://jitpack.io' } // Vajadusel saab lisada ka alternatiive
}
}
// Siia lisa kõik teegid, mida su rakendus kasutab
// (alati uuri igaks juhuks, kas eksisteerib uuemaid versioone)
dependencies {
// Näiteks kryoneti lisamine (mida ilmselt lisate oma serverisse):
implementation 'com.github.crykn:kryonet:2.22.8'
implementation 'com.esotericsoftware:kryo:5.4.0'
// Kui midagi on vaja testide jooksutamiseks, siis see on defineeritud nii
// Kuna test frameworki pole mujal vaja, siis on see siin
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
}
// Kui sa tahad teste kirjutada, peab olema see lisatud koos junit dependencyga
test {
useJUnitPlatform()
}
// Siin on defineeritud, kuidas gradle peaks ehitama JAR faili, mida saaks jooksutada ka teistes arvutites
jar {
manifest {
attributes(
// Main class väärtus oleneb sinu rakendusest.
// Siia peab minema klass, mille jooksutamisel rakenduse käima pannakse
'Main-Class': 'ee.taltech.server.Main'
)
}
duplicatesStrategy = DuplicatesStrategy.EXCLUDE // Teeb nii, et jar faili sees ei oleks topelt asju topitud
from (
// Valib kõik sinu failid jari sisse pakkimiseks
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
)
}
Projekti Ehitamine ja Käivitamine IntelliJ-s¶
Gradle Tööriistakast: Avage paremal Gradle tööriistakast.
Projekti Ehitamine: Topeltklõpsake
build
ülesandel, et kompileerida oma projekt ja luua JAR-fail.Rakenduse Käivitamine: Topeltklõpsake
run
ülesandelapplication
grupis, et käivitada oma rakendus IntelliJ IDEA-st.
Siin on näide Gradle'i seadistusest näidismängu jaoks:¶
buildscript {
repositories {
mavenCentral()
maven { url 'https://s01.oss.sonatype.org' }
gradlePluginPortal()
mavenLocal()
google()
maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
maven { url 'https://s01.oss.sonatype.org/content/repositories/snapshots/' }
}
dependencies {
}
}
allprojects {
apply plugin: 'eclipse'
apply plugin: 'idea'
// This allows you to "Build and run using IntelliJ IDEA", an option in IDEA's Settings.
idea {
module {
outputDir file('build/classes/java/main')
testOutputDir file('build/classes/java/test')
}
}
}
configure(subprojects) {
apply plugin: 'java-library'
sourceCompatibility = 21
// From https://lyze.dev/2021/04/29/libGDX-Internal-Assets-List/
// The article can be helpful when using assets.txt in your project.
tasks.register('generateAssetList') {
inputs.dir("${project.rootDir}/assets/")
// projectFolder/assets
File assetsFolder = new File("${project.rootDir}/assets/")
// projectFolder/assets/assets.txt
File assetsFile = new File(assetsFolder, "assets.txt")
// delete that file in case we've already created it
assetsFile.delete()
// iterate through all files inside that folder
// convert it to a relative path
// and append it to the file assets.txt
fileTree(assetsFolder).collect { assetsFolder.relativePath(it) }.sort().each {
assetsFile.append(it + "\n")
}
}
processResources.dependsOn 'generateAssetList'
compileJava {
options.incremental = true
}
}
subprojects {
version = '$projectVersion'
ext.appName = 'example-game'
repositories {
mavenCentral()
maven { url 'https://s01.oss.sonatype.org' }
// You may want to remove the following line if you have errors downloading dependencies.
mavenLocal()
maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
maven { url 'https://s01.oss.sonatype.org/content/repositories/snapshots/' }
maven { url 'https://jitpack.io' }
}
}
eclipse.project.name = 'example-game' + '-parent'
Võetud siit
buildscript¶
See määrab Gradle’i skripti jaoks vajalikud sõltuvused ja hoidlad.
- repositories – Siin on määratud erinevad hoidlad, kust sõltuvusi alla laaditakse:
mavenCentral() – Maven Central repositoorium.
dependencies – Siin oleks võimalik määrata sõltuvusi, mida Gradle vajab enne projektiga töötamist. Hetkel on see tühi.
allprojects¶
See plokk rakendub kõigile projektidele, kaasa arvatud alamprojektid.
apply plugin: 'eclipse' – Lisab toe Eclipse IDE jaoks.
apply plugin: 'idea' – Lisab toe IntelliJ IDEA jaoks.
- idea plokk – Konfigureerib IntelliJ IDEA ehituskataloogid:
outputDir file('build/classes/java/main') – Määrab kompileeritud klassifailide väljundkausta.
testOutputDir file('build/classes/java/test') – Määrab testide kompileeritud klassifailide väljundkausta.
configure(subprojects)¶
Siin konfigureeritakse kõik alamprojektid.
apply plugin: 'java-library' – Määrab, et kõik alamprojektid kasutavad java-library pluginit.
sourceCompatibility = 21 – Määrab Java versiooniks 21.
Automaatne asset'ide nimekirja genereerimine (generateAssetList ülesanne)
- Loob ülesande generateAssetList, mis:
Määrab, et inputs.dir("${project.rootDir}/assets/") jälgib assets/ kausta.
Loob faili assets.txt kaustas assets/.
Kustutab faili, kui see eksisteerib.
Läbib kõik failid assets/ kaustas, teisendab need suhtelisteks teedeks (relative path) ja lisab need assets.txt faili.
processResources.dependsOn 'generateAssetList' – Tagab, et generateAssetList käivitatakse enne processResources ülesannet.
compileJava ülesanne
options.incremental = true – Lubab Java kompileerimisel järk-järgulise kompileerimise, mis kiirendab arendustööd.
subprojects¶
Konfigureerib kõik alamprojektid.
version = '$projectVersion' – Määrab projekti versiooni.
ext.appName = 'example-game' – Määrab kohandatud muutuja appName väärtuseks 'example-game'.
- repositories – Määrab, kust sõltuvused alla laaditakse:
mavenCentral() – Maven Central.
Server build.gradle näidismängust¶
Nüüd vaatame serveri build.gradle faili.
apply plugin: 'application'
java.sourceCompatibility = 21
java.targetCompatibility = 21
if (JavaVersion.current().isJava9Compatible()) {
compileJava.options.release.set(21)
}
mainClassName = 'ee.taltech.examplegame.server.ServerLauncher'
application.setMainClass(mainClassName)
eclipse.project.name = appName + '-server'
dependencies {
implementation project(':shared')
implementation group: 'com.esotericsoftware', name: 'kryonet', version: '2.22.0-RC1'
implementation group: 'com.google.code.gson', name: 'gson', version: '2.11.0'
// you must enable annotation processing in intellij settings.
compileOnly 'org.projectlombok:lombok:1.18.36'
annotationProcessor 'org.projectlombok:lombok:1.18.36'
}
jar {
archiveBaseName.set(appName)
// the duplicatesStrategy matters starting in Gradle 7.0; this setting works.
duplicatesStrategy(DuplicatesStrategy.EXCLUDE)
dependsOn configurations.runtimeClasspath
from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
// these "exclude" lines remove some unnecessary duplicate files in the output JAR.
exclude('META-INF/INDEX.LIST', 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA')
dependencies {
exclude('META-INF/INDEX.LIST', 'META-INF/maven/**')
}
// setting the manifest makes the JAR runnable.
manifest {
attributes 'Main-Class': project.mainClassName
}
// this last step may help on some OSes that need extra instruction to make runnable JARs.
doLast {
file(archiveFile).setExecutable(true, false)
}
}
// Equivalent to the jar task; here for compatibility with gdx-setup.
task dist(dependsOn: [jar]) {
}
Võetud siit
Üldine seadistus¶
apply plugin: 'application' // Aktiveerib application plugina, mis võimaldab määrata rakenduse käivitusklassi ja luua käivitatava JAR-faili.
Põhiklass ja projekti nimi¶
mainClassName = 'ee.taltech.examplegame.server.ServerLauncher' // Määrab rakenduse käivitusklassiks ServerLauncher
application.setMainClass(mainClassName)
eclipse.project.name = appName + '-server' // Eclipse projekti nimeks pannakse appName + -server.
Sõltuvused¶
dependencies {
implementation project(':shared') // Kohalik projektimoodul :shared kus asuvad ühised konstandid, sõnumid ja seaded, mida kasutatakse kliendi ja serveri vaheliseks suhtluseks.
implementation group: 'com.esotericsoftware', name: 'kryonet', version: '2.22.0-RC1' // Võrgu teek KryoNet, mida kasutatakse serveri ja kliendi loomiseks
implementation group: 'com.google.code.gson', name: 'gson', version: '2.11.0' // Java objektide ja JSON-i vahelise teisendamise teek Gson
// Lombok ainult kompileerimiseks ja annotatsioonide töötlemiseks (vajab IntelliJ-s annotatsioonitöötluse lubamist)
compileOnly 'org.projectlombok:lombok:1.18.36'
annotationProcessor 'org.projectlombok:lombok:1.18.36'
}
Mis on erinevus "annotationProcessor" ja "compileOnly" vahel antud näites?
Lombok annab võimaluse lisada klassi ees anotsioone, nagu näiteks "getters", mis lisavad automaatselt selle klassi iga atribuudi jaoks getter'id, aidates vältida koodi ülekoormamist.
annotationProcessor annab võimaluse arenduskeskkonnal pakkuda arendajale auto complete valikuid klassi jaoks, millel on "getters" anotsioon, ehkki neid getter'eid füüsiliselt koodis ei ole.
compileOnly - kompilatsiooni ajal lisatakse need kõik getter'id füüsiliselt byte-koodi.
Seega erinevus seisneb selles, et esimene teeb näo, et mingid meetodid eksisteerivad, võimaldades neid kasutada IDE-s ilma veateateta. Teine lisab need meetodid tegelikult, et programmi käivitamisel ei tekiks viga, et koodis kasutatakse meetodit, mida tegelikult ei ole.
JAR-faili konfigureerimine¶
jar {
archiveBaseName.set(appName) // Seab JAR-faili nimeks muutuja appName väärtuse (näiteks "example-game").
duplicatesStrategy(DuplicatesStrategy.EXCLUDE) // Välistab duplikaadid ja ebavajalikud failid (META-INF)
dependsOn configurations.runtimeClasspath // Lisab kõik vajalikud klassiteegid JAR-i sisse (fat JAR)
from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } } // kõik vajalikud sõltuvused, mis ei ole juba kataloogid, pakitakse välja (näiteks .jar failid).
exclude('META-INF/INDEX.LIST', 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA')
dependencies {
exclude('META-INF/INDEX.LIST', 'META-INF/maven/**')
}
manifest {
attributes 'Main-Class': project.mainClassName // JAR-faili saab käivitada ainult siis, kui see sisaldab määratud põhiklassi (Main-Class). See on klass, kus main meetod asub, ja see käivitab kogu rakenduse.
// project.mainClassName on eelnevalt määratud kui ee.taltech.examplegame.server.ServerLauncher.
}
doLast {
file(archiveFile).setExecutable(true, false) // Märgistab JAR-faili käivitatavaks (mõnel OS-il vajalik)
}
}
Mis on META-INF
META-INF on eriline kaust JAR-failides, mis sisaldab metainfot – ehk infot selle JAR-faili enda kohta, mitte tingimata programmi enda kohta. Kui avada mõne .jar faili (nt arhiivina ZIP-iga), siis seal sees on tavaliselt üks kataloog nimega META-INF.
Faili nimi |
Kirjeldus |
MANIFEST.MF |
Peamine metainfoga fail – sisaldab infot nagu Main-Class, versioon, teegid jne. |
Digiallkirjade failid, mida kasutatakse allkirjastatud JAR-ides (nt turvalisus, päritolu kontroll). |
|
INDEX.LIST |
Kiiremaks JAR-i klasside leidmiseks – ei ole alati vajalik. |
maven/** |
Kui JAR on loodud Maveniga, võib siin olla infot selle artefakti päritolu kohta. |
Kui tehakse fat JAR-i (kus on sees mitu teeki korraga), siis igas JAR-is võib olla oma META-INF, ja need võivad kattuda või konflikti minna.
Näiteks, kui JAR-fail sisaldab META-INF/*.RSA või .SF ja muudada midagi selles JAR-is (nt lisad faile), siis allkiri ei vasta enam failile, ja Java võib keelduda selle käivitamisest.
Task dist¶
// Equivalent to the jar task; here for compatibility with gdx-setup.
task dist(dependsOn: [jar]) { // loob lihtsalt uue käsu nimega dist, mida saab käsurealt käivitada (./gradlew dist).#
// dependsOn: [jar] tähendab, et enne kui dist töö käivitatakse, peab kindlasti valmis saama jar töö – see on töö, mis loob JAR-faili.
}
gdx-setup on LibGDX-i projekti seadistustööriist. Mõned vanemad tööriistad (nagu gdx-setup) ootavad, et Gradle projektis oleks töö nimega dist, kuigi jar töö teeks tegelikult sama asja.
dist = alias jar-ile
Klient build.gradle näidismängust¶
Nüüd vaatame kliendi build.gradle faili.
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
eclipse.project.name = appName + '-core'
dependencies {
api "com.badlogicgames.gdx:gdx:$gdxVersion"
api "com.badlogicgames.gdx:gdx-freetype:$gdxVersion"
api "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-desktop"
api project(':shared')
if (enableGraalNative == 'true') {
implementation "io.github.berstanio:gdx-svmhelper-annotations:$graalHelperVersion"
}
implementation group: 'com.esotericsoftware', name: 'kryonet', version: '2.22.0-RC1'
}
Võetud siit
Sõltuvused¶
dependencies {
api "com.badlogicgames.gdx:gdx:$gdxVersion" // põhiliselt kasutatud teek (kogu mängu loogika).
api "com.badlogicgames.gdx:gdx-freetype:$gdxVersion" // tugi TrueType fontidele (nt .ttf-failid).
api "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-desktop"
api project(':shared') // // Kohalik projektimoodul :shared kus asuvad ühised konstandid, sõnumid ja seaded, mida kasutatakse kliendi ja serveri vaheliseks suhtluseks.
if (enableGraalNative == 'true') { // Kui enableGraalNative == 'true', siis lisatakse tugi GraalVM Native Image jaoks (gdx-svmhelper-annotations).
// See aitab LibGDX rakendust kompileerida native binaariks.
implementation "io.github.berstanio:gdx-svmhelper-annotations:$graalHelperVersion"
}
implementation group: 'com.esotericsoftware', name: 'kryonet', version: '2.22.0-RC1'
}
implementation vs api
Mis vahe on nende märksõnade vahel?
Eelkõige puudutab see ligipääsu — võib öelda, et api on nagu public ja implementation nagu private.
Mida see annab?
Oletame, et me lisame oma projekti teegi nimega "library" (pole oluline, kas läbi "api" või "implementation"), ja see teek omakorda sõltub teegist "libraryInner". Kui "libraryInner" on lisatud "api" kaudu, siis meie projektist saab kasutada ka "libraryInner" meetodeid. Kui aga "library" kasutab implementation — kaotame selle võimaluse.
Milleks seda vaja on?
Põhjuseks on kompileerimiskiirus. Kui "library" kasutab api, siis muudatused "libraryInner" teegis toovad kaasa vajaduse ümber kompileerida nii "library" kui ka kogu meie projekt, sest meil võib olla otsene sõltuvus "libraryInner"-ist. Aga kui kasutatakse implementation, siis me ei saa "libraryInner" meetodeid kasutada ja seetõttu piisab ainult "library" ümber kompileerimisest.
TROUBLESHOOTING¶
- Lisasin dependency, aga seda ei ole projektis?
Refreshi projekti (Gradle aknas noolte ring)
Kontrolli, et sul on lisatud õige repositroy, kust Gradle saaks importida teeke (allprojects -> dependencies osa build.gradle sees)
- Kuidas Gradle projekti alustada?
Vajuta File -> New -> Project. Language: Java, Build system: Gradle, Gradle DSL: Groovy
- IntelliJ ei tuvasta ära minu Gradle projekti
Proovi restarti. IntelliJ peaks näitama popupi Gradle projekti importimiseks
Proovi manuaalselt moodul lisada. File -> New -> Module from existing sources. Vali kaust, milles on sinu rakendus (see kaust kus on build.gradle ja muud Gradle failid)
Proovi IntelliJ cache kustutada. File -> Invalidate Caches. Proovi eelmiseid samme
Proovi projekt ära kustutada ja klooni see uuesti
Kui kõik eelnev ei aidanud, siis on võimalik, et projektis on midagi valesti seadistatud või läks mõni samm sassi. Gradle + Intellij töötab suht lollikindlalt, kuid kui midagi siin ei ole aidanud, siis kirjuta õppejõule