From 2f46d3da8cad2c363c77e8c7f4b6dc0e01236266 Mon Sep 17 00:00:00 2001 From: Serhiy Bzhezytskyy Date: Wed, 19 Aug 2026 17:16:02 +0300 Subject: [PATCH 1/2] SOLR-18379: pin DocsStreamer stored values for the quantized vector subclasses Scaffolding only, no production change. SOLR-18379 wants KNOWN_TYPES replaced by the ExternalizeStoredValuesAsObjects marker, and that swap is not equivalent: KNOWN_TYPES is consulted on class equality, the marker on instanceof, so the DenseVectorField subclasses ScalarQuantizedDenseVectorField and BinaryQuantizedDenseVectorField would move from FieldType.toExternal to FloatPointField.toObject - String to Float per vector element. Nothing would have noticed. Making DocsStreamer.getValue throw for any DenseVectorField subclass left both quantized field tests green, 9 tests and no failures, because they never traverse that code. These two tests do: with the same throwing control they now fail while the plain DenseVectorField test still passes, which is the asymmetry that proves they reach it for a subclass and only for a subclass. They assert today's values - the Strings 1.1 through 4.4 and their type - so the migration turns a silent change of the response format into two failing assertions. AI-assisted (Claude Sonnet 5) --- .../solr/response/DocsStreamerTest.java | 58 +++++++++++++++++-- 1 file changed, 53 insertions(+), 5 deletions(-) diff --git a/solr/core/src/test/org/apache/solr/response/DocsStreamerTest.java b/solr/core/src/test/org/apache/solr/response/DocsStreamerTest.java index b21af51fe46b..86507c6a3a3e 100644 --- a/solr/core/src/test/org/apache/solr/response/DocsStreamerTest.java +++ b/solr/core/src/test/org/apache/solr/response/DocsStreamerTest.java @@ -25,20 +25,68 @@ public class DocsStreamerTest extends SolrTestCaseJ4 { + private static final List VECTOR = Arrays.asList(1.1f, 2.2f, 3.3f, 4.4f); + @BeforeClass public static void beforeClass() throws Exception { System.setProperty( "solr.index.updatelog.enabled", "false"); // schema12 doesn't support _version_ - initCore("solrconfig.xml", "schema12.xml"); } + // Each test method initializes its own core, because the schemas holding the quantized + // field types are not the same file as the one holding the plain DenseVectorField. public void testDenseVectorField() throws Exception { - List values = Arrays.asList(1.1f, 2.2f, 3.3f, 4.4f); - SchemaField sf = h.getCore().getLatestSchema().getField("vector"); - List fields = sf.createFields(values); + try { + initCore("solrconfig.xml", "schema12.xml"); + assertStoredValues("vector", VECTOR); + } finally { + deleteCore(); + } + } + + // ScalarQuantizedDenseVectorField is a subclass of DenseVectorField, and KNOWN_TYPES is + // consulted on an equality basis, so the subclass does not take the toObject path its + // superclass takes: its stored values are externalized as Strings by FieldType.toExternal. + // This pins that difference so it cannot change without a test failing. + public void testScalarQuantizedDenseVectorField() throws Exception { + try { + initCore("solrconfig_codec.xml", "schema-densevector-quantized.xml"); + // plain DenseVectorField, an exact match in KNOWN_TYPES: Float objects + assertStoredValues("vector", VECTOR); + // subclass of it, so no exact match: Strings + assertStoredValues("v_scalar_default", stringsOf(VECTOR)); + } finally { + deleteCore(); + } + } + + // Same for the other DenseVectorField subclass. + public void testBinaryQuantizedDenseVectorField() throws Exception { + try { + initCore("solrconfig-basic.xml", "schema-densevector-bq.xml"); + assertStoredValues("v_bq", stringsOf(VECTOR)); + } finally { + deleteCore(); + } + } + + // Asserts what DocsStreamer.getValue returns for every stored field that fieldName creates + // for VECTOR. The first created field is the indexed one, so it is skipped. + private void assertStoredValues(String fieldName, List expected) { + SchemaField sf = h.getCore().getLatestSchema().getField(fieldName); + List fields = sf.createFields(VECTOR); + assertEquals(fieldName + " created field count", expected.size() + 1, fields.size()); for (int idx = 1; idx < fields.size(); ++idx) { Object value = DocsStreamer.getValue(sf, fields.get(idx)); - assertEquals(values.get(idx - 1), value); + Object want = expected.get(idx - 1); + String label = fieldName + " element " + (idx - 1); + assertNotNull(label, value); + assertEquals(label + " type", want.getClass(), value.getClass()); + assertEquals(label, want, value); } } + + private static List stringsOf(List values) { + return values.stream().map(String::valueOf).toList(); + } } From 4ee3abe9e409930a29da3e4d83df51fd0191d2ba Mon Sep 17 00:00:00 2001 From: Serhiy Bzhezytskyy Date: Wed, 19 Aug 2026 17:16:28 +0300 Subject: [PATCH 2/2] SOLR-18379: remove DocsStreamer.KNOWN_TYPES for the ExternalizeStoredValuesAsObjects marker KNOWN_TYPES was consulted on class equality, the marker on instanceof, so this is not an equivalent swap - it widens the toObject path to subclasses. Ten of the sixteen listed types override toObject(IndexableField), so the widening is only observable below those ten, and the marker is placed on ten bases rather than all sixteen: the five Trie*Field inherit it from TrieField and DenseVectorField from FloatPointField, both of which were themselves in the set. Two behaviour changes follow and both are deliberate. Quantized dense vector fields - ScalarQuantizedDenseVectorField and BinaryQuantizedDenseVectorField - now return stored values as numbers rather than strings. That repairs an inconsistency rather than introducing one: they returned strings only because the equality check excluded them while their own superclass returned floats. Nothing caught this before; making DocsStreamer.getValue throw for any DenseVectorField subclass left both quantized field tests green because they never traversed it. The pins added in the preceding commit fail on the change instead, which is what they are for. BinaryField subclasses lose their toExternal representation, because BinaryField narrows toObject's return type to ByteBuffer and no subclass can override it back to a String. There is no version of this removal that spares them, and leaving BinaryField unmarked would change BinaryField itself. In-tree that reaches only test support: StrBinaryField and SwapBytesBinaryField in core tests, and SortableBinaryField in test-framework, whose stored values go from base64 to binary. TestBinaryField's bean field for str_data is updated accordingly; str_data_dv keeps its string because docValues take a different overload. StrField and TextField don't override toObject(IndexableField) at all - its default already delegates to toExternal - so the marker changes nothing for them or for UUIDField, which inherits it from StrField. Verified: compileJava/compileTestJava, ecjLintMain/Test, spotlessJavaCheck, renderJavadoc, zero remaining references to KNOWN_TYPES anywhere, and DocsStreamerTest + TestBinaryField + ScalarQuantizedDenseVectorFieldTest + DenseVectorFieldTest - 59 tests, 0 failures. AI-assisted (Claude Sonnet 5) --- ...-18379-remove-docsstreamer-known-types.yml | 8 +++ .../apache/solr/response/DocsStreamer.java | 67 +------------------ .../org/apache/solr/schema/BinaryField.java | 2 +- .../org/apache/solr/schema/BoolField.java | 3 +- .../apache/solr/schema/DatePointField.java | 3 +- .../apache/solr/schema/DoublePointField.java | 3 +- .../org/apache/solr/schema/FieldType.java | 10 ++- .../apache/solr/schema/FloatPointField.java | 3 +- .../org/apache/solr/schema/IntPointField.java | 3 +- .../apache/solr/schema/LongPointField.java | 3 +- .../java/org/apache/solr/schema/StrField.java | 3 +- .../org/apache/solr/schema/TextField.java | 2 +- .../org/apache/solr/schema/TrieField.java | 3 +- .../solr/response/DocsStreamerTest.java | 20 +++--- .../apache/solr/schema/TestBinaryField.java | 6 +- 15 files changed, 45 insertions(+), 94 deletions(-) create mode 100644 changelog/unreleased/SOLR-18379-remove-docsstreamer-known-types.yml diff --git a/changelog/unreleased/SOLR-18379-remove-docsstreamer-known-types.yml b/changelog/unreleased/SOLR-18379-remove-docsstreamer-known-types.yml new file mode 100644 index 000000000000..327b2e210d12 --- /dev/null +++ b/changelog/unreleased/SOLR-18379-remove-docsstreamer-known-types.yml @@ -0,0 +1,8 @@ +# See https://github.com/apache/solr/blob/main/dev-docs/changelog.adoc +title: Remove the deprecated DocsStreamer.KNOWN_TYPES set in favour of the inherited FieldType.ExternalizeStoredValuesAsObjects marker; javabin responses now return stored values of quantized dense vector fields as numbers rather than strings, and stored values of custom BinaryField subclasses as binary rather than as their toExternal string. +type: removed +authors: + - name: Serhiy Bzhezytskyy +links: + - name: SOLR-18379 + url: https://issues.apache.org/jira/browse/SOLR-18379 diff --git a/solr/core/src/java/org/apache/solr/response/DocsStreamer.java b/solr/core/src/java/org/apache/solr/response/DocsStreamer.java index ab317e883e17..3dea0d68c9ac 100644 --- a/solr/core/src/java/org/apache/solr/response/DocsStreamer.java +++ b/solr/core/src/java/org/apache/solr/response/DocsStreamer.java @@ -16,11 +16,8 @@ */ package org.apache.solr.response; -import static org.apache.solr.schema.FieldType.ExternalizeStoredValuesAsObjects; - import java.io.IOException; import java.util.ArrayList; -import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; @@ -30,25 +27,9 @@ import org.apache.solr.common.SolrDocument; import org.apache.solr.common.SolrException; import org.apache.solr.response.transform.DocTransformer; -import org.apache.solr.schema.BinaryField; -import org.apache.solr.schema.BoolField; -import org.apache.solr.schema.DatePointField; -import org.apache.solr.schema.DenseVectorField; -import org.apache.solr.schema.DoublePointField; import org.apache.solr.schema.FieldType; -import org.apache.solr.schema.FloatPointField; import org.apache.solr.schema.IndexSchema; -import org.apache.solr.schema.IntPointField; -import org.apache.solr.schema.LongPointField; import org.apache.solr.schema.SchemaField; -import org.apache.solr.schema.StrField; -import org.apache.solr.schema.TextField; -import org.apache.solr.schema.TrieDateField; -import org.apache.solr.schema.TrieDoubleField; -import org.apache.solr.schema.TrieField; -import org.apache.solr.schema.TrieFloatField; -import org.apache.solr.schema.TrieIntField; -import org.apache.solr.schema.TrieLongField; import org.apache.solr.search.DocIterator; import org.apache.solr.search.DocList; import org.apache.solr.search.ReturnFields; @@ -57,22 +38,6 @@ /** This streams SolrDocuments from a DocList and applies transformer */ public class DocsStreamer implements Iterator { - /** - * A hardcoded list of known Solr field types that will be trusted to control their own conversion - * of stored field values into external Objects (via {@link FieldType#toObject}) when returning - * {@link SolrDocument} instances to clients. - * - *

