Kotlin/JVM: after adding a package directive to my...
# getting-started
k
Kotlin/JVM: after adding a package directive to my code, I can no longer access any resource files. No matter what path I try giving them, it will just not find them. Folders look like this:
src
main
kotlin
*.kt
resources
file.txt
prior to this, just "file.txt" worked.
c
generally only resources relative to your package or absolute-path-specified resources are accessible. Try moving file.txt into a directory structure reflecting the package (and access as “file.txt) or access as “/file.txt”.
e
this isn't a Kotlin thing, it's a documented behavior of Java https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#getResource-java.lang.String-
k
is there no way to avoid having directory gore caused by the package name? It feels silly to move the source 3 more directories deeper
or is there any downside to just not having the package defined since it worked fine without it?
c
You have these options available:
Try moving file.txt into a directory structure reflecting the package (and access as “file.txt) or access as “/file.txt”.
It’s bad practice to not define a package.
k
but is there any downside to it?
k
if my package is named for example com.example.app, ni what folder would I have to place the resources?
e
src/main/resources/com/example/app/file.txt
as the documentation clearly states that
.
is replaced by
/
when constructing the path
👍 1
c
com/example/app
would be the folder. Alternately, the resources can go in any folder structure (including how you have it today), and be referenced by their absolute path
/file.txt
or
/whatever/file.txt
.
k
what's the root of the absolute path?
e
resources are searched throughout the classpath, same as the compiled classes
c
src/main/resources
contains resources that are bundled in the root of the jar.
e
a good reason to make your resources relative to your package name: to avoid collisions with other dependencies in your classpath
c
indeed. there’s a number of
/config.properties
still floating around out there in random libraries…
k
src/main/resources
is this path specified by something in the build system or is it the same for all projects?
c
that’s the convention for where resources go, used by Gradle. It can, in theory, be changed but there’s no value in that (unless one counts confusing others, including Future You, as valuable).
e
it's pretty conventional even outside of Gradle, but yes. the contents of path are recursively copied into the JAR
k
that explains it, thanks
I just find the idea of forcing a package down multiple levels of folders with zero use to them super silly
it'd make so much more sense to be able to define the root of the package as the root of the repository or a single subfolder of it
e
(also when running or testing local project dependencies, Gradle is able to use the directories directly instead of building a JAR, but that's getting a bit outside the point)
(without JPMS) there isn't really any sense of "where" things in the classpath come from, or even much control over priority/ordering. so you have to do the work yourself to ensure no collisions
a
in Kotlin it’s not strictly necessary to have the package match the location. You could have a file
src/main/kotlin/main.kt
, but the contents
Copy code
package my.cool.project

fun main() { ... }
and IntellijJ’s cool with it (so long as all other .kt files in the directory have the same package)
k
that's what I've been doing but apparently it's a bad practice
c
different context. source files vs resources.
j
It isn't a bad practice, it is the recommended indeed
check official Kotlin conventions
c
different context. they are still in a package there, the OP was discussing using the default package.
k
I still don't see why I'd place even the resources six folders deep when src/main/resources is usable
c
to avoid collisions with other files at the root of the classpath, to make ownership clean as code grows.
e
if every part of your codebase is in the
com.example.kotlin
package, then it's OK to simply have
src/main/kotlin/Foo.kt
,
src/main/kotlin/subpackage/Bar.kt
, etc. for
com.example.kotlin.Foo
,
com.example.kotlin.subpackage.Bar
classes, etc.
however, that is the Kotlin compiler doing extra work
resources are not handled by the Kotlin compiler, so you need to follow Java conventions there
a
placing resources six folders deep shouldn’t be necessary - what’s the code you’re using to access them? The Java resource loader can either load a resource relative to the current class, or absolutely, from
src/main/resources
https://stackoverflow.com/q/44896538/4161471
e
using resource paths without package names shares downsides with using classes without package names: increased risk of collision between multiple entries on the classpath
(Java's inability to import package-less classes doesn't impact Kotlin)
a
try building a jar from your project and unzipping it, and looking at the contents. You’ll see all the classes and resources are smushed together in the same file structure, so that’s why resources can be relative to the class, or absolute from the root of the jar.
e
also the contents of all JARs (not just your own) are smushed together into the same structure at runtime, e.g.
kotlin-stdlib.jar
and any other dependencies you may have
a
that’s only for fat-jars, I thought?
c
no. the entire classpath is smushed together for resource loading.
e
no. given an invocation of
java -classpath foo.jar:bar.jar
, doing a
getResource("/txt")
will look for
txt
in both JARs
today i learned 1
there are APIs to enumerate duplicate resources, which makes it slightly different from the fat-jar case, but… just stick to the convention of using unique package names for every module to avoid problems.
(it's a bit different in the JPMS world, but unless OP has opted into that, it's irrelevant)
k
The Spring Boot Initializer creates an application.properties file in the resources root directory. Is this bad practice?
e
you have to follow a convention that the file is only ever provided by the application (not libraries) and there is never more than one per classpath, otherwise you get unpredictable results. so maybe ok for specific frameworks, but not for most others. I don't use Spring Boot so I don't really feel qualified to judge that case