github.com/confluentinc/confluent-kafka-go@v1.9.2/schemaregistry/serde/avro/avro_specific.go (about) 1 /** 2 * Copyright 2022 Confluent Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package avro 18 19 import ( 20 "bytes" 21 "fmt" 22 "io" 23 24 "github.com/actgardner/gogen-avro/v10/compiler" 25 "github.com/actgardner/gogen-avro/v10/parser" 26 "github.com/actgardner/gogen-avro/v10/schema" 27 "github.com/actgardner/gogen-avro/v10/vm" 28 "github.com/actgardner/gogen-avro/v10/vm/types" 29 "github.com/confluentinc/confluent-kafka-go/schemaregistry" 30 "github.com/confluentinc/confluent-kafka-go/schemaregistry/serde" 31 ) 32 33 // SpecificSerializer represents a specific Avro serializer 34 type SpecificSerializer struct { 35 serde.BaseSerializer 36 } 37 38 // SpecificDeserializer represents a specific Avro deserializer 39 type SpecificDeserializer struct { 40 serde.BaseDeserializer 41 } 42 43 var _ serde.Serializer = new(SpecificSerializer) 44 var _ serde.Deserializer = new(SpecificDeserializer) 45 46 // SpecificAvroMessage represents a generated Avro class from gogen-avro 47 type SpecificAvroMessage interface { 48 types.Field 49 Serialize(w io.Writer) error 50 Schema() string 51 } 52 53 // NewSpecificSerializer creates an Avro serializer for Avro-generated objects 54 func NewSpecificSerializer(client schemaregistry.Client, serdeType serde.Type, conf *SerializerConfig) (*SpecificSerializer, error) { 55 s := &SpecificSerializer{} 56 err := s.ConfigureSerializer(client, serdeType, &conf.SerializerConfig) 57 if err != nil { 58 return nil, err 59 } 60 return s, nil 61 } 62 63 // Serialize implements serialization of specific Avro data 64 func (s *SpecificSerializer) Serialize(topic string, msg interface{}) ([]byte, error) { 65 if msg == nil { 66 return nil, nil 67 } 68 var avroMsg SpecificAvroMessage 69 switch t := msg.(type) { 70 case SpecificAvroMessage: 71 avroMsg = t 72 default: 73 return nil, fmt.Errorf("serialization target must be an avro message. Got '%v'", t) 74 } 75 var id = 0 76 info := schemaregistry.SchemaInfo{ 77 Schema: avroMsg.Schema(), 78 } 79 id, err := s.GetID(topic, avroMsg, info) 80 if err != nil { 81 return nil, err 82 } 83 var buf bytes.Buffer 84 err = avroMsg.Serialize(&buf) 85 if err != nil { 86 return nil, err 87 } 88 payload, err := s.WriteBytes(id, buf.Bytes()) 89 if err != nil { 90 return nil, err 91 } 92 return payload, nil 93 } 94 95 // NewSpecificDeserializer creates an Avro deserializer for Avro-generated objects 96 func NewSpecificDeserializer(client schemaregistry.Client, serdeType serde.Type, conf *DeserializerConfig) (*SpecificDeserializer, error) { 97 s := &SpecificDeserializer{} 98 err := s.ConfigureDeserializer(client, serdeType, &conf.DeserializerConfig) 99 if err != nil { 100 return nil, err 101 } 102 return s, nil 103 } 104 105 // Deserialize implements deserialization of specific Avro data 106 func (s *SpecificDeserializer) Deserialize(topic string, payload []byte) (interface{}, error) { 107 if payload == nil { 108 return nil, nil 109 } 110 info, err := s.GetSchema(topic, payload) 111 if err != nil { 112 return nil, err 113 } 114 writer, err := s.toAvroType(info) 115 if err != nil { 116 return nil, err 117 } 118 subject, err := s.SubjectNameStrategy(topic, s.SerdeType, info) 119 if err != nil { 120 return nil, err 121 } 122 msg, err := s.MessageFactory(subject, writer.Name()) 123 if err != nil { 124 return nil, err 125 } 126 var avroMsg SpecificAvroMessage 127 switch t := msg.(type) { 128 case SpecificAvroMessage: 129 avroMsg = t 130 default: 131 return nil, fmt.Errorf("deserialization target must be an avro message. Got '%v'", t) 132 } 133 reader, err := s.toAvroType(schemaregistry.SchemaInfo{Schema: avroMsg.Schema()}) 134 if err != nil { 135 return nil, err 136 } 137 deser, err := compiler.Compile(writer, reader) 138 if err != nil { 139 return nil, err 140 } 141 r := bytes.NewReader(payload[5:]) 142 return vm.Eval(r, deser, avroMsg), nil 143 } 144 145 // DeserializeInto implements deserialization of specific Avro data to the given object 146 func (s *SpecificDeserializer) DeserializeInto(topic string, payload []byte, msg interface{}) error { 147 if payload == nil { 148 return nil 149 } 150 var avroMsg SpecificAvroMessage 151 switch t := msg.(type) { 152 case SpecificAvroMessage: 153 avroMsg = t 154 default: 155 return fmt.Errorf("serialization target must be an avro message. Got '%v'", t) 156 } 157 info, err := s.GetSchema(topic, payload) 158 if err != nil { 159 return err 160 } 161 writer, err := s.toAvroType(info) 162 if err != nil { 163 return err 164 } 165 reader, err := s.toAvroType(schemaregistry.SchemaInfo{Schema: avroMsg.Schema()}) 166 if err != nil { 167 return err 168 } 169 deser, err := compiler.Compile(writer, reader) 170 if err != nil { 171 return err 172 } 173 r := bytes.NewReader(payload[5:]) 174 return vm.Eval(r, deser, avroMsg) 175 } 176 177 func (s *SpecificDeserializer) toAvroType(schema schemaregistry.SchemaInfo) (schema.AvroType, error) { 178 ns := parser.NewNamespace(false) 179 return resolveAvroReferences(s.Client, schema, ns) 180 }