ic4j-agent icon indicating copy to clipboard operation
ic4j-agent copied to clipboard

Using outArgs.getArgs().get(0).getValue().toString(), but get a wrong value

Open shadow-001 opened this issue 3 years ago • 4 comments

I use outargs getArgs(). get(0). getValue(). Tostring() gets the result and refers to Querytest. However, the final data obtained is inconsistent with the data recorded in canisters.

QyeryTest: image

canister response: image

java result: image

shadow-001 avatar Jun 10 '22 04:06 shadow-001

Thank you for reporting this issue. Let me check your use case and fix the problem.

rdobrik avatar Jun 10 '22 06:06 rdobrik

Can you please share with me IDL of the canister you are calling from Java?

rdobrik avatar Jun 10 '22 12:06 rdobrik

export const idlFactory = ({ IDL }) => {

  const CanisterSettings = IDL.Record({
    'controller' : IDL.Opt(IDL.Principal),
    'freezing_threshold' : IDL.Opt(IDL.Nat),
    'controllers' : IDL.Opt(IDL.Vec(IDL.Principal)),
    'memory_allocation' : IDL.Opt(IDL.Nat),
    'compute_allocation' : IDL.Opt(IDL.Nat),
  });
  const CreateCanisterArgs = IDL.Record({
    'cycles' : IDL.Nat64,
    'settings' : CanisterSettings,
  });
  const Result = IDL.Variant({ 'Ok' : IDL.Principal, 'Err' : IDL.Text });

  return IDL.Service({
    'create_canister' : IDL.Func([CreateCanisterArgs], [Result], []),
  });
};
export const init = ({ IDL }) => { return []; };

shadow-001 avatar Jun 11 '22 11:06 shadow-001

Aah, you are returning Variant type, which wraps Principal value. In such case we are wrapping variant elements as a Java map type. So you have to get Ok item from the Map. I added Variant test echoVariant in our ICTest JUnit test (already checked in). It handles Variant Result similar to yours

type Result = {
    #Ok : Principal;
    #Err : Text;
};

So you get value as a Map and then you retrieve Principal value.

byte[] queryOutput = queryResponse.get();
IDLArgs outArgs = IDLArgs.fromBytes(queryOutput);
					
Map<Label, Object> mapResult = outArgs.getArgs().get(0).getValue();
					
if(mapResult.containsKey(Label.createNamedLabel("Ok")))
{
	Principal principalResult = (Principal) mapResult.get(Label.createNamedLabel("Ok"));
	LOG.info(principalResult.toString());
	Assertions.assertEquals(principalValue, principalResult);
}

We also serializing and deserializing IC variants to Java Enum type. You can find the sample in our Internet Identity package.

https://github.com/ic4j/ic4j-internetidentity/blob/master/src/test/java/org/ic4j/internetidentity/test/InternetIdenityTest.java

rdobrik avatar Jun 11 '22 14:06 rdobrik