static RoutableFactory createQueryResultMessageFactory() {
        return ProtobufCodecBuilder
                .of(QueryResultMessage.class, DocapiVisiting.QueryResultRequest.class)
                .encoder((apiMsg) -> {
                    // Serialization of QueryResultMessages is not implemented in Java (receive only)
                    throw new UnsupportedOperationException("Serialization of QueryResultMessage instances is not supported");
                })
                .decoder(DocapiVisiting.QueryResultRequest.parser(), (protoMsg) -> {
                    var msg = new QueryResultMessage();
                    // Explicitly enforce presence of result/summary fields, as our object is not necessarily
                    // well-defined if these have not been initialized.
                    if (!protoMsg.hasSearchResult() || !protoMsg.hasDocumentSummary()) {
                        throw new IllegalArgumentException("Query result does not have all required fields set");
                    }
                    // We have to use toByteArray() instead of asReadOnlyByteBuffer(), as the deserialization routines
                    // try to fetch the raw arrays, which are considered mutable (causing a ReadOnlyBufferException).
                    msg.setSearchResult(new SearchResult(new BufferSerializer(
                            protoMsg.getSearchResult().getPayload().toByteArray())));
                    msg.setSummary(new DocumentSummary(new BufferSerializer(
                            protoMsg.getDocumentSummary().getPayload().toByteArray())));
                    return msg;
                })
                .build();
    }
Implementation of MessageBus message request/response serialization built around Protocol Buffers.
documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/RoutableFactories80.java