Skip to content

Use Context#bodyStreamAsClass(...) #193

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

Closed
wants to merge 2 commits into from
Closed

Use Context#bodyStreamAsClass(...) #193

wants to merge 2 commits into from

Conversation

Mechite
Copy link
Contributor

@Mechite Mechite commented Mar 30, 2023

Use Javalin's Context#bodyStreamAsClass method to deserialize rather than Context#bodyAsClass.

Drawbacks

If one would like to make a custom io.javalin.json.JsonMapper, they MUST override not only toJsonString and fromJsonString (well, no longer need to override those two, but probably would also override those two), but also toJsonStream and fromJsonStream, or an exception will be thrown when deserializing.

Motivation

  • This approach means deserialization will not eat memory for large inputs and also allows for input validation to be more powerful
  • Means users of non-JSON codecs like https://msgpack.org can use the powerful features more efficiently, e.g. reading a binary byte array could be done with an InputStream inside of a POJO being read from, so instead of having to send the binary data separately to any other data needed alongside it, you could have it as the last field inside of the POJO and then stream in the POJO, do whatever validation you need to do, maybe even stream out your input so the binary data is never fully loaded in memory and is just streamed through some processing logic and you can have an output.
    For example, if I was going to make a route to resize an image, and I wanted to have the new dimensions as part of the POJO (ie the JSON) rather than a path parameter or something, so my object looked like { width: number, height: number, image: binary }, I could stream the new image out and have the width and height on hand all with one request.
  • Means users of JSON could also do the same thing! While yes, JSON doesn't have a proper binary data format, you can safely just use Base64 in strings for everything, even file uploads; while yes, Base64 results in a 33% size increase to regular binary data, compression with e.g. gzip would result in this being completely negligible and quite honestly, I personally find this approach to allow for much more modern REST APIs than would normally be attained by e.g. form data.

@rbygrave
Copy link
Contributor

We should note the minimum version of javalin that this requires. Do you know the required version?

@Mechite
Copy link
Contributor Author

Mechite commented Mar 30, 2023

We should note the minimum version of javalin that this requires. Do you know the required version?

Unsure about the version, however some quick research through GitHub search shows javalin/javalin#1336 as where they first unveiled the feature. This PR was made because of the issue javalin/javalin#1335, where they state "javalin 4.0RC migration", so basically, from all I know, this feature has been here since the beginning release of Javalin 4.

@Mechite
Copy link
Contributor Author

Mechite commented Mar 31, 2023

Another drawback to note which I didn't consider at first was that bodyStreamAsClass can only be called once and the original body isn't cached; if you injected a Context and wanted to use any of the body related methods, it wouldn't work as the body is going to be streamed through your API.
I think we should make this feature a default that can be configured, unless you think otherwise and opinionation/convention is superior to configurability here; this streaming functionality is a killer feature but it could cause issues if there is a specific reason to have the whole body in memory.

@rbygrave
Copy link
Contributor

rbygrave commented Apr 3, 2023

Note to say the build is failing with this PR, I haven't looked at the failures yet.

was that bodyStreamAsClass can only be called once and the original body isn't cached;

That is fine by me / expected by me at least. Noting that people can always use the Javalin Context and control this themselves for the cases when a body is read more than once (which I expect to be extremely rare).

@Mechite
Copy link
Contributor Author

Mechite commented Apr 3, 2023

Yeah, not sure why it is failing considering the changes are pretty trivial as it is basically just an API usage change

@Mechite Mechite closed this by deleting the head repository Apr 3, 2023
@Mechite Mechite reopened this Apr 3, 2023
@SentryMan
Copy link
Collaborator

if you put the diamond operator thing it should work

@Mechite
Copy link
Contributor Author

Mechite commented Apr 3, 2023

Closing as I decided to make things easier for myself with a fresh PR.

@Mechite Mechite closed this Apr 3, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants