Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

some crashes with missing virtual method #977

Closed
chk2902 opened this issue Dec 18, 2024 · 10 comments
Closed

some crashes with missing virtual method #977

chk2902 opened this issue Dec 18, 2024 · 10 comments

Comments

@chk2902
Copy link

chk2902 commented Dec 18, 2024

Some customers of mine start to experience problems with the following stack trace:

STACK_TRACE=java.lang.NoSuchMethodError: No virtual method error(Ljava/lang/Exception;)Lcom/github/kittinunf/result/Result$Failure; in class Lcom/github/kittinunf/result/Result$Companion; or its super classes (declaration of 'com.github.kittinunf.result.Result$Companion' appears in base.apk!classes3.dex) at com.github.kittinunf.fuel.core.DeserializableKt.response(Deserializable.kt:171) at com.github.kittinunf.fuel.core.requests.DefaultRequest.responseObject(DefaultRequest.kt:490) at com.chk.go_elocal.database.flextariff.provider.Tibber.updateStatistics(Tibber.java:201)
caused as you can see by the call of the "request.responseObject" in Java code:

Triple<Request, Response, Result<FuelJson, FuelError>> result = request.responseObject(FuelJsonKt.jsonDeserializer()); Result<FuelJson, FuelError> responseResult = result.getThird();

Version is the current stable version 2.3.1, and it just happens in release builds (on Android).

implementation 'com.github.kittinunf.result:result:5.6.0' implementation "com.github.kittinunf.fuel:fuel:$fuel_version" implementation "com.github.kittinunf.fuel:fuel-android:$fuel_version" implementation "com.github.kittinunf.fuel:fuel-json:$fuel_version"
Strange: The same call works (in some other class) for the same customers when I use a full object path:

Triple<Request, Response, com.github.kittinunf.result.Result<FuelJson, FuelError>> result = request.responseObject(FuelJsonKt.jsonDeserializer()); com.github.kittinunf.result.Result<FuelJson, FuelError> responseResult = result.getThird();
although the "import" in the other class file has the same path.

Does anybody know what could be the reason? Ther was a gradle update at the end of november, but actually I don't know the build process good enough to know whether something like that could cause it...

@chk2902
Copy link
Author

chk2902 commented Dec 18, 2024

BTW: I did not change the Fuel version for a long time, so I guess it will be something in the build process.

Strange is: it works when it's called "manually" (called by a one-time Worker process), but (at least sometimes) it does not work in a scheduled Worker process.

Other idea: can it be that that "missing" method is called when there's a problem with the data passed to it, and I cannot reproduce it (and it has that strange pattern) as the data I get does not have that problem?

@iNoles
Copy link
Collaborator

iNoles commented Jan 5, 2025

Whenever NoSuchMethodError or similar problems come up, it's usually one of two things:

  1. A build problem where the build system uses incompatible intermediate files to building the apk. You can try to fix this (or exclude it as the reason) by fully cleaning your project in Android Studio ("Build -> Clean project") and also running "File -> Invalidate Caches".
  2. An unintended version upgrade of another dependent library that also uses Result or Fuel. Based on your description, this is the likely reason. Gradle updates all Fuel versions in the entire dependency tree to the same version. You can check what gradle is doing by running ./gradlew yourAppGradleTarget:dependencies.

@bentrnr21
Copy link

Hi, The crashes due to missing virtual methods are concerning. Could you provide more context on the environments and scenarios where these crashes occur? I’m willing to help investigate and resolve these issues to improve Fuel’s stability.

Thank you

@chk2902
Copy link
Author

chk2902 commented Mar 11, 2025

Well it has not happened any more, so I (hope/guess) it was a problem of dependencies, although I did numerous "Cleans" and other more or less duious attempts, and it happened in the same code (!) of a Worker process, just the way it being called (one-time or periodic) was the problem - left me wondering. It is too long ago to know what I did to make it work, my memory is short-term and tasks are getting "lost" once solved.

I will get back to you when I experience it again - assume the case as closed for the moment.

@chk2902
Copy link
Author

chk2902 commented Mar 11, 2025

Oh, you won't believe it... it just came in: I just got a mail of a customer with that problem:

