feat: support exception fields in BinaryConv t2j (#21)
* support exception field * delete unused fields * delete unused file * optimize * return json string * add comments * fix comment
This commit is contained in:
parent
e68c1c1068
commit
962f7eaad2
20
conv/api.go
20
conv/api.go
|
@ -48,18 +48,18 @@ var (
|
|||
)
|
||||
|
||||
type Options struct {
|
||||
|
||||
|
||||
// EnableValueMapping indicates if value mapping (api.js_conv...) should be enabled
|
||||
EnableValueMapping bool
|
||||
// EnableHttpMapping indicates if http mapping (api.query|api.header...) should be enabled
|
||||
EnableHttpMapping bool
|
||||
// EnableThriftBase indicates if thrift/base should be recoginized and mapping to/from context
|
||||
// EnableThriftBase indicates if thrift/base should be recognized and mapping to/from context
|
||||
EnableThriftBase bool
|
||||
|
||||
|
||||
// Int64AsString indicates if string value cane be read as **Int8/Int16/Int32/Int64/Float64**,
|
||||
// or in response a **Int64** value can be written as string
|
||||
String2Int64 bool
|
||||
// NoBase64Binary indicates if base64 string shoud be Encode/Decode as []byte
|
||||
// NoBase64Binary indicates if base64 string should be Encode/Decode as []byte
|
||||
NoBase64Binary bool
|
||||
// ByteAsUint8 indicates if byte should be conv as uint8 (default is int8), this only works for t2j now
|
||||
ByteAsUint8 bool
|
||||
|
@ -73,7 +73,7 @@ type Options struct {
|
|||
WriteRequireField bool
|
||||
// DisallowUnknownField indicates if unknown fields should be skipped
|
||||
DisallowUnknownField bool
|
||||
|
||||
|
||||
// ReadHttpValueFallback indicates if http-annotated fields should fallback to http body after reading from non-body parts (header,cookie...) failed
|
||||
ReadHttpValueFallback bool
|
||||
// WriteHttpValueFallback indicates if http-annotated fields should fallback to http body after writing to non-body parts (header,cookie...) failed
|
||||
|
@ -82,15 +82,17 @@ type Options struct {
|
|||
// or root-level fields should be seeking on http-values when reading failed from current layer of json.
|
||||
// this option is only used in j2t now.
|
||||
TracebackRequredOrRootFields bool
|
||||
// OmitHttpMappingErrors indicates to omit http-mapping failing errors.
|
||||
// OmitHttpMappingErrors indicates to omit http-mapping failing errors.
|
||||
// If there are more-than-one HTTP annotations on the field, dynamicgo will try to mapping next annotation source (from left to right) until succeed.
|
||||
OmitHttpMappingErrors bool
|
||||
|
||||
|
||||
// NoCopyString indicates if string-kind http values should be copied or just referenced (if possible)
|
||||
NoCopyString bool
|
||||
// UseNativeSkip indicates if use thrift.SkipNative() or thrift.SkipGo()
|
||||
// UseNativeSkip indicates if using thrift.SkipNative() or thrift.SkipGo()
|
||||
UseNativeSkip bool
|
||||
|
||||
|
||||
// ConvertException indicates that it returns error for thrift exception fields when doing BinaryConv t2j
|
||||
ConvertException bool
|
||||
}
|
||||
|
||||
var bufPool = sync.Pool{
|
||||
|
|
|
@ -282,6 +282,28 @@ func TestAGWBodyDynamic(t *testing.T) {
|
|||
require.Equal(t, (`{"Int64":1,"Xjson":"{\"b\":1}"}`), string(out))
|
||||
}
|
||||
|
||||
func TestException(t *testing.T) {
|
||||
cv := NewBinaryConv(conv.Options{
|
||||
ConvertException: true,
|
||||
})
|
||||
desc := thrift.FnWholeResponse(thrift.GetFnDescFromFile("testdata/idl/example3.thrift", "ExampleMethod", thrift.Options{}))
|
||||
|
||||
exp := example3.NewExampleServiceExampleMethodResult()
|
||||
success := example3.NewExampleResp()
|
||||
success.Status = 202
|
||||
exception := example3.NewException()
|
||||
exception.Code = 400
|
||||
exception.Msg = "this is an exception"
|
||||
exp.Success = success
|
||||
exp.Err = exception
|
||||
ctx := context.Background()
|
||||
in := make([]byte, exp.BLength())
|
||||
_ = exp.FastWriteNocopy(in, nil)
|
||||
_, err := cv.Do(ctx, desc, in)
|
||||
require.Error(t, err)
|
||||
require.Equal(t, err.Error(), `{"code":400,"msg":"this is an exception"}`)
|
||||
}
|
||||
|
||||
func TestInt2String(t *testing.T) {
|
||||
cv := NewBinaryConv(conv.Options{
|
||||
EnableValueMapping: true,
|
||||
|
@ -323,9 +345,9 @@ func TestHttpMappingFallback(t *testing.T) {
|
|||
_ = exp.FastWriteNocopy(in, nil)
|
||||
expJSON := `{}`
|
||||
cv.SetOptions(conv.Options{
|
||||
EnableHttpMapping: true,
|
||||
EnableHttpMapping: true,
|
||||
WriteHttpValueFallback: false,
|
||||
OmitHttpMappingErrors: true,
|
||||
OmitHttpMappingErrors: true,
|
||||
})
|
||||
ctx := context.Background()
|
||||
resp := http.NewHTTPResponse()
|
||||
|
@ -346,9 +368,9 @@ func TestHttpMappingFallback(t *testing.T) {
|
|||
_ = exp.FastWriteNocopy(in, nil)
|
||||
expJSON := `{"Msg":"hello"}`
|
||||
cv.SetOptions(conv.Options{
|
||||
EnableHttpMapping: true,
|
||||
EnableHttpMapping: true,
|
||||
WriteHttpValueFallback: true,
|
||||
OmitHttpMappingErrors: true,
|
||||
OmitHttpMappingErrors: true,
|
||||
})
|
||||
ctx := context.Background()
|
||||
resp := http.NewHTTPResponse()
|
||||
|
@ -510,9 +532,9 @@ func TestJSONString(t *testing.T) {
|
|||
_ = exp.FastWriteNocopy(in, nil)
|
||||
|
||||
cv := NewBinaryConv(conv.Options{
|
||||
EnableHttpMapping: true,
|
||||
EnableHttpMapping: true,
|
||||
WriteHttpValueFallback: true,
|
||||
OmitHttpMappingErrors: true,
|
||||
OmitHttpMappingErrors: true,
|
||||
})
|
||||
ctx := context.Background()
|
||||
resp := http.NewHTTPResponse()
|
||||
|
@ -635,7 +657,6 @@ func TestOptionalDefaultValue(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
|
||||
func TestSimpleArgs(t *testing.T) {
|
||||
cv := NewBinaryConv(conv.Options{})
|
||||
|
||||
|
@ -658,4 +679,4 @@ func TestSimpleArgs(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
require.Equal(t, strconv.Itoa(math.MaxInt64), string(out))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ package t2j
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/cloudwego/dynamicgo/conv"
|
||||
|
@ -83,6 +84,8 @@ func (self *BinaryConv) do(ctx context.Context, src []byte, desc *thrift.TypeDes
|
|||
desc.Struct().Requires().CopyTo(r)
|
||||
comma := false
|
||||
|
||||
existExceptionField := false
|
||||
|
||||
for {
|
||||
_, typeId, id, e := p.ReadFieldBegin()
|
||||
if e != nil {
|
||||
|
@ -139,6 +142,13 @@ func (self *BinaryConv) do(ctx context.Context, src []byte, desc *thrift.TypeDes
|
|||
*out = json.EncodeString(*out, field.Alias())
|
||||
*out = json.EncodeObjectColon(*out)
|
||||
|
||||
// handle a thrift exception field. the id of a thrift exception field is non-zero
|
||||
if self.opts.ConvertException && id != 0 {
|
||||
existExceptionField = true
|
||||
// reset out to get only exception field data
|
||||
*out = (*out)[:0]
|
||||
}
|
||||
|
||||
if self.opts.EnableValueMapping && field.ValueMapping() != nil {
|
||||
err = field.ValueMapping().Read(ctx, &p, field, out)
|
||||
if err != nil {
|
||||
|
@ -150,6 +160,10 @@ func (self *BinaryConv) do(ctx context.Context, src []byte, desc *thrift.TypeDes
|
|||
return unwrapError(fmt.Sprintf("converting field %s of STRUCT %s failed", field.Name(), desc.Type()), err)
|
||||
}
|
||||
}
|
||||
|
||||
if existExceptionField {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if err = self.handleUnsets(r, desc.Struct(), out, comma, ctx, resp); err != nil {
|
||||
|
@ -157,7 +171,11 @@ func (self *BinaryConv) do(ctx context.Context, src []byte, desc *thrift.TypeDes
|
|||
}
|
||||
|
||||
thrift.FreeRequiresBitmap(r)
|
||||
*out = json.EncodeObjectEnd(*out)
|
||||
if existExceptionField && err == nil {
|
||||
err = errors.New(string(*out))
|
||||
} else {
|
||||
*out = json.EncodeObjectEnd(*out)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -43,6 +43,12 @@ func FnResponse(fn *FunctionDescriptor) *TypeDescriptor {
|
|||
return fn.Response().Struct().FieldById(0).Type()
|
||||
}
|
||||
|
||||
// FnWholeResponse get the normal response type
|
||||
func FnWholeResponse(fn *FunctionDescriptor) *TypeDescriptor {
|
||||
// let-it-fail: it panic when something is nil
|
||||
return fn.Response()
|
||||
}
|
||||
|
||||
// FnRequest
|
||||
// We assume the request only have one argument and the only argument it the type we want.
|
||||
func FnRequest(fn *FunctionDescriptor) *TypeDescriptor {
|
||||
|
|
Loading…
Reference in New Issue