如何为Java 11 HttpRequest创建自定义BodyPublisher

如何为Java 11 HttpRequest创建自定义BodyPublisher,java,java-11,java-http-client,Java,Java 11,Java Http Client,我正在尝试创建一个自定义的BodyPublisher,它将反序列化我的JSON对象。我可以在创建请求时反序列化JSON,并使用bodypublisher的ofByteArray方法,但我更愿意使用自定义发布程序 公共类CustomPublisher实现HttpRequest.BodyPublisher{ 专用字节[]字节; 公共CustomPublisher(ObjectNode jsonData){ ... //将jsonData反序列化为字节 ... } @凌驾 公共长内容长度(){ if(

我正在尝试创建一个自定义的
BodyPublisher
,它将反序列化我的JSON对象。我可以在创建请求时反序列化JSON,并使用
bodypublisher
ofByteArray
方法,但我更愿意使用自定义发布程序

公共类CustomPublisher实现HttpRequest.BodyPublisher{
专用字节[]字节;
公共CustomPublisher(ObjectNode jsonData){
...
//将jsonData反序列化为字节
...
}
@凌驾
公共长内容长度(){
if(bytes==null)返回0;
返回字节数.length
}
@凌驾

public void subscribe(Flow.Subscriber避免使用它生成字节数组是正确的,因为这会为大型对象造成内存问题

我不会尝试编写自定义发布程序,而是利用工厂方法

正如您所注意到的,您可以使用
HttpRequest.bodypublisher.ofByteArray
。这对于相对较小的对象来说很好,但我编程是出于习惯。假设代码不需要扩展的问题是,其他开发人员会假设传递大型对象是安全的,而不会意识到对性能的影响

编写自己的body publisher需要大量工作。它的
subscribe
方法继承自

subscribe
方法的文档从以下内容开始:

如果可能,添加给定的订阅服务器

每次调用
subscribe
方法时,您都需要将订阅服务器添加到某种集合中,您需要创建的实现,并需要立即将其传递给订阅服务器的
onSubscribe
方法。只有当e通过调用相应订阅者(而不仅仅是任何订阅者)的方法来调用Subscription的
request
方法,并且在发送所有数据后,必须调用同一订阅者的
onComplete()
方法。除此之外,订阅实现对象需要处理
cancel
请求

通过扩展Flow.Publisher的默认实现,然后向其添加
contentLength()
方法,可以简化很多工作。但正如SubmissionPublisher文档所示,即使是一个最小的工作实现,您仍有大量工作要做


HttpRequest.BodyPublishers.of…方法将为您完成所有这一切。
of ByteArray
对于小对象来说是可以的,但是
of InputStream
将适用于您可以传入的任何对象。

您打算以什么格式发布您的ObjectNode?作为JSON?@VGR构造函数使用Jackson将其反序列化为字节数组,即如果我理解正确,HttpRequest想要返回一个
ByteBuffer
。那么该ByteBuffer的内容示例是什么?@VGR在构造函数中初始化的字节数组。但是我不知道整个字节数组是否应该作为一个单字节数组推送到ByteBuffer中,或者每个元素是否应该一个接一个地推送。或者,即使这很重要。不要一次发送一个字节,这是非常浪费和缓慢的。请使用阈值,如
1。您能否详细说明“我不会尝试编写自定义发布服务器”,因为仅使用
bodypublisher.ofByteArray()就可以轻松完成此任务
method。为了澄清对象大小是固定的,甚至没有那么大。更新了答案。编写BodyPublisher意味着实现Flow.Publisher,这是一项艰巨的工作。您可以使用ByteArray,但迟早会有其他开发人员认为您的代码可以安全地用于大型对象,而不会意识到其对性能的影响我在一个实现的工作示例中添加了一些注意事项
因为在我看来,它让我的问题有了更清晰、更可读的解决方案,而且您还没有提供任何确凿的证据证明字节数组的大小会成为HttpRequest用例中的限制因素。确凿的证据?您认为长度为100000000的字节数组会有什么作用您的程序性能?如果您选择假设只有小对象会被序列化,这是您的选择,但这只是标准的可伸缩性实践。这与我们一次复制几个字节的文件而不是将整个内容读取到单个字节数组中的原因相同。应用程序将需要所有字节的loa因为它是HttpRequest,所以在内存中的某个点或其他任何方式都会被删除。
HttpRequest.BodyPublisher publisher =
    HttpRequest.BodyPublishers.ofInputStream(() ->  {
        PipedInputStream in = new PipedInputStream();

        ForkJoinPool.commonPool().submit(() -> {
            try (PipedOutputStream out = new PipedOutputStream(in)) {
                objectMapper.writeTree(
                    objectMapper.getFactory().createGenerator(out),
                    jsonData);
            }
            return null;
        });

        return in;
    });