CyberSource / cybersource-rest-client-java

Java client library for the CyberSource REST API
Other
17 stars 42 forks source link

TransactionDetailsApi.getTransaction "declares multiple JSON fields named next" error #111

Open DanDodin-SRPMIC opened 2 years ago

DanDodin-SRPMIC commented 2 years ago

When I call TransactionDetailsApi.getTransaction I receive an error. This error can be reproduced using samples.TransactionDetails.RetrieveTransaction from cybersource-rest-samples-java. The error message below is from the rest samples call. I am using cybersource-rest-client-java version 0.0.46.

java.lang.IllegalArgumentException: jdk.internal.ref.PhantomCleanable<?> declares multiple JSON fields named next at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:172) at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:102) at com.google.gson.Gson.getAdapter(Gson.java:489) at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.createBoundField(ReflectiveTypeAdapterFactory.java:117) at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:166) at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:102) at com.google.gson.Gson.getAdapter(Gson.java:489) at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:56) at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:127) at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:245) at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:69) at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:127) at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:245) at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:69) at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:127) at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:245) at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:69) at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:127) at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:245) at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:69) at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:127) at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:245) at com.google.gson.Gson.toJson(Gson.java:735) at com.google.gson.Gson.toJson(Gson.java:714) at com.google.gson.Gson.toJson(Gson.java:669) at com.google.gson.Gson.toJson(Gson.java:649) at Invokers.JSON.serialize(JSON.java:83) at Invokers.ApiClient.execute(ApiClient.java:1204) at Api.TransactionDetailsApi.getTransactionWithHttpInfo(TransactionDetailsApi.java:159) at Api.TransactionDetailsApi.getTransaction(TransactionDetailsApi.java:144) at samples.TransactionDetails.RetrieveTransaction.run(RetrieveTransaction.java:42) at samples.TransactionDetails.RetrieveTransaction.main(RetrieveTransaction.java:26)

MrForms commented 1 year ago

Invokers.ApiClient uses a new JSON(this), which in turns creates a GSON instance using a GsonBuilder that does not use 'excludeFieldsWithoutExposeAnnotation'.

At some point it will therefore rely on some form of reflection and hit classes such as collections, or other complex objects that might expose the same method name through out the inheritance hierarchy.

Perhaps the workaround would simply be to add the .excludeFieldsWithoutExposeAnnotation() method to the GsonBuilder line in the JSON constructor class, assuming you can add @Expose

DanDodin-SRPMIC commented 1 year ago

I don't think adding .excludeFieldsWithoutExposeAnnotation() will work. Class TssV2TransactionsGet200Response is autogenerated from swagger. The GSON @Expose annotation is not added to fields.

As a work around I am using Jackson instead of GSON to parse the response in my code. Replaced: TssV2TransactionsGet200Response resp = apiInstance.getTransaction(transactionNumber);

With:

Call call = apiInstance.getTransactionCall(transactionNumber, null, null);
Response response = call.execute();
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
TssV2TransactionsGet200Response resp =
    objectMapper.readValue(response.body().bytes(), TssV2TransactionsGet200Response.class);
MrForms commented 1 year ago

@DanDodin-SRPMIC Good point. Was thinking that the @Expose could be added, but that would mean updating the definitions of the response objects for swagger.

I ended up hacking the ApiClient to specify my own JSON instance and just overrode the serialize method to use Jackson like you suggested. That worked.

Thanks!