Steps to reproduce
- Try to load the following JSON configuration using ExternalAccountCredentials.fromStream()
{
"service_account_impersonation_url": null, //optional field, would be similar with any other
"audience": "audience",
"subject_token_type": "subjectTokenType",
"credential_source": {"file":"file"}
}
Code example
ExternalAccountCredentials credentials = ExternalAccountCredentials.fromStream(
new ByteArrayInputStream(("""
{\
"service_account_impersonation_url": null,\
"audience": "audience",\
"subject_token_type": "subjectTokenType",\
"credential_source": {"file":"file"}\
}""").getBytes()));
Stack trace
com.google.auth.oauth2.CredentialFormatException: An invalid input stream was provided.
at com.google.auth.oauth2.ExternalAccountCredentials.fromStream(ExternalAccountCredentials.java:398)
at com.google.auth.oauth2.ExternalAccountCredentials.fromStream(ExternalAccountCredentials.java:366)
at com.google.auth.oauth2.ExternalAccountCredentialsTest.fromStream_nullOptionalField(ExternalAccountCredentialsTest.java:153)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:232)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:55)
Caused by: java.lang.ClassCastException: class java.lang.Object cannot be cast to class java.lang.String (java.lang.Object and java.lang.String are in module java.base of loader 'bootstrap')
at com.google.auth.oauth2.ExternalAccountCredentials.fromJson(ExternalAccountCredentials.java:422)
at com.google.auth.oauth2.ExternalAccountCredentials.fromStream(ExternalAccountCredentials.java:396)
... 28 more
Any additional information below
This is caused by com.google.api.client.json.JsonParser used to parse the JSON payload.
This implementation does not deserializes null JSON value to null reference in Java, instead using magic null objects from com.google.api.client.util.Data => this causes this ClassCastException when trying to deserialize, as the magic object can't be cast to the expected field type.
The current behavior does not follow the principle of least astonishment, that be that a null value for a specific optional field in JSON configuration is just considered as missing.
This issue is likely to happen for other types of JSON credential configuration that have optional values.
Steps to reproduce
{ "service_account_impersonation_url": null, //optional field, would be similar with any other "audience": "audience", "subject_token_type": "subjectTokenType", "credential_source": {"file":"file"} }Code example
Stack trace
Any additional information below
This is caused by com.google.api.client.json.JsonParser used to parse the JSON payload.
This implementation does not deserializes null JSON value to null reference in Java, instead using magic null objects from com.google.api.client.util.Data => this causes this ClassCastException when trying to deserialize, as the magic object can't be cast to the expected field type.
The current behavior does not follow the principle of least astonishment, that be that a null value for a specific optional field in JSON configuration is just considered as missing.
This issue is likely to happen for other types of JSON credential configuration that have optional values.