11package com .fasterxml .jackson .dataformat .avro .interop .annotations ;
22
33import java .io .IOException ;
4- import java .util .ArrayList ;
5- import java .util .Arrays ;
6- import java .util .HashMap ;
7- import java .util .Map ;
4+ import java .nio .ByteBuffer ;
5+ import java .util .*;
86
7+ import org .apache .avro .SchemaBuilder ;
98import org .apache .avro .io .Decoder ;
109import org .apache .avro .io .Encoder ;
1110import org .apache .avro .reflect .AvroEncode ;
@@ -53,14 +52,17 @@ static class CustomComponent {
5352 @ Nullable
5453 public Long longValue ;
5554
55+ @ AvroEncode (using = UuidAsBytesAvroEncoding .class )
56+ private UUID uuidValue ;
57+
5658 protected CustomComponent () { }
5759 }
5860
5961 @ SuppressWarnings ("unchecked" )
6062 public static class ApacheImplEncoding extends CustomEncoding <CustomComponent > {
6163
6264 public ApacheImplEncoding () throws IOException {
63- schema = ApacheAvroInteropUtil .getJacksonSchema (CustomComponent .class );
65+ schema = ApacheAvroInteropUtil .getApacheSchema (CustomComponent .class );
6466 }
6567
6668 @ Override
@@ -75,8 +77,67 @@ protected CustomComponent read(Object reuse, Decoder in) throws IOException {
7577
7678 }
7779
78- protected Wrapper wrapper ;
80+ public static class UuidAsBytesAvroEncoding extends CustomEncoding <UUID > {
81+ public static byte [] asByteArray (UUID uuid ) {
82+ long msb = uuid .getMostSignificantBits ();
83+ long lsb = uuid .getLeastSignificantBits ();
84+ byte [] buffer = new byte [16 ];
85+ for (int i = 0 ; i < 8 ; i ++) {
86+ buffer [i ] = (byte ) (msb >>> 8 * (7 - i ));
87+ }
88+ for (int i = 8 ; i < 16 ; i ++) {
89+ buffer [i ] = (byte ) (lsb >>> 8 * (7 - i ));
90+ }
91+ return buffer ;
92+ }
7993
94+ public static UUID toUUID (byte [] byteArray ) {
95+ long msb = 0 ;
96+ long lsb = 0 ;
97+ for (int i = 0 ; i < 8 ; i ++) { msb = (msb << 8 ) | (byteArray [i ] & 0xff ); }
98+ for (int i = 8 ; i < 16 ; i ++) { lsb = (lsb << 8 ) | (byteArray [i ] & 0xff ); }
99+ return new UUID (msb , lsb );
100+ }
101+
102+ public UuidAsBytesAvroEncoding () {
103+ this .schema = SchemaBuilder .unionOf ().nullType ().and ().bytesBuilder ().endBytes ().endUnion ();
104+ }
105+
106+ @ Override
107+ public void write (Object datum , Encoder encoder ) throws IOException {
108+ if (datum == null ) {
109+ encoder .writeIndex (0 );
110+ encoder .writeNull ();
111+ return ;
112+ }
113+ encoder .writeIndex (1 );
114+ encoder .writeBytes (asByteArray ((UUID ) datum ));
115+ }
116+
117+ @ Override
118+ public UUID read (Object datum , Decoder decoder ) throws IOException {
119+ try {
120+ // get index in union
121+ int index = decoder .readIndex ();
122+ if (index == 1 ) {
123+ // read in 16 bytes of data
124+ ByteBuffer b = ByteBuffer .allocate (16 );
125+ decoder .readBytes (b );
126+ // convert
127+ UUID uuid = toUUID (b .array ());
128+ return uuid ;
129+ } else {
130+ decoder .readNull ();
131+ // no uuid present
132+ return null ;
133+ }
134+ } catch (Exception exception ) {
135+ throw new IllegalStateException ("Could not decode bytes into UUID" , exception );
136+ }
137+ }
138+ }
139+
140+ protected Wrapper wrapper ;
80141 protected Wrapper result ;
81142
82143 @ Before
@@ -93,6 +154,7 @@ public void setup() throws IOException {
93154 mv .put ("cats" , new ArrayList <Integer >());
94155 mv .put ("dogs" , new ArrayList <>(Arrays .asList (-1234 , 56 , 6767 , 54134 , 57 , 86 )));
95156 wrapper .component .stringValue = "Hello World!" ;
157+ wrapper .component .uuidValue = UUID .randomUUID ();
96158
97159 CustomComponent cc = new CustomComponent ();
98160 cc .byteValue = (byte ) 42 ;
@@ -101,8 +163,8 @@ public void setup() throws IOException {
101163 cc .doubleValue = Double .POSITIVE_INFINITY ;
102164 cc .longValue = Long .MAX_VALUE ;
103165 cc .stringValue = "Nested Hello World!" ;
166+ cc .uuidValue = UUID .randomUUID ();
104167 wrapper .component .nestedRecordValue = cc ;
105-
106168 //
107169 result = roundTrip (wrapper );
108170 }
@@ -137,4 +199,13 @@ public void testIntegerValue() {
137199 assertThat (result .component .intValue ).isEqualTo (wrapper .component .intValue );
138200 }
139201
202+ @ Test
203+ public void testNestedUuidValue () {
204+ assertThat (result .component .nestedRecordValue .uuidValue ).isEqualTo (wrapper .component .nestedRecordValue .uuidValue );
205+ }
206+
207+ @ Test
208+ public void testUuidValue () {
209+ assertThat (result .component .uuidValue ).isEqualTo (wrapper .component .uuidValue );
210+ }
140211}
0 commit comments