Skip to content

Commit 8fd9463

Browse files
committed
Fix #270
1 parent 17f3969 commit 8fd9463

File tree

5 files changed

+145
-4
lines changed

5 files changed

+145
-4
lines changed

release-notes/VERSION-2.x

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ Project: jackson-dataformat-xml
44
= Releases
55
------------------------------------------------------------------------
66

7+
2.9.8 (not yet released)
8+
9+
#270: Add support for `writeBinary()` with `InputStream` to `ToXMLGenerator`
10+
(requested by csbxvs@github; contributed by marc-christian-schulze@github)
11+
712
2.9.7 (19-Sep-2018)
813

914
No changes since 2.9.6

src/main/java/com/fasterxml/jackson/dataformat/xml/ser/ToXmlGenerator.java

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -840,6 +840,69 @@ public void writeBinary(Base64Variant b64variant,
840840
}
841841
}
842842

843+
@Override
844+
public int writeBinary(Base64Variant b64variant, InputStream data, int dataLength) throws IOException
845+
{
846+
if (data == null) {
847+
writeNull();
848+
return 0;
849+
}
850+
_verifyValueWrite("write Binary value");
851+
if (_nextName == null) {
852+
handleMissingName();
853+
}
854+
try {
855+
if (_nextIsAttribute) {
856+
// Stax2 API only has 'full buffer' write method:
857+
byte[] fullBuffer = toFullBuffer(data, dataLength);
858+
_xmlWriter.writeBinaryAttribute("", _nextName.getNamespaceURI(), _nextName.getLocalPart(), fullBuffer);
859+
} else if (checkNextIsUnwrapped()) {
860+
// should we consider pretty-printing or not?
861+
writeStreamAsBinary(data, dataLength);
862+
863+
} else {
864+
if (_xmlPrettyPrinter != null) {
865+
_xmlPrettyPrinter.writeLeafElement(_xmlWriter,
866+
_nextName.getNamespaceURI(), _nextName.getLocalPart(),
867+
toFullBuffer(data, dataLength), 0, dataLength);
868+
} else {
869+
_xmlWriter.writeStartElement(_nextName.getNamespaceURI(), _nextName.getLocalPart());
870+
writeStreamAsBinary(data, dataLength);
871+
_xmlWriter.writeEndElement();
872+
}
873+
}
874+
} catch (XMLStreamException e) {
875+
StaxUtil.throwAsGenerationException(e, this);
876+
}
877+
878+
return dataLength;
879+
}
880+
881+
private void writeStreamAsBinary(InputStream data, int len) throws IOException, XMLStreamException
882+
{
883+
// base64 encodes up to 3 bytes into a 4 bytes string
884+
byte[] tmp = new byte[3];
885+
int offset = 0;
886+
int read;
887+
while((read = data.read(tmp, offset, Math.min(3 - offset, len))) != -1) {
888+
offset += read;
889+
len -= read;
890+
if(offset == 3) {
891+
offset = 0;
892+
_xmlWriter.writeBinary(tmp, 0, 3);
893+
}
894+
if (len == 0) {
895+
break;
896+
}
897+
}
898+
899+
// we still have < 3 bytes in the buffer
900+
if(offset > 0) {
901+
_xmlWriter.writeBinary(tmp, 0, offset);
902+
}
903+
}
904+
905+
843906
private byte[] toFullBuffer(byte[] data, int offset, int len)
844907
{
845908
// might already be ok:
@@ -852,7 +915,22 @@ private byte[] toFullBuffer(byte[] data, int offset, int len)
852915
}
853916
return result;
854917
}
855-
918+
919+
private byte[] toFullBuffer(InputStream data, final int len) throws IOException
920+
{
921+
byte[] result = new byte[len];
922+
int offset = 0;
923+
924+
for (; offset < len; ) {
925+
int count = data.read(result, offset, len - offset);
926+
if (count < 0) {
927+
_reportError("Too few bytes available: missing "+(len - offset)+" bytes (out of "+len+")");
928+
}
929+
offset += count;
930+
}
931+
return result;
932+
}
933+
856934
/*
857935
/**********************************************************
858936
/* Output method implementations, primitive

src/test/java/com/fasterxml/jackson/dataformat/xml/deser/builder/BuilderSimpleTest.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package com.fasterxml.jackson.dataformat.xml.deser.builder;
22

3-
import java.util.*;
4-
53
import com.fasterxml.jackson.annotation.*;
64

75
import com.fasterxml.jackson.core.Version;

src/test/java/com/fasterxml/jackson/dataformat/xml/failing/ListDeser294Test.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import java.util.*;
44

5-
import com.fasterxml.jackson.annotation.JsonProperty;
65
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
76
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
87
import com.fasterxml.jackson.dataformat.xml.XmlTestBase;
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package com.fasterxml.jackson.dataformat.xml.ser;
2+
3+
import java.nio.*;
4+
5+
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
6+
import com.fasterxml.jackson.dataformat.xml.XmlTestBase;
7+
8+
/**
9+
* See <a href="https://github.com/FasterXML/jackson-dataformat-xml/issues/270">issue #270</a>
10+
* for details
11+
*/
12+
public class TestBinaryStreamToXMLSerialization extends XmlTestBase
13+
{
14+
private final XmlMapper MAPPER = new XmlMapper();
15+
16+
public void testWith0Bytes() throws Exception
17+
{
18+
String xml = MAPPER.writeValueAsString(createPojo());
19+
assertEquals("<TestPojo><field/></TestPojo>", xml);
20+
}
21+
22+
public void testWith1Byte() throws Exception
23+
{
24+
String xml = MAPPER.writeValueAsString(createPojo( 'A' ));
25+
assertEquals("<TestPojo><field>QQ==</field></TestPojo>", xml);
26+
}
27+
28+
public void testWith2Bytes() throws Exception
29+
{
30+
String xml = MAPPER.writeValueAsString(createPojo( 'A', 'B' ));
31+
assertEquals("<TestPojo><field>QUI=</field></TestPojo>", xml);
32+
}
33+
34+
public void testWith3Bytes() throws Exception
35+
{
36+
String xml = MAPPER.writeValueAsString(createPojo( 'A', 'B', 'C' ));
37+
assertEquals("<TestPojo><field>QUJD</field></TestPojo>", xml);
38+
}
39+
40+
public void testWith4Bytes() throws Exception
41+
{
42+
String xml = MAPPER.writeValueAsString(createPojo( 'A', 'B', 'C', 'D' ));
43+
assertEquals("<TestPojo><field>QUJDRA==</field></TestPojo>", xml);
44+
}
45+
46+
private TestPojo createPojo(char... content) {
47+
TestPojo obj = new TestPojo();
48+
// DirectByteBuffer does not have an underlying array
49+
// so the ByteArraySerializer has to fallback to stream writing
50+
obj.field = ByteBuffer.allocateDirect(content.length);
51+
for(char b : content) {
52+
obj.field.put((byte) b);
53+
}
54+
obj.field.position(0);
55+
return obj;
56+
}
57+
58+
public static class TestPojo {
59+
public ByteBuffer field;
60+
}
61+
}

0 commit comments

Comments
 (0)