blob: 514a39dde917afd4be62b21fc4bf1e99a0624e61 [file]
/*
* 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 generic
import (
"context"
)
import (
hessian "github.com/apache/dubbo-go-hessian2"
)
import (
"dubbo.apache.org/dubbo-go/v3/common/constant"
"dubbo.apache.org/dubbo-go/v3/filter/generic/generalizer"
)
// GenericService uses for generic invoke for service call
type GenericService struct {
Invoke func(ctx context.Context, methodName string, types []string, args []hessian.Object) (any, error) `dubbo:"$invoke"`
referenceStr string
generic string
}
// NewGenericService returns a GenericService instance
func NewGenericService(referenceStr string) *GenericService {
return &GenericService{referenceStr: referenceStr, generic: constant.GenericSerializationDefault}
}
// Reference gets referenceStr from GenericService
func (s *GenericService) Reference() string {
return s.referenceStr
}
// SetGenericType sets the generic mode used by InvokeWithType to realize typed results.
func (s *GenericService) SetGenericType(generic string) error {
if isGenericDisabled(generic) {
s.generic = generic
return nil
}
if _, err := getGeneralizer(generic); err != nil {
return err
}
s.generic = generic
return nil
}
// GenericType returns the generic mode used by InvokeWithType.
func (s *GenericService) GenericType() string {
return s.generic
}
// InvokeWithType invokes the remote method and deserializes the result into the reply struct.
// The reply parameter must be a non-nil pointer to the target type.
//
// InvokeWithType uses the service generic mode to realize the result. Supported modes are
// true, gson, bean, protobuf-json, and the legacy protobuf mode (Map/Hessian semantics).
// generic=false disables generic result realization and returns an explicit error.
//
// Example usage:
//
// var user User
// err := genericService.InvokeWithType(ctx, "getUser", []string{"java.lang.String"}, []hessian.Object{"123"}, &user)
// if err != nil {
// return err
// }
// fmt.Println(user.Name, user.Age)
func (s *GenericService) InvokeWithType(ctx context.Context, methodName string, types []string, args []hessian.Object, reply any) error {
// Validate the reply pointer
replyValue, err := validateReplyPointer(reply)
if err != nil {
return err
}
g, err := s.getGeneralizer()
if err != nil {
return err
}
// Call the underlying Invoke method
result, err := s.Invoke(ctx, methodName, types, args)
if err != nil {
return err
}
if result == nil {
return nil
}
replyType := replyValue.Elem().Type()
realized, err := realizeResult(result, replyType, g)
if err != nil {
return err
}
return setRealizedReply(replyValue, realized)
}
func (s *GenericService) getGeneralizer() (generalizer.Generalizer, error) {
generic := s.GenericType()
if isGenericDisabled(generic) {
return nil, unsupportedTypedResultModeError(generic)
}
return getGeneralizer(generic)
}