-
Notifications
You must be signed in to change notification settings - Fork 155
Replace jackson-databind with azure-json in HTTP response classes #918
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
| //This method is used to convert a JSON string to an object which implements the JsonSerializable interface from com.azure.json | ||
| static <T extends JsonSerializable<T>> T convertJsonStringToJsonSerializableObject(String jsonResponse, Class<T> tClass) { | ||
| try (JsonReader jsonReader = JsonProviders.createReader(jsonResponse)) { | ||
| return (T) tClass.getDeclaredMethod("fromJson", JsonReader.class).invoke(null, jsonReader); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is all this reflection ok for apps consuming our libs? In .NET at least, reflection is frawned upon because it stops the AOT linker from doing its job. It's also slow.
JSON libraries prefer to use a "source generation" approach which avoids reflection and is faster.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The first version I had simply had the same try/catch clause in a lot of places, and to avoid duplicate code I tried this approach.
However, ease of debugging is a concern (that's part of the reason we're even doing this), and since this JSON parsing could happen on every request it might slow them down. I'll do some more research/testing to see if there's a better approach (sending a lambda?), and if not I'll go back to directly calling that "fromJson" method in various places.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should be able to remove reflection by making a few changes here:
- Change the method parameters to:
static <T extends JsonSerializable<T>> T convertJsonStringToJsonSerializableObject(String jsonResponse, ReadValueCallback<JsonReader, T> readFunction)You know at calling time what T will be.
- Change the try-with-resources block to:
try (JsonReader jsonReader = JsonProviders.createReader(jsonResponse)) {
return readFunction.read(jsonReader);
}- Change the caller to:
JsonHelper.convertJsonStringToJsonSerializableObject(instanceDiscoveryJson, AadInstanceDiscoveryResponse::fromJson);JsonHelper.convertJsonStringToJsonSerializableObject(response.body(), ManagedIdentityResponse::fromJson);There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the suggestion, I made these changes in the latest commit.
Definitely easier to read, and just from a couple quick tests runs about twice as fast (0-2 milliseconds instead of 2-4)
| @JsonProperty(value = "expires_on") String expiresOn) { | ||
| this.accessToken = token; | ||
| this.expiresOn = expiresOn; | ||
| public static ManagedIdentityResponse fromJson(JsonReader jsonReader) throws IOException { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Jackson seems more elegant / readable with the attribute approach...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's definitely more elegant, there's a reason it's by far the most popular JSON-related library on Maven: https://mvnrepository.com/open-source/json-libraries
But to get rid of 3rd-party dependencies there's not much choice, azure-json is at least used by most other Azure products: https://mvnrepository.com/artifact/com.azure/azure-json/usages
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Jackson Databind is much cleaner, and in some cases clearer, but it does require a lot of reflection to be used by Jackson. This code here is effectively equivalent to what you'd see if you were using Jackson Core which doesn't have all the reflection handling.
| reader.nextToken(); | ||
| switch (fieldName) { | ||
| case "ver": | ||
| response.version = Float.parseFloat(reader.getString()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JsonReader has getFloat, I'd recommend using that instead. Unless you need special handling if ver is actually a String JSON node.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I originally used getFloat, however it gave me the following error: Current token (VALUE_STRING) not numeric, can not use numeric value accessors at [Source: (String)"{"ver":"1.0", ...
I assumed it was because the JSON we were receiving was a string of "1.0", though at least according to the specs shouldn't it be able to parse a number or a string? https://learn.microsoft.com/en-us/java/api/com.azure.json.jsonreader?view=azure-java-stable#com-azure-json-jsonreader-getfloat()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JsonReader uses a very literal interpretation of the JSON spec where it won't perform implicit conversions to numbers or booleans if the underlying value is a JSON string.
…tion-library-for-java into avdunn/jackson-databind-removal
This PR begins the process of replacing the com.fasterxml.jackson.core dependency with azure-json, #909
There are a lot of added and deleted lines, but for the most part the changes are:
To help keep the PR focused and lower the risk of a breaking change in behavior, this first PR covers various package-private classes and methods. Follow-up PRs will finish the job of removing com.fasterxml.jackson.core, as well as use RevAPI to ensure no changes are made to the API