Skip to content

Add BodyString annotation, to support controllers with body of type String #198

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

Merged
merged 14 commits into from
Apr 5, 2023

Conversation

SentryMan
Copy link
Collaborator

@SentryMan SentryMan commented Apr 3, 2023

Enough people have asked me about it for me to think this should be a thing.

  • adds a new annotation to indicate a string method param is a body type
  • javalin based adapters will use body() for string body

@rbygrave
Copy link
Contributor

rbygrave commented Apr 3, 2023

My gut says that @BodyString should be called @Body. So although we need it for the case where a body is type String, it could be used as a marker for the body in other cases or in some future case that we don't know about yet.

@SentryMan SentryMan changed the title BodyString annotation Body annotation Apr 3, 2023
@Mechite
Copy link
Contributor

Mechite commented Apr 3, 2023

Body as byte[]?
EDIT - Avaje auto detects, got it. But in that case, what would be the need to even add this if it is possible to just turn the byte[] into a new string object? Wouldn't this just help make things into annotation hell?

@SentryMan
Copy link
Collaborator Author

I'm hoping the javadoc would scare off anybody that tries to set this unironically for non-strings. The fact remains that there is no intuitive mechanism to get/send a string body.

just turn the byte[] into a new string object?

you know that, I know that, but the average dev is not gonna think of that.

@SentryMan
Copy link
Collaborator Author

SentryMan commented Apr 3, 2023

I could make it fail compilation if the @Body is placed on a non-string to force people not to use it "wrong". @rbygrave thoughts?

@SentryMan
Copy link
Collaborator Author

I'm gonna change it back to BodyString. I currently cannot conceive of a situation where somebody could use it not on a string. If you are trying to get/send some esoteric body you can just use a byte[] or InputStream.

If somebody manages to find such an obscure edge case, we can tell them to use Context or ServerRequest and applaud them.

@SentryMan SentryMan changed the title Body annotation BodyString annotation Apr 3, 2023
@SentryMan
Copy link
Collaborator Author

I'm good with this, please review when you get time.

@Mechite
Copy link
Contributor

Mechite commented Apr 4, 2023

just turn the byte[] into a new string object?

you know that, I know that, but the average dev is not gonna think of that.

So we document it? I feel like adding this complexity is less convenient and anyway we need to discourage developers creating applications in this way; when you aren't using something "normal" like Spring and are trying to reduce latency while having a good project structure with Avaje, you should also be streaming your inputs and outputs, and focussing on concurrency, etc; in my opinion actually, the performance of something eg Javalin becomes completely useless without the advent of Project Loom and the support for it, because at scale, things like Akka and Eclipse Vert.x are much more scalable, but now with Loom we can essentially build very performant applications and I feel that Avaje should not only focus on helping scale the complexity of an application with dependency injection techniques and these annotation driven controllers at compile-time, but also focus on scaling business applications across clusters and larger infrastructure - we should encourage more performant development patterns and make "the wrong way" tougher.

There are cases you'd like the entire body in memory, as a string object, without streaming it, but those cases are really rare and instead of having first-class support for them, we should have the approach Java fundamentally takes as an ecosystem - force the imperative approach, i.e. creating a string object. Honestly, we could even drop byte[] and force people to work with streams no matter what, since they could just String body = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8); -why would anybody even need a non POJO-deserialised body apart from streaming large data, or if they wanted to handle the deserialisation themselves (but in that case, they would still want to stream the input to parse it efficiently)?

In any case, the amount of "shortcuts" we provide in my opinion should be kept to a minimum to help guide people into working with good application paradigms and reaping performance benefits all around.

@SentryMan
Copy link
Collaborator Author

You're pretty persuasive, I'm almost talked out of this. I'm on board with limiting to streaming options and removing byte[] support in favor of inputstream. But even so, getting/sending the body as a small string is common enough that a shortcut for String body = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8); would be appreciated I'd say.

@rbygrave
Copy link
Contributor

rbygrave commented Apr 4, 2023

why would anybody even need a non POJO-deserialised body

To some extent we need to get past "Http Hello World", as in, if someone is kicking the tires with avaje-http and the first thing they do is POST some simple hello world content ... it is fairly un-intuitive and the first impression is not great.

byte[] ... avaje http auto detects that

This is because unlike JAX-RS (and Spring MVC) avaje http by default is "interpreting" path parameters and hence query parameters by convention - and we do this to greatly reduce the amount of annotations we need.

In this way String type is a bit special and defaults to path/query parameters etc (but byte[], InputStream etc instead default to being a BODY type as we don't think that they are suitable types for query params).

So this is kind of nice for what we think is the majority case (specifically query params that are String types) but we now have this issue that a String body isn't obvious / intuitive.

Edit:
Changed to use - " majority case (specifically query params that are String types)"

@rbygrave
Copy link
Contributor

rbygrave commented Apr 4, 2023

... but now I'm wondering what the use case actually is and I'm thinking this isn't a likely "hello world" case?

@SentryMan What was the use case that people hit where they wanted the String body ?

@SentryMan
Copy link
Collaborator Author

I know one case of an API that takes html input and parses the text.

Even so, it appears to be close to an industry standard to have an easy way to get a string body. Jaxrs, spring, and javalin all do it.

@Mechite
Copy link
Contributor

Mechite commented Apr 4, 2023

I know one case of an API that takes html input and parses the text.

Even so, it appears to be close to an industry standard to have an easy way to get a string body. Jaxrs, spring, and javalin all do it.

I would say it would still make more sense for this API to parse the HTML by streaming, and we should find some way to encourage this; but also, yes, not being able to do a "hello world" post easily is an issue, so I guess we should just have this annotation available anyway since it would only be two more lines of documentation and less confusion 🤔.

I'd ask actually - what about primitive bodies? int body? Would this work out of the box without issue?

@SentryMan
Copy link
Collaborator Author

SentryMan commented Apr 4, 2023

I'd ask actually - what about primitive bodies? int body? Would this work out of the box without issue?

I draw the line at strings, if anybody wants to do a primitive, I'd refuse. The annotation itself only supports strings

@rbygrave
Copy link
Contributor

rbygrave commented Apr 4, 2023

I guess we should just have this annotation available anyway

As a side comment, to me one of the interesting things about "the annotation processing code generation approach" ... is that very often the "extra complexity / extra cost" of a feature is almost fully contained in the generator and resulting generated code and not at runtime (or the runtime part of the library).

That is, the extra "cost" does not result in runtime complexity (which I really like) ... but yes we still have costs in terms of "Documentation" and "Concepts".

@SentryMan
Copy link
Collaborator Author

we still have costs in terms of "Documentation"

It's a good thing that we have contributors that are willing to update the docs.

@SentryMan
Copy link
Collaborator Author

ahh hang on a sec, gotta change the generated openAPI to make it say the body is application/text

@SentryMan
Copy link
Collaborator Author

so fixed that, but I wonder if it would be good to have a @consumes annotation to generate the correct openAPI when people use stuff like InputStream for example

@rbygrave rbygrave added this to the 1.35 milestone Apr 5, 2023
@rbygrave rbygrave changed the title BodyString annotation Add BodyString annotation, to support controllers with body of type String Apr 5, 2023
@rbygrave rbygrave merged commit f3fd134 into avaje:master Apr 5, 2023
@SentryMan SentryMan deleted the BodyString branch April 5, 2023 00:12
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