07:07:59.101 32225: .database.flextariff.provider.Tibber@4dfb94e: java.lang.NoSuchMethodError: No virtual method error(Ljava/lang/Exception;)Lcom/github/kittinunf/result/Result$Failure; in class Lcom/github/kittinunf/result/Result$Companion; or its super classes (declaration of 'com.github.kittinunf.result.Result$Companion' appears in base.apk!classes4.dex)
	at com.github.kittinunf.fuel.core.DeserializableKt.response(Deserializable.kt:171)
	at com.github.kittinunf.fuel.core.requests.DefaultRequest.responseObject(DefaultRequest.kt:490)
	at com.chk.go_elocal.database.flextariff.provider.Tibber.updateDataIfNeeded(Tibber.java:379)
	at com.chk.go_elocal.database.flextariff.FlexTariffProvider.updateDataForced(FlexTariffProvider.java:361)
	at com.chk.go_elocal.database.flextariff.FlexTariffProvider.computeData(FlexTariffProvider.java:1292)
	at com.chk.go_elocal.database.flextariff.FlexTariffProvider.computeData(FlexTariffProvider.java:1213)
	at com.chk.go_elocal.database.flextariff.FlexTariffProvider.getCurrentInterval(FlexTariffProvider.java:2050)
	at com.chk.go_elocal.devices.grid.Grid_State_Proxy.toStringForLogging(Grid_State_Proxy.java:590)
	at com.chk.go_elocal.service.MainService.onGridmeterData(MainService.java:2573)
	at com.chk.go_elocal.server.GridmeterServer.updateInfo(GridmeterServer.java:471)
	at com.chk.go_elocal.server.GridmeterServer.onGridmeterQueryStatusResponse(GridmeterServer.java:427)
	at com.chk.go_elocal.devices.grid.Connection_Base_Modbus$2.run(Connection_Base_Modbus.java:581)
	at android.os.Handler.handleCallback(Handler.java:938)
	at android.os.Handler.dispatchMessage(Handler.java:99)
	at android.os.Looper.loop(Looper.java:246)
	at android.app.ActivityThread.main(ActivityThread.java:8653)
	at java.lang.reflect.Method.invoke(Native Method)
	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602)
	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130)

And now I remember: it happens when there's a failure in the call (here: too many calls, log says:

429 Too Many Requests
headers:
message:
 Too many requests. Your IP is now temporarily banned for calling API for a few minutes.

Is it that I expect a JSON object as result and I get a string?

@chk2902
Copy link
Author

chk2902 commented Mar 11, 2025

The code I use is

            Request request =
                    getFuelManager(this.getClass())
                            .post(url, null)
                            .appendHeader(Headers.CONTENT_TYPE, "application/json")
                            .appendHeader(Headers.AUTHORIZATION, "Bearer " + token)
                            .body(body, StandardCharsets.US_ASCII);

            try
                {
                Triple<Request, Response, com.github.kittinunf.result.Result<FuelJson, FuelError>> result         = request.responseObject(FuelJsonKt.jsonDeserializer());
                com.github.kittinunf.result.Result<FuelJson, FuelError>                            responseResult = result.getThird();

                if (responseResult != null)
                    {
                    FuelJson oResult = responseResult.get();

                    return onDataRequestResponse(home, providerId, connectionReliabilityNotifier, oResult.obj(), responseResult.component2());
                    }
                }
            catch (Throwable e)
                {
                CLogUtils.LogExceptionNoThrow(this, e);
                }

@iNoles
Copy link
Collaborator

iNoles commented Mar 15, 2025

The code I use is

            Request request =
                    getFuelManager(this.getClass())
                            .post(url, null)
                            .appendHeader(Headers.CONTENT_TYPE, "application/json")
                            .appendHeader(Headers.AUTHORIZATION, "Bearer " + token)
                            .body(body, StandardCharsets.US_ASCII);

            try
                {
                Triple<Request, Response, com.github.kittinunf.result.Result<FuelJson, FuelError>> result         = request.responseObject(FuelJsonKt.jsonDeserializer());
                com.github.kittinunf.result.Result<FuelJson, FuelError>                            responseResult = result.getThird();

                if (responseResult != null)
                    {
                    FuelJson oResult = responseResult.get();

                    return onDataRequestResponse(home, providerId, connectionReliabilityNotifier, oResult.obj(), responseResult.component2());
                    }
                }
            catch (Throwable e)
                {
                CLogUtils.LogExceptionNoThrow(this, e);
                }

I think it is expecting FuelError but you expect it to be JSON. Why are you not using success {} and failure {}?

@chk2902
Copy link
Author

chk2902 commented Mar 16, 2025

If I knew how to (I use Java, and that code is Kotlin ;)

I found no way to do this - can I define multiple handlers for these 2 error result types (string and json), and if yes, how? Could you please help me? Do you mean

                request.response(new ResponseHandler<byte[]>()
                    {
                    @Override
                    public void success(@NonNull Request request, @NonNull Response response, byte[] bytes)
                        {
                        
                        }

                    @Override
                    public void failure(@NonNull Request request, @NonNull Response response, @NonNull FuelError fuelError)
                        {

                        }
                    });

and switch upon the contents of the byte[] which handler to use (synchroneous?)? Which is the preferred way to handle this problem?

@iNoles
Copy link
Collaborator

iNoles commented Mar 16, 2025

If I knew how to (I use Java, and that code is Kotlin ;)

I found no way to do this - can I define multiple handlers for these 2 error result types (string and json), and if yes, how? Could you please help me? Do you mean

                request.response(new ResponseHandler<byte[]>()
                    {
                    @Override
                    public void success(@NonNull Request request, @NonNull Response response, byte[] bytes)
                        {
                        
                        }

                    @Override
                    public void failure(@NonNull Request request, @NonNull Response response, @NonNull FuelError fuelError)
                        {

                        }
                    });

and switch upon the contents of the byte[] which handler to use (synchroneous?)? Which is the preferred way to handle this problem?

I believe it is only one handler at a time. The both handlers should be synchronous.

@chk2902
Copy link
Author

chk2902 commented Mar 28, 2025

I think I worked it out.

@chk2902 chk2902 closed this as completed Mar 28, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants