annotation-go/registry.go
crusader 08db48ce48 ing
2018-08-23 15:13:22 +09:00

399 lines
10 KiB
Go

package annotation
import (
"encoding/json"
"fmt"
"reflect"
"strings"
our "git.loafle.net/overflow/util-go/reflect"
)
type Registry interface {
Register(t reflect.Type) error
GetTypeAnnotation(t reflect.Type, at reflect.Type) (Annotation, error)
GetTypeAnnotations(t reflect.Type) (map[reflect.Type]Annotation, error)
GetFieldAnnotation(t reflect.Type, name string, at reflect.Type) (Annotation, error)
GetFieldAnnotations(t reflect.Type, name string) (map[reflect.Type]Annotation, error)
GetAllFieldAnnotations(t reflect.Type) (map[string]map[reflect.Type]Annotation, error)
GetMethodAnnotation(t reflect.Type, name string, at reflect.Type) (Annotation, error)
GetMethodAnnotations(t reflect.Type, name string) (map[reflect.Type]Annotation, error)
GetAllMethodAnnotations(t reflect.Type) (map[string]map[reflect.Type]Annotation, error)
}
func New(parent Registry) Registry {
r := &AnnotationRegistry{
parent: parent,
definitions: make(map[string]*Definition, 0),
typeDefinitions: make(map[reflect.Type]*TypeDefinition, 0),
}
if nil == r.parent {
r.parent = SystemRegistry
}
return r
}
var SystemRegistry = &AnnotationRegistry{
parent: nil,
definitions: make(map[string]*Definition, 0),
typeDefinitions: make(map[reflect.Type]*TypeDefinition, 0),
}
type AnnotationRegistry struct {
parent Registry
definitions map[string]*Definition
typeDefinitions map[reflect.Type]*TypeDefinition
}
func Register(t reflect.Type) error {
return SystemRegistry.Register(t)
}
func (r *AnnotationRegistry) Register(t reflect.Type) error {
rt, _, _ := our.GetTypeInfo(t)
fields := findAnnotatedFields(t, AnnotationType, false)
switch len(fields) {
case 0:
return fmt.Errorf("type[%s] is not Annotation", rt.Name())
case 1:
default:
return fmt.Errorf("type[%s] have only one Annotation", rt.Name())
}
f := fields[AnnotationName]
name := strings.TrimSpace(f.Tag.Get(NameTag))
if "" == name {
return fmt.Errorf("annotation name of type[%s] is not valid", rt.Name())
}
if _, ok := r.definitions[name]; ok {
return fmt.Errorf("name[%s] of annotation exist already", name)
}
r.definitions[name] = &Definition{
t: t,
rt: rt,
}
return nil
}
func findAnnotatedFields(t reflect.Type, ft reflect.Type, deep bool) map[string]*reflect.StructField {
fields := make(map[string]*reflect.StructField, 0)
rt, _, _ := our.GetTypeInfo(t)
if reflect.Struct != rt.Kind() {
return fields
}
LOOP:
for i := 0; i < rt.NumField(); i++ {
f := rt.Field(i)
if f.Anonymous {
if f.Type == ft {
fields[f.Name] = &f
continue LOOP
}
if deep {
_fields := findAnnotatedFields(f.Type, ft, deep)
for _n, _f := range _fields {
fields[_n] = _f
}
}
}
}
return fields
}
func (r *AnnotationRegistry) getAnnotation(f *reflect.StructField) (map[reflect.Type]Annotation, error) {
annotations := make(map[reflect.Type]Annotation, 0)
tag := strings.TrimSpace(f.Tag.Get(AnnotationTag))
if "" == tag {
return annotations, nil
}
if !AnnotationRGX.MatchString(tag) {
return nil, fmt.Errorf("Tag of annotation[%s] is not match", tag)
}
rss := AnnotationRGX.FindAllStringSubmatch(tag, -1)
if nil == rss || 0 == len(rss) {
return annotations, nil
}
for _, rs := range rss {
if 3 != len(rs) {
return nil, fmt.Errorf("Tag of annotation[%s] is not valid", rs[0])
}
name := fmt.Sprintf("@%s", strings.TrimSpace(rs[1]))
body := rs[2]
if !AnnotationBodyRGX.MatchString(body) {
return nil, fmt.Errorf("Body[%s] of annotation[%s] is not valid", body, name)
}
body = AnnotationBodyRGX.ReplaceAllStringFunc(body, func(token string) string {
switch len(token) {
case 0, 1, 2:
return "\"\""
default:
return strings.Replace(fmt.Sprintf("\"%s\"", token[1:len(token)-1]), "\\'", "'", -1)
}
})
body = fmt.Sprintf("{%s}", strings.TrimSpace(body))
def, ok := r.definitions[name]
if !ok {
return nil, fmt.Errorf("annotation[%s] is not exist", name)
}
v := reflect.New(def.rt)
i := v.Interface()
err := json.Unmarshal([]byte(body), i)
if nil != err {
return nil, fmt.Errorf("Unmarshal failed %v", err)
}
annotations[def.t] = i
}
return annotations, nil
}
func (r *AnnotationRegistry) getTypeDefinition(t reflect.Type) (*TypeDefinition, error) {
rt, _, _ := our.GetTypeInfo(t)
if reflect.Struct != rt.Kind() {
return nil, fmt.Errorf("type[%s] is not struct", rt.Name())
}
td, ok := r.typeDefinitions[t]
if ok {
return td, nil
}
td = &TypeDefinition{
t: t,
rt: rt,
}
LOOP:
for i := 0; i < rt.NumField(); i++ {
f := rt.Field(i)
if f.Anonymous {
if f.Type == TypeAnnotationType {
if 0 < len(td.typeAnnotation) {
return nil, fmt.Errorf("TypeAnnotation of type[%s] be defined one more time", rt.Name())
}
as, err := r.getAnnotation(&f)
if nil != err {
return nil, err
}
if 0 == len(as) {
continue LOOP
}
td.typeAnnotation = as
}
} else {
if f.Type == MethodAnnotationType {
as, err := r.getAnnotation(&f)
if nil != err {
return nil, err
}
if 0 == len(as) {
continue LOOP
}
if 0 == len(td.methodAnnotation) {
td.methodAnnotation = make(map[string]map[reflect.Type]Annotation, 0)
}
td.methodAnnotation[f.Name] = as
continue LOOP
} else {
as, err := r.getAnnotation(&f)
if nil != err {
return nil, err
}
if 0 == len(as) {
continue LOOP
}
if 0 == len(td.fieldAnnotation) {
td.fieldAnnotation = make(map[string]map[reflect.Type]Annotation, 0)
}
td.fieldAnnotation[f.Name] = as
continue LOOP
}
}
}
r.typeDefinitions[t] = td
return td, nil
}
func GetTypeAnnotation(t reflect.Type, at reflect.Type) (Annotation, error) {
return SystemRegistry.GetTypeAnnotation(t, at)
}
func (r *AnnotationRegistry) GetTypeAnnotation(t reflect.Type, at reflect.Type) (Annotation, error) {
td, err := r.getTypeDefinition(t)
if nil != err {
return nil, err
}
if 0 == len(td.typeAnnotation) {
return nil, fmt.Errorf("TypeAnnotation of type[%s] is not exist", td.rt.Name())
}
a, ok := td.typeAnnotation[at]
if !ok {
return nil, fmt.Errorf("Annotation[%s] of type[%s] is not exist", at.Name(), td.rt.Name())
}
return a, nil
}
func GetTypeAnnotations(t reflect.Type) (map[reflect.Type]Annotation, error) {
return SystemRegistry.GetTypeAnnotations(t)
}
func (r *AnnotationRegistry) GetTypeAnnotations(t reflect.Type) (map[reflect.Type]Annotation, error) {
td, err := r.getTypeDefinition(t)
if nil != err {
return nil, err
}
if 0 == len(td.typeAnnotation) {
return nil, fmt.Errorf("TypeAnnotation of type[%s] is not exist", td.rt.Name())
}
return td.typeAnnotation, nil
}
func GetFieldAnnotation(t reflect.Type, name string, at reflect.Type) (Annotation, error) {
return SystemRegistry.GetFieldAnnotation(t, name, at)
}
func (r *AnnotationRegistry) GetFieldAnnotation(t reflect.Type, name string, at reflect.Type) (Annotation, error) {
td, err := r.getTypeDefinition(t)
if nil != err {
return nil, err
}
if 0 == len(td.fieldAnnotation) {
return nil, fmt.Errorf("FieldAnnotation of type[%s] is not exist", td.rt.Name())
}
as, ok := td.fieldAnnotation[name]
if !ok || 0 == len(as) {
return nil, fmt.Errorf("Field[%s] Annotation of type[%s] is not exist", name, td.rt.Name())
}
a, ok := as[at]
if !ok {
return nil, fmt.Errorf("Annotation[%s] of field[%s] in type[%s] is not exist", at.Name(), name, td.rt.Name())
}
return a, nil
}
func GetFieldAnnotations(t reflect.Type, name string) (map[reflect.Type]Annotation, error) {
return SystemRegistry.GetFieldAnnotations(t, name)
}
func (r *AnnotationRegistry) GetFieldAnnotations(t reflect.Type, name string) (map[reflect.Type]Annotation, error) {
td, err := r.getTypeDefinition(t)
if nil != err {
return nil, err
}
if 0 == len(td.fieldAnnotation) {
return nil, fmt.Errorf("FieldAnnotation of type[%s] is not exist", td.rt.Name())
}
as, ok := td.fieldAnnotation[name]
if !ok || 0 == len(as) {
return nil, fmt.Errorf("Field[%s] Annotation of type[%s] is not exist", name, td.rt.Name())
}
return as, nil
}
func GetAllFieldAnnotations(t reflect.Type) (map[string]map[reflect.Type]Annotation, error) {
return SystemRegistry.GetAllFieldAnnotations(t)
}
func (r *AnnotationRegistry) GetAllFieldAnnotations(t reflect.Type) (map[string]map[reflect.Type]Annotation, error) {
td, err := r.getTypeDefinition(t)
if nil != err {
return nil, err
}
if 0 == len(td.fieldAnnotation) {
return nil, fmt.Errorf("FieldAnnotation of type[%s] is not exist", td.rt.Name())
}
return td.fieldAnnotation, nil
}
func GetMethodAnnotation(t reflect.Type, name string, at reflect.Type) (Annotation, error) {
return SystemRegistry.GetMethodAnnotation(t, name, at)
}
func (r *AnnotationRegistry) GetMethodAnnotation(t reflect.Type, name string, at reflect.Type) (Annotation, error) {
td, err := r.getTypeDefinition(t)
if nil != err {
return nil, err
}
if 0 == len(td.methodAnnotation) {
return nil, fmt.Errorf("MethodAnnotation of type[%s] is not exist", td.rt.Name())
}
as, ok := td.methodAnnotation[name]
if !ok || 0 == len(as) {
return nil, fmt.Errorf("Method[%s] Annotation of type[%s] is not exist", name, td.rt.Name())
}
a, ok := as[at]
if !ok {
return nil, fmt.Errorf("Annotation[%s] of method[%s] in type[%s] is not exist", at.Name(), name, td.rt.Name())
}
return a, nil
}
func GetMethodAnnotations(t reflect.Type, name string) (map[reflect.Type]Annotation, error) {
return SystemRegistry.GetMethodAnnotations(t, name)
}
func (r *AnnotationRegistry) GetMethodAnnotations(t reflect.Type, name string) (map[reflect.Type]Annotation, error) {
td, err := r.getTypeDefinition(t)
if nil != err {
return nil, err
}
if 0 == len(td.methodAnnotation) {
return nil, fmt.Errorf("MethodAnnotation of type[%s] is not exist", td.rt.Name())
}
as, ok := td.methodAnnotation[name]
if !ok || 0 == len(as) {
return nil, fmt.Errorf("Method[%s] Annotation of type[%s] is not exist", name, td.rt.Name())
}
return as, nil
}
func GetAllMethodAnnotations(t reflect.Type) (map[string]map[reflect.Type]Annotation, error) {
return SystemRegistry.GetAllMethodAnnotations(t)
}
func (r *AnnotationRegistry) GetAllMethodAnnotations(t reflect.Type) (map[string]map[reflect.Type]Annotation, error) {
td, err := r.getTypeDefinition(t)
if nil != err {
return nil, err
}
if 0 == len(td.methodAnnotation) {
return nil, fmt.Errorf("MethodAnnotation of type[%s] is not exist", td.rt.Name())
}
return td.methodAnnotation, nil
}