Search code examples
javagsonretrofit2

Java module doesn't find package


I use Retrofit 2 for an API that I made, and I use Retrofit Gson to convert the API response to an object. I have a package with my JSON models (as a class) and I need Gson to access to those models.

When I add the line to open the package for Gson, I get an error on the building saying that they can't access to the package. I tried to open for the package above (that I know work because javafx.fxml uses it), but then I get this error (not on the building, but when I use Gson while running)

Exception in thread "DefaultDispatcher-worker-2" java.lang.IllegalArgumentException: Unable to create converter for class fr.plaglefleau.banksystemdesktop.api.models.bankapi.response.get.LoginResponse
    for method BankApi.login
    at [email protected]/retrofit2.Utils.methodError(Utils.java:56)
    at [email protected]/retrofit2.HttpServiceMethod.createResponseConverter(HttpServiceMethod.java:139)
    at [email protected]/retrofit2.HttpServiceMethod.parseAnnotations(HttpServiceMethod.java:97)
    at [email protected]/retrofit2.ServiceMethod.parseAnnotations(ServiceMethod.java:39)
    at [email protected]/retrofit2.Retrofit.loadServiceMethod(Retrofit.java:235)
    at [email protected]/retrofit2.Retrofit$1.invoke(Retrofit.java:177)
    at jdk.proxy2/com.sun.proxy.jdk.proxy2.$Proxy6.login(Unknown Source)
    at [email protected]/fr.plaglefleau.banksystemdesktop.SignInController$signIn$1.invokeSuspend(SignInController.kt:95)
    at kotlin.stdlib/kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
    at kotlinx.coroutines.core/kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:108)
    at kotlinx.coroutines.core/kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:589)
    at kotlinx.coroutines.core/kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:806)
    at kotlinx.coroutines.core/kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:710)
    at kotlinx.coroutines.core/kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:697)
    Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}@5216989, Dispatchers.Default]
Caused by: com.google.gson.JsonIOException: Failed making field 'fr.plaglefleau.banksystemdesktop.api.models.bankapi.response.get.LoginResponse#message' accessible; either increase its visibility or write a custom TypeAdapter for its declaring type.
    at [email protected]/com.google.gson.internal.reflect.ReflectionHelper.makeAccessible(ReflectionHelper.java:38)
    at [email protected]/com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:286)
    at [email protected]/com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:130)
Caused by: com.google.gson.JsonIOException: Failed making field 'fr.plaglefleau.banksystemdesktop.api.models.bankapi.response.get.LoginResponse#message' accessible; either increase its visibility or write a custom TypeAdapter for its declaring type.

    at [email protected]/com.google.gson.Gson.getAdapter(Gson.java:556)
    at [email protected]/retrofit2.converter.gson.GsonConverterFactory.responseBodyConverter(GsonConverterFactory.java:64)
    at [email protected]/retrofit2.Retrofit.nextResponseBodyConverter(Retrofit.java:418)
    at [email protected]/retrofit2.Retrofit.responseBodyConverter(Retrofit.java:401)
    at [email protected]/retrofit2.HttpServiceMethod.createResponseConverter(HttpServiceMethod.java:137)
    ... 12 more
Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make field private final java.lang.String fr.plaglefleau.banksystemdesktop.api.models.bankapi.response.get.LoginResponse.message accessible: module fr.plaglefleau.banksystemdesktop does not "opens fr.plaglefleau.banksystemdesktop.api.models.bankapi.response.get" to module com.google.gson
    at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354)
Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make field private final java.lang.String fr.plaglefleau.banksystemdesktop.api.models.bankapi.response.get.LoginResponse.message accessible: module fr.plaglefleau.banksystemdesktop does not "opens fr.plaglefleau.banksystemdesktop.api.models.bankapi.response.get" to module com.google.gson

    at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)
    at java.base/java.lang.reflect.Field.checkCanSetAccessible(Field.java:178)
    at java.base/java.lang.reflect.Field.setAccessible(Field.java:172)
    at [email protected]/com.google.gson.internal.reflect.ReflectionHelper.makeAccessible(ReflectionHelper.java:35)
    ... 19 more

here is my module-info.java

module fr.plaglefleau.banksystemdesktop {
    requires javafx.controls;
    requires javafx.fxml;
    requires kotlin.stdlib;
    requires TranslationLibrary.main;
    requires kotlinx.coroutines.core;
    requires org.jetbrains.annotations;
    requires retrofit2;
    requires retrofit2.converter.gson;
    requires com.google.gson;

    opens fr.plaglefleau.banksystemdesktop to javafx.fxml, retrofit2.converter.gson;
    exports fr.plaglefleau.banksystemdesktop;
}

I push the project on GitHub, here is the link


Solution

  • Regarding the Package ... not found in module error you are seeing after updating module-info.java:
    The problem is most likely that your project consists of Java and Kotlin code, and the package you want to open is part of the Kotlin code.

    You can probably solve this by either:

    • Adjusting your build.gradle so that the compileJava task can see the Kotlin classes, see the Kotlin documentation
    • Opening your complete module to all other modules for reflection, instead of individual packages. See also the related question: Can a module-info.java 'opens' statement include a package and all sub-packages?
      That is, change your module-info.java and remove opens ... to ...; and instead write open module:
      open module fr.plaglefleau.banksystemdesktop {
          requires ...
      }
      
      See also Understanding Java 9 Modules. This could however make troubleshooting more difficult when Gson or another library by accident uses reflection on a class from one of your packages which you did not actually want to open.

    Note that Gson is mainly designed for Java. It might work for some Kotlin features, but not for all (e.g. nullability is not considered). Since your model classes are written in Kotlin, it might be better to use a JSON library with explicit Kotlin support, for example https://github.com/square/moshi and corresponding Retrofit converter.