blob: 200f64976f7f5e2bbe6e5cb84c44af3b12aed38b [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package generalizer
import (
"reflect"
"sync"
)
import (
perrors "github.com/pkg/errors"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/proto"
)
var (
protobufJsonGeneralizer Generalizer
protobufJsonGeneralizerOnce sync.Once
)
func GetProtobufJsonGeneralizer() Generalizer {
protobufJsonGeneralizerOnce.Do(func() {
protobufJsonGeneralizer = &ProtobufJsonGeneralizer{}
})
return protobufJsonGeneralizer
}
// ProtobufJsonGeneralizer generalizes an object to json and realizes an object from json using protobuf.
// Currently, ProtobufJsonGeneralizer is disabled temporarily until the triple protocol is ready.
type ProtobufJsonGeneralizer struct{}
func (g *ProtobufJsonGeneralizer) Generalize(obj interface{}) (interface{}, error) {
message, ok := obj.(proto.Message)
if !ok {
return nil, perrors.Errorf("unexpected type of obj(=%T), wanted is proto.Message", obj)
}
jsonbytes, err := protojson.Marshal(message)
if err != nil {
return nil, err
}
return string(jsonbytes), nil
}
func (g *ProtobufJsonGeneralizer) Realize(obj interface{}, typ reflect.Type) (interface{}, error) {
jsonbytes, ok := obj.(string)
if !ok {
return nil, perrors.Errorf("unexpected type of obj(=%T), wanted is string", obj)
}
// typ represents a struct instead of a pointer
for typ.Kind() == reflect.Ptr {
typ = typ.Elem()
}
// create the target object
ret, ok := reflect.New(typ).Interface().(proto.Message)
if !ok {
return nil, perrors.Errorf("the type of obj(=%s) should be proto.Message", typ)
}
// get the values from json
err := protojson.Unmarshal([]byte(jsonbytes), ret)
if err != nil {
return nil, err
}
return ret, nil
}
// GetType returns empty string for "protobuf-json"
func (g *ProtobufJsonGeneralizer) GetType(_ interface{}) (string, error) {
return "", nil
}