Streaming encoding
It would be nice if streaming encoding similar to Jackson is added. Important for me would be that I could stream the elements of a ByteString as well, since these form the major part of my payload.
@neothemachine Basically, streaming encoding and decoding is already implemented. Could you please provide a small pseudo-code example what you want to achieve? Maybe I can help you to find the right direction; if not, I am sure we can find and implement a solution for your problem.
The README only has a "Streaming Decoding Example" and I checked the code of CborEncoder to see if it has some kind of streaming interface but couldn't find anything.
new CborEncoder(outputstream).stream()
.add("text") // add string
.add(1234) // add integer
.add(new byte[] { 0x10 }) // add byte array
.addArray() // add array
.add(1)
.add("text")
.end()
.close();
Something like that.
OK, it is already there but not with a nice DSL as described. You could transform the example above to (free coded, not checked with IDE):
CborEncoder encoder = new CborEncoder(outputstream);
encoder.encode(new UnicodeString("text"));
encoder.encode(new UnsignedInteger(1234));
encoder.encode(new ByteString(new byte[] { 0x10 }));
encoder.encode(new Array().setChunked()); // start array
encoder.encode(new UnsignedInteger(1));
encoder.encode(new UnicodeString("text"));
encoder.encode(Special.BREAK); // close array
outputstream.close();
A more developer-friendly DSL would be much better, of course.
I see. It seems natural to me to want to use the CborBuilder as such a DSL. So CborBuilder could be made into an interface where one implementation is the current builder class and the other directly writes to a CborEncoder instance (where the relations could be set up by my proposed .stream() call).
Good idea! Allow me some time to implement this.
In parallel I am implementing a generic streaming interface that I can use both with Jackson and cbor-java and which is supposed to be compatible to both, meaning which I can easily write adapters for. I think some things in CborBuilder are actually too much for a streaming interface, so maybe this has to be split in two interfaces or so.
For reference, this is what I currently got (targeted to my use case):
/**
* A streaming encoder interface for JSON-compatible object structures
* with additional hints for more advanced formats like CBOR encoders.
*
* This interface is a mix of cbor-java's CborBuilder and Jackson's Streaming API,
* with the goal of being compatible to both and being able to write
* simple adapters for them.
*
* @author Maik Riechert
*/
public interface StreamingEncoder {
class ArrayHints {
private final Long size;
private final Class<Number> type;
/**
*
* @param size can be null
* @param type can be null
*/
public ArrayHints(Long size, Class<Number> type) {
this.size = size;
this.type = type;
}
boolean hasSize() {
return size != null;
}
long getSize() {
return size;
}
boolean hasType() {
return type != null;
}
Class<Number> getType() {
return type;
}
}
interface ArrayEncoder <T> {
ArrayEncoder<T> add(String value) throws IOException;
ArrayEncoder<T> add(boolean value) throws IOException;
ArrayEncoder<T> add(int value) throws IOException;
ArrayEncoder<T> add(long value) throws IOException;
ArrayEncoder<T> add(float value) throws IOException;
ArrayEncoder<T> add(double value) throws IOException;
ArrayEncoder<ArrayEncoder<T>> startArray() throws IOException;
ArrayEncoder<ArrayEncoder<T>> startArray(ArrayHints hints) throws IOException;
MapEncoder<ArrayEncoder<T>> startMap() throws IOException;
T end() throws IOException;
}
interface MapEncoder <T> {
MapEncoder<T> put(String key, String value) throws IOException;
MapEncoder<T> put(String key, boolean value) throws IOException;
MapEncoder<T> put(String key, int value) throws IOException;
MapEncoder<T> put(String key, long value) throws IOException;
MapEncoder<T> put(String key, float value) throws IOException;
MapEncoder<T> put(String key, double value) throws IOException;
ArrayEncoder<MapEncoder<T>> startArray(String key) throws IOException;
ArrayEncoder<MapEncoder<T>> startArray(String key, ArrayHints hints) throws IOException;
MapEncoder<MapEncoder<T>> startMap(String key) throws IOException;
T end() throws IOException;
}
MapEncoder<StreamingEncoder> startMap() throws IOException;
void end() throws IOException;
// at the root level we only support Maps for now.
}