How to register a custom serializer for chaincode in Hyperledger Fabric
Recently, I come across an issue where Fabric chaincode throws a NullPointerException
as follows when try to return an ArrayList<String>
org.hyperledger.fabric.Logger error nulljava.lang.NullPointerException
at org.hyperledger.fabric.contract.execution.JSONTransactionSerializer.toBuffer(JSONTransactionSerializer.java:84)
at org.hyperledger.fabric.contract.execution.impl.ContractExecutionService.convertReturn(ContractExecutionService.java:89)
at org.hyperledger.fabric.contract.execution.impl.ContractExecutionService.executeRequest(ContractExecutionService.java:67)
at org.hyperledger.fabric.contract.ContractRouter.processRequest(ContractRouter.java:119)
at org.hyperledger.fabric.contract.ContractRouter.invoke(ContractRouter.java:130)
at org.hyperledger.fabric.shim.impl.ChaincodeInvocationTask.call(ChaincodeInvocationTask.java:100)
at org.hyperledger.fabric.shim.impl.InvocationTaskManager.lambda$newTask$17(InvocationTaskManager.java:265)
at java.base/java.util.concurrent.CompletableFuture$AsyncRun.run(CompletableFuture.java:1736)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
As I understand this happens due to the default JSONTransactionSerializer
cannot handle my return type. Thus, I had to find a way to implement my own Serializer to cater my requirement.
After some googling, it seems there is a SerializerInterface (org.hyperledger.fabric.contract.execution.SerializerInterface
) that need to be implemented according to the according to [FAB-15634] Implement Interface/annotation for the serializer — Hyperledger JIRA. However, I couldn’t find any documentation on how to register the custom serializer so that chaincode can use the custom serializer instead of the default one. Checking on the Serializer PR [FAB-15634] Annotations for Serializer by mbwhite · Pull Request #41 · hyperledger/fabric-chaincode-java · GitHub I realised how to register the custom implementation.
What you have to do is use the transactionSerializer
attribute with the Contract
annotation
Sample code
Implement the SerializerInterface and create the Serializer
import org.hyperledger.fabric.contract.annotation.Serializer;
import org.hyperledger.fabric.contract.execution.SerializerInterface;
import org.hyperledger.fabric.contract.metadata.TypeSchema;
@Serializer()
public class CustomSerializer implements SerializerInterface {
@Override
public byte[] toBuffer(Object value, TypeSchema ts) {
...
}
@Override
public Object fromBuffer(byte[] buffer, TypeSchema ts) {
...
}
}
Register the Serializer with the contract
@Contract(
name = "HelloHyper",
transactionSerializer = "org.contract.CustomSerializer"
)
@Default
public class InverterContract implements ContractInterface {