But May there is a way to avoid creating a class
# announcements
m
But May there is a way to avoid creating a class
c
ClassLoader.getSystemClassLoader().getResource("/path/to/resource/")
or
ClassLoader.getSystemResourceAsStream("/path/to/resource")
m
Thank you
Seems it's deeper issue
Copy code
java.lang.IllegalStateException: ClassLoader.getSystemCla…Loader().getResource(url) must not be null
i've posted code to the channel
c
huh, checked locally, indeed system class loader is null... that's strange.
g
You can use something like Thread.currentThread().classloader, but be careful you will get classloader of thread, it's not always the same as classloader of your function.
More safe something like
object {}.classloader
, but to be honest always used currentThread instead, I don't have such complicated classloader cases
m
object {}.classloader
Should it be called in inline func?
c
Or something like this 🙂
Copy code
object resourceAsStream {
	operator fun invoke(path: String) : InputStream = javaClass.getResourceAsStream(path)
}

fun <T> fromYamlList(resourceStream: InputStream): List<T> {
	TODO("You'll have to implement this")
}

inline fun <reified T> fromTestDataYamlList(url: String): List<T> {
	return fromYamlList(resourceAsStream("/path/to/resource/in/the/classpath"))
}
m
@Czar Thanks, it's work=) Could you please explain me (or what point to docs=)) about
Copy code
object resourceAsStream {
    operator fun invoke(path: String) : InputStream = javaClass.getResourceAsStream(path)
}
The instance of this object is used to get the class where it is invoked
Am I right?
c
Object is a singleton, so we have a class and its instance in one,
javaClass
is roughly analogous to java's
this.getClass()
and
operator fun invoke
to make it look good 🙂 Read about it here: https://kotlinlang.org/docs/reference/operator-overloading.html#invoke
m
Could it somehow lead to issues in multithreaded env?
c
if you're asking can you call this from several parallel threads, then there should be no problems, the
resourceAsStream
object does not contain state, and
invoke
is a function which does it job based on input and returns its result as output, without keeping state in the instance.
m
Thank you fro clarifications
😉 1
g
But this solution with
object
has the same problem as currentThread. You will get resource from classloader of an object who created this object (in this case who first used this object), not from classloader of your function. But in most cases it's not a big problem
1
m
As I understand object object ResourcePath will be created every time when I access
inline fun <reified T> fromTestDataYamlList
It means that we get resource path every time when its called
Thread A called inline func and ResourcePath returns path of the class from thread A Thread B called inline func and ResourcePath returns path of the class from thread B
g
No, it will be created once
Please read documentation of
object
declaration
But you can create an object each time in function to get "fair" classloader
Less efficient, but more correct and safe
m
do you mean creating object instance in inline function?
Copy code
class ResourcePath {
    operator fun invoke(path: String): String = javaClass.getResource(path).path
}

inline fun <reified T> fromTestDataYamlList(url: String): ArrayList<T> {
return fromYamlList(ResourcePath().invoke("/testData$url"))
}
Strange code=)
g
Why,?
You don't need invoke, just use proper function name instead
m
I mean a bit overcomplicated
g
operator fun invoke -> fun loadResource
m
Copy code
class Resources {
    fun getPath(path: String): String = javaClass.getResource(path).path
}

inline fun <reified T> fromTestDataYamlList(url: String): ArrayList<T> {
    return fromYamlList(Resources().getPath("/testData$url"))
}
Thank you for your time
g
Not sure that you need reified in this particular case
Reified make sense only when you need instance of generic
m
I need it in
fromYamlList
I parse Yaml to different Objects
g
Oh, I see, yeah
m
Copy code
fromTestDataYamlList<UserInfo>("/user/request/addUsers.yaml")
<UserInfo> it's changes
g
Make sense, to parse yaml to Kotlin class
m
😃
Thank you one more time)
g
👍
c
Actually, it's even easier if you absolutely want to have new object on each invocation:
Copy code
inline fun getPath(url: String) = object {}.javaClass.getResource("/testData$url").path

inline fun <reified T> fromTestDataYamlList(url: String): ArrayList<T> {
   return fromYamlList(getPath(url))
}