web3j
web3j copied to clipboard
Versions for Android should support @Keep Annotations to keep for instance org.web3j.crypto.WalletFile from being minified by Googles R8 compiler
Versions for Android should support @Keep Annotations to keep for instance org.web3j.crypto.WalletFile from being minified by Googles R8 compiler
Steps To Reproduce
When creating a release version of our Android App, which uses the web3j framework we experienced than some classes from web3j got minified which should not. In our example this was org.web3j.crypto.WalletFile
, where the minification caused strange wallet files to be created which could not be read externally. See attached screenshot:

Expected behavior
Some classes like org.web3j.crypto.WalletFile
should not be minified
adding some pro-guard rules for Android should resolve this situation. We added the following rule:
-keep class org.web3j.crypto.* { *; }
for you it would be better to annotate those classes with androidx.annotation.Keep
Actual behavior
minification of all classes by Google R8
Environment
Describe the environment in which the issue occurs
- Web3j version:
implementation 'org.web3j:core:4.6.0-android'
- Java or Android version
Android from API version 23 and above
- Operating System
Android
Additional context
Add any other context about the problem here.
- Logs
- Sample code and/or code snippets
- Unit/integration tests to highlight the issue
- etherscan references
Some addition:
When using web3j in a function like this:
fun getBLX01Balance(walletAddress: String, completion: (BigDecimal) -> Unit) {
doAsync {
// connect to node
val web3 = Web3j.build(HttpService(InfuraEndpoint))
val credentials: Credentials = WalletUtils.loadCredentials(getWalletPassword(), App.instance.web3WalletFile)
// TODO: get contractAddress from backend
val contractAddress = "0x45749338BDb0E35f4e36fA5741bEa0413E7322A9"
val blx01Contract: ERC20 = ERC20.load(contractAddress, web3, credentials, DefaultGasProvider())
// TODO: use own wallet address once there are BLX01 tokens on it
val weiBlx01Balance: BigInteger = blx01Contract.balanceOf("0xcfeb4b83251fb149687fa99f1c660f99411eefe3").send()
val blx01Balance: BigDecimal = Convert.fromWei(weiBlx01Balance.toString(), Convert.Unit.ETHER)
completion(blx01Balance)
}
}
I needed to add the following rules to proguard-rules.pro:
-keep class org.web3j.crypto.* { *; }
-keep class org.web3j.protocol.** { *; }
otherwise I get problems in com.fasterxml.jackson during serialization like this:
2020-07-16 01:17:38.033 21230-21827/com.bloxxter.bloxxterid E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #3
Process: com.bloxxter.bloxxterid, PID: 21230
java.lang.RuntimeException: An error occurred while executing doInBackground()
at android.os.AsyncTask$4.done(AsyncTask.java:399)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383)
at java.util.concurrent.FutureTask.setException(FutureTask.java:252)
at java.util.concurrent.FutureTask.run(FutureTask.java:271)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:289)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:919)
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.web3j.protocol.c.k and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS)
at com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(:1191)
at com.fasterxml.jackson.databind.DatabindContext.reportBadDefinition(:313)
at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.failForEmpty(:71)
at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.serialize(:33)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(:480)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(:319)
at com.fasterxml.jackson.databind.ObjectMapper._configAndWriteValue(:3906)
at com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(:3220)
at org.web3j.protocol.Service.send(:46)
at org.web3j.protocol.c.k.c(:87)
at com.bloxxter.bloxxterid.helper.l$e.e(:122)
at com.bloxxter.bloxxterid.helper.l$e.a(:27)
at com.bloxxter.bloxxterid.helper.m.a(:12)
at com.bloxxter.bloxxterid.helper.m.doInBackground(:6)
at android.os.AsyncTask$3.call(AsyncTask.java:378)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:289)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:919)
2020-07-16 01:17:38.043 21230-21808/com.bloxxter.bloxxterid E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #1
Process: com.bloxxter.bloxxterid, PID: 21230
java.lang.RuntimeException: An error occurred while executing doInBackground()
at android.os.AsyncTask$4.done(AsyncTask.java:399)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383)
at java.util.concurrent.FutureTask.setException(FutureTask.java:252)
at java.util.concurrent.FutureTask.run(FutureTask.java:271)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:289)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:919)
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.web3j.protocol.c.k and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS)
at com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(:1191)
at com.fasterxml.jackson.databind.DatabindContext.reportBadDefinition(:313)
at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.failForEmpty(:71)
at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.serialize(:33)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(:480)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(:319)
at com.fasterxml.jackson.databind.ObjectMapper._configAndWriteValue(:3906)
at com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(:3220)
at org.web3j.protocol.Service.send(:46)
at org.web3j.protocol.c.k.c(:87)
at l.d.g.e.c(:155)
at l.d.g.d.a(:134)
at l.d.g.c.b(:293)
at l.d.g.c.d(:301)
at l.d.g.c.c(:312)
at l.d.g.c.f(:400)
at l.d.g.a.call(Unknown Source:6)
at org.web3j.protocol.c.i.b(:42)
at com.bloxxter.bloxxterid.helper.l$d.e(:143)
at com.bloxxter.bloxxterid.helper.l$d.a(:27)
at com.bloxxter.bloxxterid.helper.m.a(:12)
at com.bloxxter.bloxxterid.helper.m.doInBackground(:6)
at android.os.AsyncTask$3.call(AsyncTask.java:378)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:289)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:919)
And an important hint for somebody who finds this while searching the web for Problems with ProGuard or Googles R8 when using web3j: Googles R8 manipulates the visibilities of class members! (when you allow it to do so, also, even when those classes seem to be protected by a -keep clause). I had to find it out the hard way, I debugged literally for hours until I had a clue what was going on. The default ProGuard file named proguard-android-optimize.txt
which will be used by this clause proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
in your standard projects build.gradle
contains a clause -allowaccessmodification
which causes the serialization of Request
to run havoc:
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class com.fasterxml.jackson.databind.util.LRUMap and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: org.web3j.protocol.core.Request["web3jService"]->org.web3j.protocol.http.HttpService["objectMapper"]->com.fasterxml.jackson.databind.ObjectMapper["_deserializationConfig"]->com.fasterxml.jackson.databind.DeserializationConfig["_base"]->com.fasterxml.jackson.databind.cfg.BaseSettings["_classIntrospector"]->com.fasterxml.jackson.databind.introspect.BasicClassIntrospector["_cachedFCA"])
at com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(:1191)
at com.fasterxml.jackson.databind.DatabindContext.reportBadDefinition(:313)
at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.failForEmpty(:71)
at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.serialize(:33)
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(:727)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(:719)
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(:155)
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(:727)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(:719)
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(:155)
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(:727)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(:719)
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(:155)
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(:727)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(:719)
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(:155)
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(:727)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(:719)
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(:155)
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(:727)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(:719)
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(:155)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(:480)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(:319)
at com.fasterxml.jackson.databind.ObjectMapper._configAndWriteValue(:3906)
at com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(:3220)
at org.web3j.protocol.Service.send(:46)
at org.web3j.protocol.core.Request.send(:87)
morale of the story: Don't use proguard-android-optimize.txt
when building Android-Apps with web3j. Better use a copy of this file where you remove the -allowaccessmodification
clause.
Good luck!
I've been testing confusing code for three days. I didn't expect this. Thank you
remove -allowaccessmodification
from proguard-android-optimize.txt (copy)
It's work , Thank for solution
https://android.googlesource.com/platform/sdk/+/master/files/proguard-android-optimize.txt