algorand / java-algorand-sdk

Algorand SDK for Java7+ to interact with the Algorand network
https://algorand.github.io/java-algorand-sdk/
MIT License
68 stars 69 forks source link

Error serializing application transaction using the Java SDK #220

Closed winder closed 3 years ago

winder commented 3 years ago

@egieseke commented on Mon Apr 05 2021

Summary

JSON serialization issue for application transaction found in Java AlgoSDK version 1.5.1

Scope/Requirements

Serialize and deserialize an application transaction in JSON.

Urgency/Relative Priority

High. Unable to send an application transaction through a REST API using the AlgoSDK Transaction class.

Notes

In the below output, the OnCompletion code "apan" should be serialized as "UpdateApplicationOC" rather than the numeric enum value 4.

DEBUG [2021-04-05 03:55:49,017] io.dropwizard.jersey.jackson.JsonProcessingExceptionMapper: Unable to process JSON ! com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type com.algorand.algosdk.transaction.Transaction$OnCompletion from String "4": 4 was not one of [NoOpOC, OptInOC, CloseOutOC, ClearStateOC, UpdateApplicationOC, DeleteApplicationOC] ! at [Source: (org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$UnCloseableInputStream); line: 1, column: 353] (through reference chain: com.businessapp.core.service.api.transaction.dto.SignedTransactionRequest["signedTransaction"]->com.algorand.algosdk.transaction.SignedTransaction["txn"]->com.algorand.algosdk.transaction.Transaction["apan"]) 3:33 PM

{"sig":"h/la22XEvbXHKtTz6XvN0mOpeb4yS+FOr1dGISpVg0bwPCYv5IlSogYcPnRA7LPge1FketdSmkp/trC5421dBg==","txn":{"apaa":["S09aN1FUVUhFWU5CVURCTkZDQ0JNWVlQMlZWTTdCSDRSU1U1SFdKVTZVR0NMVkwzRlRXNDc1SlhUSQ=="],"apan": 4 ,"apap":"AiAFAAUBAgQmDAdDcmVhdG9yCVN0YXJ0RGF0ZQdFbmREYXRlBEdvYWwIUmVjZWl2ZXIFVG90YWwNRnVuZENsb3NlRGF0ZQZFc2Nyb3cGZG9uYXRlB3JlY2xhaW0FY2xhaW0NTXlBbW91bnRHaXZlbiIxGBJBADAoMQBnMRsjEkEBlyk2GgAXZyo2GgEXZys2GgIXZycENhoDZycFImcnBjYaBBdnJEMjMRkSQQA7KGQxABIyBycGZA8QQQFcIiRgEkABVzIEJRIzARAkEhAnBGQzAQkSEDMBCCISECcHZDMBABIQQQEyJEMhBDEZEkEAFShkMQASMRskEhBBARsnBzYaAGckQyUxGRJAAQoiMRsSQQAJJDEZEkEA/iRDNhoAJwgSQAAVNhoAJwkSQACKNhoAJwoSQABOQgDeMgcpZA8yBypkDhBBANAyBCUSMwEQJBIQQQDDJwVkMwEICDUBJwU0AWciMRgnC2NBAA8zAQgINQMiJws0A2ZCAJ8iJwszAQhmQgCVMgQlEkEAjDMBBycEZBIzAQAnB2QSEDMBCScEZBIQMgcqZA0QQQBsJwVkK2QPQQBjQgBiMgQlEkEAWTMBBzMAABIzAQAnB2QSEDIHKmQNECcFZCtkDBAzAQgzAQEIIicLYg4QQQAtMwEBMwEICCRgEjMBCTIDEhFBABkiJwtiMwEICTMBAQk1BSInCzQFZkIABCRDIkMkQw==","apid":15097190,"apsu":"AiABASI=","fee":1000,"fv":13339854,"gh":"SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=","grp":"QTvhzIOE85lvWLSdogL9zkeAhmUN8ak0Ri0s+ClB8MI=","lv":13340854,"snd":"ieS/PmcIvofUQa/G56ByQspbw/XNRS7WszQDZ0wHEqw=","type":"appl"}}

winder commented 3 years ago

@egieseke I'm not able to reproduce the error.

    @Test
    public void CreateAppCallTest() throws Exception {
        Address addr = new Address("BH55E5RMBD4GYWXGX5W5PJ5JAHPGM5OXKDQH5DC4O2MGI7NW4H6VOE4CP4");
        byte[] gh = Encoder.decodeFromBase64("SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=");

        Transaction tx = Transaction.ApplicationOptInTransactionBuilder()
                .sender(addr)
                .fee(10)
                .firstValid(322575)
                .lastValid(323575)
                .genesisHash(gh)
                .applicationId(1234L)
                .build();

        assertThat(tx.onCompletion).isEqualTo(Transaction.OnCompletion.OptInOC);

        SignedTransaction stx = DEFAULT_ACCOUNT.signTransaction(tx);

        TestUtil.serializeDeserializeCheck(tx);
        TestUtil.serializeDeserializeCheck(stx);
    }

Perhaps you need to configure dropwizards object mapper?

This is what we use:

        jsonMapper = new ObjectMapper();
        jsonMapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true);
        jsonMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true);
        jsonMapper.setSerializationInclusion(JsonInclude.Include.NON_DEFAULT);

We're also stuck on an older version of Jackson to support java 7, which could be related.

egieseke commented 3 years ago

@winder It seems that the deserializer is interpreting 4 as a string rather than an int, and not able to convert to the proper enum. Wondering why the OnCompletion enum does not follow the template of the Type enum which works?

ian-algorand commented 3 years ago

@egieseke can you still replicate this issue with and without the frameworks that you mentioned above? We need to be able to replicate it or this will likely become a not fix.

egieseke commented 3 years ago

@ian-algorand Yes, it is definitely an issue using the Jackson JSON library, which is the defacto standard for the Java community. I am working on a fix, so please don't close it. You can assign this to me if you like. Being able to serialize our objects through REST APIs is important for developers using our platform and SDKs.

winder commented 3 years ago

@egieseke as mentioned before, we're using Jackson in the SDK. In order to support Java7 we are unable to upgrade it further. Please provide an example of how to reproduce the issue.

Without an example, my suggestion is that you should use the SDK-provided helpers to serialize and deserialize according to your specific use case: