rest icon indicating copy to clipboard operation
rest copied to clipboard

Add required apis to serialize the EntityPart

Open jimma opened this issue 4 years ago • 5 comments

At the moment there is no api to get the object which is added to the EntityPart to serialize the entity to output stream. It also needs getType() and getGenericType() to select the proper MessageBodyWriter.

jimma avatar Jul 06 '21 11:07 jimma

Hi @jimma - the EntityPart.Builder class is used for the multipart sender to specify the object to send and the type/generic type of that object. The EntityPart is intended to represent the object as a part of a multipart request to the user - it would be analogous to the Response object. So the user should not need to get the object directly (they would need to go through message body readers - which would require that they specify the type/generic type - this is handled by getContent methods with Class and GenericType as parameters).

For implementors, they would need to have access to the type/generic type and object that the user created using the Builder so that they could serialize the part in the HTTP stream - but for that, I would expect that implementations would create their own implementation class of Builder and EntityPart that would provide them with access to the type and object specified by the user.

Hope this helps.

andymc12 avatar Jul 06 '21 14:07 andymc12

Hi @andymc12 Thanks for your quick response.

For implementors, they would need to have access to the type/generic type and object that the user created using the Builder so that they could serialize the part in the HTTP stream - but for that, I would expect that implementations would create their own implementation class of Builder and EntityPart that would provide them with access to the type and object specified by the user.

Yes. Implementor can provide its own access the type and object. But I see adding these apis will be helpful for user to get this object of this Entity before sending out for debug or test purpose, and for implementor these apis are very convenient to select proper message writer to serialize this object.

List<EntityPart> parts = Arrays.asList( 
EntityPart.withName("text").content("plan text".mediaType(MediaType.TEXT_PLAIN_TYPE).build(),
EntityPart.withName("file").content(fileInputStream).mediaType(MediaType.TEXT_PLAIN_TYPE).build());

jimma avatar Jul 07 '21 09:07 jimma

I'm concerned that it might add confusion or require language like "if on the sending side and not yet sent, returns the content, otherwise throws an IllegalStateException" or similar (once sent, the implementation is required to close the input stream so it may not be possible to get the content from the EntityPart at that point).

In your example, I'm not sure what we would return from parts.get(1).getContent() - it could return the FileInputStream or it could run that stream through a MessageBodyReader to convert it to a String or some other object.

Instead of making the EntityPart a data structure for the user, I'd prefer that the user kept track of their objects separately. For example,

String text = "plan text";
InputStream fileInputStream = ...
List<EntityPart> parts = Arrays.asList( 
EntityPart.withName("text").content(text).mediaType(MediaType.TEXT_PLAIN_TYPE).build(),
EntityPart.withName("file").content(fileInputStream).mediaType(MediaType.TEXT_PLAIN_TYPE).build());

LOG.info("we're sending text = {0} and file = {1}", text, fileInputStream);

andymc12 avatar Jul 07 '21 13:07 andymc12

How about we better name it with getContentEntity() to get the object and change the getContent() to getContentStream() for getting the InputStream?

There is still other place like user gets the EntityPart and reads the content in a RequestFilter before serialize to output:

public class RequestFilterGetEntity implements ClientRequestFilter {
    @Override
    public void filter(ClientRequestContext requestContext) throws IOException {
        Object entity = requestContext.getEntity();
        List<EntityPart> parts = (List<EntityPart>) entity;
        for (EntityPart part : parts) {
            if (((String)part.getContentEntity()).contains("abort")) {
                requestContext.abortWith(Response.ok().build());
                return;
            }
        }
    }

For a MessageBodyWriter to write the EntityPart list, if we set anObjectto this EntityPart instead of an InputStream, we need to get this Object first and serialize this Object with selected writer, right ?

jimma avatar Jul 08 '21 08:07 jimma

@andymc12 I added some comment https://github.com/eclipse-ee4j/jaxrs-api/pull/990#issuecomment-943155060. Please review.

jimma avatar Oct 14 '21 09:10 jimma