For historic reasons, this Set is consulted using an equality basis, so subclasses - * of these "known" types are not given the same level of trust. - * - *

Any field type not found in this list will have stored values externalized as - * Strings using {@link FieldType#toExternal} unless they implement {@link - * ExternalizeStoredValuesAsObjects} - * - * @deprecated new field types should not be added to this list, instead use {@link - * ExternalizeStoredValuesAsObjects} - */ - @Deprecated public static final Set> KNOWN_TYPES = new HashSet<>(); private final ResultContext rctx; private final SolrDocumentFetcher docFetcher; // a collaborator of SolrIndexSearcher @@ -217,41 +182,11 @@ public static Object getValue(SchemaField sf, IndexableField f) { return f.stringValue(); } } else { - if (KNOWN_TYPES.contains(ft.getClass()) - || ft instanceof FieldType.ExternalizeStoredValuesAsObjects) { + if (ft instanceof FieldType.ExternalizeStoredValuesAsObjects) { return ft.toObject(f); } else { return ft.toExternal(f); } } } - - static { - // DO NOT ADD TO THIS SET ! ! ! ! - // SEE JAVADOCS FOR KNOWN_TYPES ! - - KNOWN_TYPES.add(BoolField.class); - KNOWN_TYPES.add(StrField.class); - KNOWN_TYPES.add(TextField.class); - KNOWN_TYPES.add(TrieField.class); - KNOWN_TYPES.add(TrieIntField.class); - KNOWN_TYPES.add(TrieLongField.class); - KNOWN_TYPES.add(TrieFloatField.class); - KNOWN_TYPES.add(TrieDoubleField.class); - KNOWN_TYPES.add(TrieDateField.class); - KNOWN_TYPES.add(BinaryField.class); - KNOWN_TYPES.add(IntPointField.class); - KNOWN_TYPES.add(LongPointField.class); - KNOWN_TYPES.add(DoublePointField.class); - KNOWN_TYPES.add(FloatPointField.class); - // DenseVectorField extends FloatPointField but here we list DenseVectorField - // explicitly due to KNOWN_TYPES.contains use of the KNOWN_TYPES set - KNOWN_TYPES.add(DenseVectorField.class); - KNOWN_TYPES.add(DatePointField.class); - // We do not add UUIDField because UUID object is not a supported type in JavaBinCodec - // and if we write UUIDField.toObject, we wouldn't know how to handle it in the client side - - // DO NOT ADD TO THIS SET ! ! ! ! - // SEE JAVADOCS FOR KNOWN_TYPES ! - } } diff --git a/solr/core/src/java/org/apache/solr/schema/BinaryField.java b/solr/core/src/java/org/apache/solr/schema/BinaryField.java index d752d20916ae..9d955e66935b 100644 --- a/solr/core/src/java/org/apache/solr/schema/BinaryField.java +++ b/solr/core/src/java/org/apache/solr/schema/BinaryField.java @@ -34,7 +34,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class BinaryField extends FieldType { +public class BinaryField extends FieldType implements FieldType.ExternalizeStoredValuesAsObjects { private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); diff --git a/solr/core/src/java/org/apache/solr/schema/BoolField.java b/solr/core/src/java/org/apache/solr/schema/BoolField.java index cefd4a0bdbe7..694da33ae730 100644 --- a/solr/core/src/java/org/apache/solr/schema/BoolField.java +++ b/solr/core/src/java/org/apache/solr/schema/BoolField.java @@ -46,7 +46,8 @@ import org.apache.solr.uninverting.UninvertingReader.Type; /** */ -public class BoolField extends PrimitiveFieldType { +public class BoolField extends PrimitiveFieldType + implements FieldType.ExternalizeStoredValuesAsObjects { @Override public SortField getSortField(SchemaField field, boolean reverse) { field.checkSortability(); diff --git a/solr/core/src/java/org/apache/solr/schema/DatePointField.java b/solr/core/src/java/org/apache/solr/schema/DatePointField.java index 83e3ac916996..77ece0365560 100644 --- a/solr/core/src/java/org/apache/solr/schema/DatePointField.java +++ b/solr/core/src/java/org/apache/solr/schema/DatePointField.java @@ -98,7 +98,8 @@ * * @see PointField */ -public class DatePointField extends PointField implements DateValueFieldType { +public class DatePointField extends PointField + implements DateValueFieldType, FieldType.ExternalizeStoredValuesAsObjects { public DatePointField() { type = NumberType.DATE; diff --git a/solr/core/src/java/org/apache/solr/schema/DoublePointField.java b/solr/core/src/java/org/apache/solr/schema/DoublePointField.java index 70cc45bfd5a7..409f8697023f 100644 --- a/solr/core/src/java/org/apache/solr/schema/DoublePointField.java +++ b/solr/core/src/java/org/apache/solr/schema/DoublePointField.java @@ -41,7 +41,8 @@ * @see PointField * @see DoublePoint */ -public class DoublePointField extends PointField implements DoubleValueFieldType { +public class DoublePointField extends PointField + implements DoubleValueFieldType, FieldType.ExternalizeStoredValuesAsObjects { public DoublePointField() { type = NumberType.DOUBLE; diff --git a/solr/core/src/java/org/apache/solr/schema/FieldType.java b/solr/core/src/java/org/apache/solr/schema/FieldType.java index 971235e07b58..54944ddc44db 100644 --- a/solr/core/src/java/org/apache/solr/schema/FieldType.java +++ b/solr/core/src/java/org/apache/solr/schema/FieldType.java @@ -1506,12 +1506,16 @@ protected static Object unmarshalBase64SortValue(Object value) { * representation that will be returned to clients. * *

The default behavior if this interface is not implemented, is to delegate to {@link - * FieldType#toExternal(IndexableField)}, unless the field type is (exactly equal to) one of a - * specific list of {@link org.apache.solr.response.DocsStreamer#KNOWN_TYPES} + * FieldType#toExternal(IndexableField)}. + * + *

This interface is checked with {@code instanceof}, so subclasses of a field type that + * implements it are trusted as well. {@link UUIDField}, for example, inherits it from {@link + * StrField} and must keep returning a String from {@link FieldType#toObject(IndexableField)}: a + * {@code UUID} object is not a type {@code JavaBinCodec} can write, and clients would not know + * how to handle it. * * @see #toExternal * @see #toObject(IndexableField) - * @see org.apache.solr.response.DocsStreamer#KNOWN_TYPES */ public static interface ExternalizeStoredValuesAsObjects {} diff --git a/solr/core/src/java/org/apache/solr/schema/FloatPointField.java b/solr/core/src/java/org/apache/solr/schema/FloatPointField.java index 4ed65fe45c3b..9363e2003dbc 100644 --- a/solr/core/src/java/org/apache/solr/schema/FloatPointField.java +++ b/solr/core/src/java/org/apache/solr/schema/FloatPointField.java @@ -41,7 +41,8 @@ * @see PointField * @see FloatPoint */ -public class FloatPointField extends PointField implements FloatValueFieldType { +public class FloatPointField extends PointField + implements FloatValueFieldType, FieldType.ExternalizeStoredValuesAsObjects { public FloatPointField() { type = NumberType.FLOAT; diff --git a/solr/core/src/java/org/apache/solr/schema/IntPointField.java b/solr/core/src/java/org/apache/solr/schema/IntPointField.java index 5f44195286b7..b9853d60f234 100644 --- a/solr/core/src/java/org/apache/solr/schema/IntPointField.java +++ b/solr/core/src/java/org/apache/solr/schema/IntPointField.java @@ -39,7 +39,8 @@ * @see PointField * @see IntPoint */ -public class IntPointField extends PointField implements IntValueFieldType { +public class IntPointField extends PointField + implements IntValueFieldType, FieldType.ExternalizeStoredValuesAsObjects { public IntPointField() { type = NumberType.INTEGER; diff --git a/solr/core/src/java/org/apache/solr/schema/LongPointField.java b/solr/core/src/java/org/apache/solr/schema/LongPointField.java index 8aa32e77cfea..fe5c2368bc14 100644 --- a/solr/core/src/java/org/apache/solr/schema/LongPointField.java +++ b/solr/core/src/java/org/apache/solr/schema/LongPointField.java @@ -39,7 +39,8 @@ * @see PointField * @see LongPoint */ -public class LongPointField extends PointField implements LongValueFieldType { +public class LongPointField extends PointField + implements LongValueFieldType, FieldType.ExternalizeStoredValuesAsObjects { public LongPointField() { type = NumberType.LONG; diff --git a/solr/core/src/java/org/apache/solr/schema/StrField.java b/solr/core/src/java/org/apache/solr/schema/StrField.java index bc437553fe43..fca41f4b3511 100644 --- a/solr/core/src/java/org/apache/solr/schema/StrField.java +++ b/solr/core/src/java/org/apache/solr/schema/StrField.java @@ -34,7 +34,8 @@ import org.apache.solr.search.QParser; import org.apache.solr.uninverting.UninvertingReader.Type; -public class StrField extends PrimitiveFieldType { +public class StrField extends PrimitiveFieldType + implements FieldType.ExternalizeStoredValuesAsObjects { @Override protected void init(IndexSchema schema, Map args) { diff --git a/solr/core/src/java/org/apache/solr/schema/TextField.java b/solr/core/src/java/org/apache/solr/schema/TextField.java index 549b10c4cdfc..4b4db4e7b45f 100644 --- a/solr/core/src/java/org/apache/solr/schema/TextField.java +++ b/solr/core/src/java/org/apache/solr/schema/TextField.java @@ -44,7 +44,7 @@ * TextField is the basic type for configurable text analysis. Analyzers for field * types using this implementation should be defined in the schema. */ -public class TextField extends FieldType { +public class TextField extends FieldType implements FieldType.ExternalizeStoredValuesAsObjects { protected boolean autoGeneratePhraseQueries; protected boolean enableGraphQueries; protected SolrQueryParserBase.SynonymQueryStyle synonymQueryStyle; diff --git a/solr/core/src/java/org/apache/solr/schema/TrieField.java b/solr/core/src/java/org/apache/solr/schema/TrieField.java index 9512176d33d1..01549b11dc78 100644 --- a/solr/core/src/java/org/apache/solr/schema/TrieField.java +++ b/solr/core/src/java/org/apache/solr/schema/TrieField.java @@ -88,7 +88,8 @@ * @see PointField */ @Deprecated -public class TrieField extends NumericFieldType { +public class TrieField extends NumericFieldType + implements FieldType.ExternalizeStoredValuesAsObjects { public static final int DEFAULT_PRECISION_STEP = 8; protected int precisionStepArg = diff --git a/solr/core/src/test/org/apache/solr/response/DocsStreamerTest.java b/solr/core/src/test/org/apache/solr/response/DocsStreamerTest.java index 86507c6a3a3e..b646705c2348 100644 --- a/solr/core/src/test/org/apache/solr/response/DocsStreamerTest.java +++ b/solr/core/src/test/org/apache/solr/response/DocsStreamerTest.java @@ -44,17 +44,17 @@ public void testDenseVectorField() throws Exception { } } - // ScalarQuantizedDenseVectorField is a subclass of DenseVectorField, and KNOWN_TYPES is - // consulted on an equality basis, so the subclass does not take the toObject path its - // superclass takes: its stored values are externalized as Strings by FieldType.toExternal. - // This pins that difference so it cannot change without a test failing. + // ScalarQuantizedDenseVectorField is a subclass of DenseVectorField, and the + // ExternalizeStoredValuesAsObjects marker is consulted with instanceof, so the subclass takes + // the same toObject path as its superclass: its stored values are externalized as Floats. + // This pins that agreement so it cannot change without a test failing. public void testScalarQuantizedDenseVectorField() throws Exception { try { initCore("solrconfig_codec.xml", "schema-densevector-quantized.xml"); - // plain DenseVectorField, an exact match in KNOWN_TYPES: Float objects + // plain DenseVectorField, marker inherited from FloatPointField: Float objects assertStoredValues("vector", VECTOR); - // subclass of it, so no exact match: Strings - assertStoredValues("v_scalar_default", stringsOf(VECTOR)); + // subclass of it, so it inherits the marker too: Float objects as well + assertStoredValues("v_scalar_default", VECTOR); } finally { deleteCore(); } @@ -64,7 +64,7 @@ public void testScalarQuantizedDenseVectorField() throws Exception { public void testBinaryQuantizedDenseVectorField() throws Exception { try { initCore("solrconfig-basic.xml", "schema-densevector-bq.xml"); - assertStoredValues("v_bq", stringsOf(VECTOR)); + assertStoredValues("v_bq", VECTOR); } finally { deleteCore(); } @@ -85,8 +85,4 @@ private void assertStoredValues(String fieldName, List expected) { assertEquals(label, want, value); } } - - private static List stringsOf(List values) { - return values.stream().map(String::valueOf).toList(); - } } diff --git a/solr/core/src/test/org/apache/solr/schema/TestBinaryField.java b/solr/core/src/test/org/apache/solr/schema/TestBinaryField.java index 157cccbbb82a..6c970f0f56c5 100644 --- a/solr/core/src/test/org/apache/solr/schema/TestBinaryField.java +++ b/solr/core/src/test/org/apache/solr/schema/TestBinaryField.java @@ -137,7 +137,7 @@ public void testSimple() throws Exception { assertArrayEquals(expected_bytes, (byte[]) d.getFieldValue("rev_data")); assertArrayEquals(expected_bytes, (byte[]) d.getFieldValue("rev_data_dv")); - assertEquals(expected_string, d.getFieldValue("str_data")); + assertArrayEquals(expected_bytes, (byte[]) d.getFieldValue("str_data")); assertEquals(expected_string, d.getFieldValue("str_data_dv")); } for (Bean d : beans) { @@ -151,7 +151,7 @@ public void testSimple() throws Exception { assertArrayEquals(expected_bytes, d.rev_data); assertArrayEquals(expected_bytes, d.rev_data_dv); - assertEquals(expected_string, d.str_data); + assertArrayEquals(expected_bytes, d.str_data); assertEquals(expected_string, d.str_data_dv); } } @@ -170,7 +170,7 @@ public static class Bean { @Field byte[] data_dv; @Field byte[] rev_data; @Field byte[] rev_data_dv; - @Field String str_data; + @Field byte[] str_data; @Field String str_data_dv; } }