@@ -233,4 +233,110 @@ public void testBigDecimalUnionPrefersBytesOverDouble() throws Exception
233233 assertThat ((BigDecimal ) result .get ("value" )).isEqualByComparingTo (input );
234234 }
235235
236+ // Verify that plain BYTES (without "decimal" logical type) is NOT chosen for
237+ // BigDecimal: conversion would fail, so DOUBLE must be used instead
238+ @ Test
239+ public void testBigDecimalUnionSkipsPlainBytes () throws Exception
240+ {
241+ String schemaJson = a2q ("{" +
242+ "'type':'record'," +
243+ "'name':'Test'," +
244+ "'fields':[" +
245+ " {'name':'value', 'type':['null','bytes','double']}" +
246+ "]" +
247+ "}" );
248+ AvroSchema schema = MAPPER .schemaFrom (schemaJson );
249+
250+ BigDecimal input = BigDecimal .valueOf (123456789 , 6 );
251+ Map <String , Object > data = Map .of ("value" , input );
252+ byte [] bytes = MAPPER .writer (schema ).writeValueAsBytes (data );
253+
254+ Map <String , Object > result = MAPPER .readerFor (Map .class )
255+ .with (schema )
256+ .readValue (bytes );
257+ // Written as DOUBLE (index 2) since plain `bytes` cannot hold a BigDecimal
258+ assertThat (result .get ("value" )).isInstanceOf (Double .class );
259+ assertThat ((Double ) result .get ("value" )).isEqualTo (input .doubleValue ());
260+ }
261+
262+ // Verify that "decimal" BYTES wins over STRING even when declared later:
263+ // preference is by type fidelity, not by declaration order
264+ @ Test
265+ public void testBigDecimalUnionPrefersBytesOverString () throws Exception
266+ {
267+ String schemaJson = a2q ("{" +
268+ "'type':'record'," +
269+ "'name':'Test'," +
270+ "'fields':[" +
271+ " {'name':'value', 'type':['null','string'," +
272+ " {'type':'bytes','logicalType':'decimal','precision':20,'scale':6}," +
273+ " 'double']}" +
274+ "]" +
275+ "}" );
276+ AvroSchema schema = MAPPER .schemaFrom (schemaJson );
277+
278+ BigDecimal input = BigDecimal .valueOf (123456789 , 6 );
279+ Map <String , Object > data = Map .of ("value" , input );
280+ byte [] bytes = MAPPER .writer (schema ).writeValueAsBytes (data );
281+
282+ Map <String , Object > result = MAPPER .readerFor (Map .class )
283+ .with (schema )
284+ .readValue (bytes );
285+ assertThat (result .get ("value" )).isInstanceOf (BigDecimal .class );
286+ assertThat ((BigDecimal ) result .get ("value" )).isEqualByComparingTo (input );
287+ }
288+
289+ // Verify that FIXED with "decimal" logical type is also usable for BigDecimal
290+ @ Test
291+ public void testBigDecimalUnionPrefersFixedOverString () throws Exception
292+ {
293+ String schemaJson = a2q ("{" +
294+ "'type':'record'," +
295+ "'name':'Test'," +
296+ "'fields':[" +
297+ " {'name':'value', 'type':['null','string'," +
298+ " {'type':'fixed','name':'Dec','size':16," +
299+ " 'logicalType':'decimal','precision':20,'scale':6}," +
300+ " 'double']}" +
301+ "]" +
302+ "}" );
303+ AvroSchema schema = MAPPER .schemaFrom (schemaJson );
304+
305+ BigDecimal input = BigDecimal .valueOf (123456789 , 6 );
306+ Map <String , Object > data = Map .of ("value" , input );
307+ byte [] bytes = MAPPER .writer (schema ).writeValueAsBytes (data );
308+
309+ Map <String , Object > result = MAPPER .readerFor (Map .class )
310+ .with (schema )
311+ .readValue (bytes );
312+ assertThat (result .get ("value" )).isInstanceOf (BigDecimal .class );
313+ assertThat ((BigDecimal ) result .get ("value" )).isEqualByComparingTo (input );
314+ }
315+
316+ // Verify that plain FIXED (without "decimal" logical type) is not chosen either
317+ @ Test
318+ public void testBigDecimalUnionSkipsPlainFixed () throws Exception
319+ {
320+ String schemaJson = a2q ("{" +
321+ "'type':'record'," +
322+ "'name':'Test'," +
323+ "'fields':[" +
324+ " {'name':'value', 'type':['null'," +
325+ " {'type':'fixed','name':'Raw','size':16}," +
326+ " 'double']}" +
327+ "]" +
328+ "}" );
329+ AvroSchema schema = MAPPER .schemaFrom (schemaJson );
330+
331+ BigDecimal input = BigDecimal .valueOf (123456789 , 6 );
332+ Map <String , Object > data = Map .of ("value" , input );
333+ byte [] bytes = MAPPER .writer (schema ).writeValueAsBytes (data );
334+
335+ Map <String , Object > result = MAPPER .readerFor (Map .class )
336+ .with (schema )
337+ .readValue (bytes );
338+ assertThat (result .get ("value" )).isInstanceOf (Double .class );
339+ assertThat ((Double ) result .get ("value" )).isEqualTo (input .doubleValue ());
340+ }
341+
236342}
0 commit comments