-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
Support Multipart @FormParam on EntityPart #41204
base: main
Are you sure you want to change the base?
Conversation
I'll just add it down here, but this implementation is NOT complete. Most of it looks correct, but we should really have more complete tests and obviously implement the |
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.
Wow, this looks great. Impressive in such a short time :)
I've added a few comments, but you're going in the right direction.
Looking at the spec, it appears that we need the following to fully support EntityPart
:
- ✅
@FormParam("name") EntityPart param
and@FormParam("name") List<EntityPart> param
, which you've done List<EntityPart>
as a body parameter. I suppose that one catches all parts, so it's the equivalent of our@RestForm(FileUpload.ALL) List<FileUpload>
orMultipartFormDataInput
- Implement
RuntimeDelegateImpl.createEntityPartBuilder
and the builder type - Probably the client side support too? The spec doesn't say much about that, perhaps the TCK does, but we don't run it, unfortunately.
Additionally, on our end, we'll need to:
- Update the docs to mention
EntityPart
in multipart support - Ultimately, we'll need to figure out if and how to unify our multipart support with the spec's.
I didn't see anything in the spec about returning EntityPart
to return multipart from the endpoint. Or about the client support for it.
if (value.isFileItem()) { | ||
this.content = new FileInputStream(value.getFileItem().getFile().toFile()); | ||
} else { | ||
this.content = new ByteArrayInputStream(value.getValue().getBytes(Charset.defaultCharset())); |
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'm not sure what encoding the byte array should have, but I suspect not the default charset. First, because we prefer utf-8 everywhere, and second because it's possible that anybody reading the InputStream
will use the part's encoding as set in headers or media type, which would be different to the default charset.
Also, perhaps the InputStream
should be build lazily in getContent
? Otherwise if a user closes it, doing two calls to getContent
will fail.
|
||
@Override | ||
public InputStream getContent() { | ||
return this.content; |
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.
Probably lazily build the InputStream
here based on the value.
...erver/runtime/src/main/java/org/jboss/resteasy/reactive/server/multipart/EntityPartImpl.java
Show resolved
Hide resolved
Are you sure that works? Withour |
This comment has been minimized.
This comment has been minimized.
Yes I'm pretty sure; we can add that as a test-case as well. I don't really know how it works though. Thank you for the quick feedback! I will update the PR according to your comments and take a look at the builder. I agree that client-side is a must long-term, but it is probably easier to do that at a later stage? |
Sure, it can be done later. |
I have updated my PR according to your comments. I am not sure if everything is fully correct but it's getting there. Yes, I looked back and saw that no, |
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.
Nice, good progress :)
Status for workflow
|
Status | Name | Step | Failures | Logs | Raw logs | Build scan |
---|---|---|---|---|---|---|
✖ | Native Tests - HTTP | Build |
Failures | Logs | Raw logs | 🔍 |
Full information is available in the Build summary check run.
You can consult the Develocity build scans.
Failures
⚙️ Native Tests - HTTP #
- Failing: integration-tests/rest-client-reactive-multipart
📦 integration-tests/rest-client-reactive-multipart
✖ io.quarkus.it.rest.client.multipart.MultipartResourceIT.shouldHandleEntityPartMessage
- History - More details - Source on GitHub
java.lang.AssertionError:
1 expectation failed.
Expected status code <200> but was <400>.
at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
at org.codehaus.groovy.reflection.CachedConstructor.invoke(CachedConstructor.java:73)
at org.codehaus.groovy.runtime.callsite.ConstructorSite$ConstructorSiteNoUnwrapNoCoerce.callConstructor(ConstructorSite.java:108)
Flaky tests - Develocity
⚙️ JVM Tests - JDK 21
📦 extensions/smallrye-reactive-messaging-kafka/deployment
✖ io.quarkus.smallrye.reactivemessaging.kafka.deployment.dev.KafkaDevServicesDevModeTestCase.sseStream
- History
Assertion condition defined as a Lambda expression in io.quarkus.smallrye.reactivemessaging.kafka.deployment.dev.KafkaDevServicesDevModeTestCase Expecting size of: [] to be greater than or equal to 2 but was 0 within 10 seconds.
-org.awaitility.core.ConditionTimeoutException
org.awaitility.core.ConditionTimeoutException:
Assertion condition defined as a Lambda expression in io.quarkus.smallrye.reactivemessaging.kafka.deployment.dev.KafkaDevServicesDevModeTestCase
Expecting size of:
[]
to be greater than or equal to 2 but was 0 within 10 seconds.
at org.awaitility.core.ConditionAwaiter.await(ConditionAwaiter.java:167)
at org.awaitility.core.AssertionCondition.await(AssertionCondition.java:119)
at org.awaitility.core.AssertionCondition.await(AssertionCondition.java:31)
📦 integration-tests/grpc-hibernate
✖ com.example.grpc.hibernate.BlockingRawTest.shouldAdd
- History
Condition with Lambda expression in com.example.grpc.hibernate.BlockingRawTestBase was not fulfilled within 30 seconds.
-org.awaitility.core.ConditionTimeoutException
org.awaitility.core.ConditionTimeoutException: Condition with Lambda expression in com.example.grpc.hibernate.BlockingRawTestBase was not fulfilled within 30 seconds.
at org.awaitility.core.ConditionAwaiter.await(ConditionAwaiter.java:167)
at org.awaitility.core.CallableCondition.await(CallableCondition.java:78)
at org.awaitility.core.CallableCondition.await(CallableCondition.java:26)
at org.awaitility.core.ConditionFactory.until(ConditionFactory.java:1006)
at org.awaitility.core.ConditionFactory.until(ConditionFactory.java:975)
at com.example.grpc.hibernate.BlockingRawTestBase.shouldAdd(BlockingRawTestBase.java:59)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
This is a fix of issue #41186
Previously,
@FormParam
was not supported onEntityPart
parameters in resources, and would cause a runtime error stating that a converter is missing. This was not compliant to the Jakarta RESTful Web Services 3.1 spec. Now, this is fixed by handlingEntityPart
as a 'multipart type' during conversion and addingEntityPart
support toMultipartFormParamExtractor
.Two test cases have been added to ensure correctness.