github.com/keysonZZZ/kmg@v0.0.0-20151121023212-05317bfd7d39/kmgRpc/kmgRpcJava/reflect.go (about)

     1  package kmgRpcJava
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/bronze1man/kmg/kmgGoSource/kmgGoParser"
     7  	"github.com/bronze1man/kmg/kmgStrings"
     8  	"strconv"
     9  )
    10  
    11  func reflectToTplConfig(req *GenerateRequest) *tplConfig {
    12  	config := &tplConfig{
    13  		OutPackageName: req.OutPackageName,
    14  		ClassName:      req.OutClassName,
    15  		innerClassMap:  map[string]*InnerClass{},
    16  	}
    17  	if req.ApiNameFilterCb == nil {
    18  		req.ApiNameFilterCb = func(name string) bool {
    19  			return true
    20  		}
    21  	}
    22  
    23  	pkg := kmgGoParser.NewProgramFromDefault().GetPackage(req.ObjectPkgPath)
    24  	//pkg := kmgGoParser.MustParsePackage(kmgConfig.DefaultEnv().GOPATHToString(), req.ObjectPkgPath)
    25  	namedTyp := pkg.LookupNamedType(req.ObjectName)
    26  	if namedTyp == nil {
    27  		panic(fmt.Errorf("can not find this object. [%s]", req.ObjectName))
    28  	}
    29  	objTyp := kmgGoParser.Type(namedTyp)
    30  	if req.ObjectIsPointer {
    31  		objTyp = kmgGoParser.NewPointer(objTyp)
    32  	}
    33  	//获取 object 上面所有的方法
    34  	methodList := pkg.GetNamedTypeMethodSet(namedTyp)
    35  	for _, methodObj := range methodList {
    36  		if !methodObj.IsExport() {
    37  			continue
    38  		}
    39  		if !req.ApiNameFilterCb(methodObj.Name) {
    40  			continue
    41  		}
    42  		api := Api{
    43  			Name: methodObj.Name,
    44  		}
    45  		RequestInnerClass := &InnerClass{
    46  			Name:     api.Name + "RpcRequest",
    47  			IsPublic: false,
    48  		}
    49  		for _, pairObj := range methodObj.InParameter {
    50  			if isPointerToKmgHttpContext(pairObj.Type) {
    51  				// 此处忽略掉特殊传入参数 *kmgHttp.Context
    52  				continue
    53  			}
    54  			pair := NameTypePair{
    55  				Name: kmgStrings.FirstLetterToUpper(pairObj.Name),
    56  			}
    57  			pair.TypeStr = config.addType(pairObj.Type)
    58  			api.InArgsList = append(api.InArgsList, pair)
    59  			RequestInnerClass.FieldList = append(RequestInnerClass.FieldList, pair)
    60  		}
    61  		config.addInnerClass(RequestInnerClass)
    62  		/*
    63  		 * 在java中,如果输出参数的类型是error,会转到exception里面
    64  		 * 在java中,如果输出参数去除error后,没有参数了,java函数不会返回参数
    65  		 * 在java中,如果输出参数除去error后,还有1个,直接返回这个类型,此时此参数依然按照前面的说法进行向前兼容.
    66  		 * 在java中,如果输出参数除去error后,还有2个及2个以上,返回一个class,这个class包含这些个参数.
    67  		 */
    68  		notErrorOutParameter := []NameTypePair{}
    69  		for i, pairObj := range methodObj.OutParameter {
    70  			builtintyp, ok := pairObj.Type.(kmgGoParser.BuiltinType)
    71  			if !(ok && string(builtintyp) == "error") {
    72  				name := kmgStrings.FirstLetterToUpper(pairObj.Name)
    73  				if name == "" {
    74  					name = "Out_" + strconv.Itoa(i)
    75  				}
    76  				notErrorOutParameter = append(notErrorOutParameter, NameTypePair{
    77  					Name:    name,
    78  					TypeStr: config.addType(pairObj.Type),
    79  				})
    80  			}
    81  		}
    82  		if len(notErrorOutParameter) == 0 {
    83  			api.OutTypeString = "void"
    84  		} else {
    85  			responseInnerClass := &InnerClass{
    86  				Name:      api.Name + "RpcResponse",
    87  				FieldList: notErrorOutParameter,
    88  				IsPublic:  true,
    89  			}
    90  			config.addInnerClass(responseInnerClass)
    91  
    92  			if len(notErrorOutParameter) == 1 {
    93  				api.OutTypeString = notErrorOutParameter[0].TypeStr
    94  				api.OutTypeFieldName = notErrorOutParameter[0].Name
    95  			} else {
    96  				api.OutTypeString = responseInnerClass.Name
    97  			}
    98  		}
    99  		config.ApiList = append(config.ApiList, api)
   100  	}
   101  	return config
   102  }
   103  
   104  func isPointerToKmgHttpContext(typi kmgGoParser.Type) bool {
   105  	typ1, ok := typi.(kmgGoParser.PointerType)
   106  	if !ok {
   107  		return false
   108  	}
   109  	typ2, ok := typ1.Elem.(*kmgGoParser.NamedType)
   110  	if !ok {
   111  		return false
   112  	}
   113  	return typ2.Name == "Context" && typ2.PackagePath == "github.com/bronze1man/kmg/kmgNet/kmgHttp"
   114  }
   115  
   116  func (config *tplConfig) addType(typi kmgGoParser.Type) string {
   117  	switch typ := typi.(type) {
   118  	//case kmgGoParser.FuncType:
   119  	//	panic("TODO")
   120  	case kmgGoParser.PointerType:
   121  		return config.addType(typ.Elem)
   122  	case *kmgGoParser.NamedType:
   123  		if typ.Name == "Time" && typ.PackagePath == "time" {
   124  			return "Date"
   125  		}
   126  		// TODO 命名重复?
   127  		name := typ.Name
   128  		ntyp := config.innerClassMap[name]
   129  		if ntyp != nil {
   130  			return name
   131  		}
   132  		switch utyp := typ.GetUnderType().(type) {
   133  		case kmgGoParser.StructType:
   134  			innerClass := &InnerClass{
   135  				Name:     name,
   136  				IsPublic: true,
   137  			}
   138  			config.addInnerClass(innerClass) // 避免循环引用导致出现bug.
   139  			for i := range utyp.Field {
   140  				innerClass.FieldList = append(innerClass.FieldList, NameTypePair{
   141  					Name:    utyp.Field[i].Name,
   142  					TypeStr: config.addType(utyp.Field[i].Elem),
   143  				})
   144  			}
   145  			return name
   146  		default:
   147  			return config.addType(utyp)
   148  		}
   149  	case kmgGoParser.BuiltinType:
   150  		s, ok := builtinTypeMap[string(typ)]
   151  		if !ok {
   152  			panic("not support BuiltinType " + string(typ))
   153  		}
   154  		return s
   155  	case kmgGoParser.SliceType:
   156  		return "List<" + config.addType(typ.Elem) + ">"
   157  	default:
   158  		panic(fmt.Errorf("TODO %T", typi))
   159  	}
   160  }
   161  
   162  var builtinTypeMap = map[string]string{
   163  	"string":  "String",
   164  	"int":     "Integer",
   165  	"int64":   "Long",
   166  	"float64": "Float",
   167  	"bool":    "Boolean",
   168  	"byte":    "Byte",
   169  }