hashgraph / hedera-sdk-java

Hedera™ Hashgraph SDK for Java
https://docs.hedera.com/guides/docs/sdks
Apache License 2.0
231 stars 120 forks source link

Hedera Java SDK protobuf-javalite dependency incompatible with important GCP libraries like secrets manager #1024

Closed robkainz closed 2 years ago

robkainz commented 2 years ago

Description

I'm not able to start my spring boot server in a Google Cloud environment after upgrading to a recent Hedera SDK (2.14.0-beta.1 was used at the time, but I am quite sure the problem still exists with the latest SDK.) I first noticed the problem when some unit tests failed.

@gregscullard quickly determined that the reason was protobuf-javalite is incompatible with Google's google-cloud-secretmanager:2.0.2, which we heavily depend on, and I imagine others will as well.

According to this discussion Greg sent to me, protobuf-javalite was only meant to be used in an Android environment, though I don't think that is 100% confirmed. However, it is clear from Google's documentation according to the discussion that it is not usable with GCP libraries:

https://github.com/GoogleCloudPlatform/cloud-opensource-java/issues/587

Here is the specific exception I saw when starting up my server on Google Cloud:

nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [java.lang.String]: Factory method 'operatorMainnetPrivateKey' threw exception; nested exception is java.lang.NoClassDefFoundError: io/grpc/CallCredentials2
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:799)
    at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:228)
    at
  ...

Here is the exception I saw when running my unit tests, this specific one simply moves hbar from my testnet faucet account to the one I use for testing:

  java.lang.VerifyError: Bad type on operand stack
Exception Details:
  Location:
    com/hedera/hashgraph/sdk/proto/TokenTransferList.mergeExpectedDecimals(Lcom/google/protobuf/UInt32Value;)V @31: invokevirtual
  Reason:
    Type 'com/google/protobuf/UInt32Value' (current frame, stack[2]) is not assignable to 'com/google/protobuf/GeneratedMessageLite'
  Current Frame:
    bci: @31
    flags: { }
    locals: { 'com/hedera/hashgraph/sdk/proto/TokenTransferList', 'com/google/protobuf/UInt32Value' }
    stack: { 'com/hedera/hashgraph/sdk/proto/TokenTransferList', 'com/google/protobuf/UInt32Value$Builder', 'com/google/protobuf/UInt32Value' }

Part of the stack trace showing that it is a protobuf dependency issue:

at java.base/java.lang.Class.forName0(Native Method)
    at java.base/java.lang.Class.forName(Class.java:398)
    at com.google.protobuf.GeneratedMessageLite.getDefaultInstance(GeneratedMessageLite.java:299)
    at com.google.protobuf.GeneratedMessageInfoFactory.messageInfoFor(GeneratedMessageInfoFactory.java:58)

I suspect that lite version of protobuf dependency for the Hedera sdk must be replaced with the full version.

Steps to reproduce

  1. Write a Junit test case that sends some hbar from one account to another in a simple spring boot application.
  2. Add the following dependency to your build.gradle file: implementation 'com.google.cloud:google-cloud-secretmanager:2.0.2'
  3. Compile and run the unit test.

Additional context

No response

Hedera network

mainnet, testnet

Version

2.14.0-beta.1

Operating system

macOS

robkainz commented 2 years ago

I tried modifying the dependency resolution in my gradle file, but wasn't able to get it to work. Here's one of the things I tried:

configurations.all { resolutionStrategy.eachDependency { DependencyResolveDetails details -> if ( details.requested.group == "com.google.protobuf" && details.requested.name == "protobuf-javalite" ) { details.useTarget("com.google.protobuf:protobuf-java:3.21.1") } } }

janaakhterov commented 2 years ago

As mentioned in the PR, I don't know if we really can change this dependency because it's a breaking change.

gregscullard commented 2 years ago

Could we publish an alternative SDK which doesn't use protobuf lite as an alternative ? Or, can you suggest a work around with the gradle configuration to resolve the conflict ?