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,13 +52,16 @@ 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 public static class ApacheImplEncoding extends CustomEncoding <CustomComponent > {
6062
6163 public ApacheImplEncoding () {
62- schema = ApacheAvroInteropUtil .getJacksonSchema (CustomComponent .class );
64+ schema = ApacheAvroInteropUtil .getApacheSchema (CustomComponent .class );
6365 }
6466
6567 @ Override
@@ -74,8 +76,67 @@ protected CustomComponent read(Object reuse, Decoder in) throws IOException {
7476
7577 }
7678
77- protected Wrapper wrapper ;
79+ public static class UuidAsBytesAvroEncoding extends CustomEncoding <UUID > {
80+ public static byte [] asByteArray (UUID uuid ) {
81+ long msb = uuid .getMostSignificantBits ();
82+ long lsb = uuid .getLeastSignificantBits ();
83+ byte [] buffer = new byte [16 ];
84+ for (int i = 0 ; i < 8 ; i ++) {
85+ buffer [i ] = (byte ) (msb >>> 8 * (7 - i ));
86+ }
87+ for (int i = 8 ; i < 16 ; i ++) {
88+ buffer [i ] = (byte ) (lsb >>> 8 * (7 - i ));
89+ }
90+ return buffer ;
91+ }
7892
93+ public static UUID toUUID (byte [] byteArray ) {
94+ long msb = 0 ;
95+ long lsb = 0 ;
96+ for (int i = 0 ; i < 8 ; i ++) { msb = (msb << 8 ) | (byteArray [i ] & 0xff ); }
97+ for (int i = 8 ; i < 16 ; i ++) { lsb = (lsb << 8 ) | (byteArray [i ] & 0xff ); }
98+ return new UUID (msb , lsb );
99+ }
100+
101+ public UuidAsBytesAvroEncoding () {
102+ this .schema = SchemaBuilder .unionOf ().nullType ().and ().bytesBuilder ().endBytes ().endUnion ();
103+ }
104+
105+ @ Override
106+ public void write (Object datum , Encoder encoder ) throws IOException {
107+ if (datum == null ) {
108+ encoder .writeIndex (0 );
109+ encoder .writeNull ();
110+ return ;
111+ }
112+ encoder .writeIndex (1 );
113+ encoder .writeBytes (asByteArray ((UUID ) datum ));
114+ }
115+
116+ @ Override
117+ public UUID read (Object datum , Decoder decoder ) throws IOException {
118+ try {
119+ // get index in union
120+ int index = decoder .readIndex ();
121+ if (index == 1 ) {
122+ // read in 16 bytes of data
123+ ByteBuffer b = ByteBuffer .allocate (16 );
124+ decoder .readBytes (b );
125+ // convert
126+ UUID uuid = toUUID (b .array ());
127+ return uuid ;
128+ } else {
129+ decoder .readNull ();
130+ // no uuid present
131+ return null ;
132+ }
133+ } catch (Exception exception ) {
134+ throw new IllegalStateException ("Could not decode bytes into UUID" , exception );
135+ }
136+ }
137+ }
138+
139+ protected Wrapper wrapper ;
79140 protected Wrapper result ;
80141
81142 @ Before
@@ -92,6 +153,7 @@ public void setup() throws IOException {
92153 mv .put ("cats" , new ArrayList <Integer >());
93154 mv .put ("dogs" , new ArrayList <>(Arrays .asList (-1234 , 56 , 6767 , 54134 , 57 , 86 )));
94155 wrapper .component .stringValue = "Hello World!" ;
156+ wrapper .component .uuidValue = UUID .randomUUID ();
95157
96158 CustomComponent cc = new CustomComponent ();
97159 cc .byteValue = (byte ) 42 ;
@@ -100,8 +162,8 @@ public void setup() throws IOException {
100162 cc .doubleValue = Double .POSITIVE_INFINITY ;
101163 cc .longValue = Long .MAX_VALUE ;
102164 cc .stringValue = "Nested Hello World!" ;
165+ cc .uuidValue = UUID .randomUUID ();
103166 wrapper .component .nestedRecordValue = cc ;
104-
105167 //
106168 result = roundTrip (wrapper );
107169 }
@@ -136,4 +198,13 @@ public void testIntegerValue() {
136198 assertThat (result .component .intValue ).isEqualTo (wrapper .component .intValue );
137199 }
138200
201+ @ Test
202+ public void testNestedUuidValue () {
203+ assertThat (result .component .nestedRecordValue .uuidValue ).isEqualTo (wrapper .component .nestedRecordValue .uuidValue );
204+ }
205+
206+ @ Test
207+ public void testUuidValue () {
208+ assertThat (result .component .uuidValue ).isEqualTo (wrapper .component .uuidValue );
209+ }
139210}
0 commit comments