k8s.io/kube-openapi@v0.0.0-20240228011516-70dd3763d340/pkg/validation/strfmt/bson/objectid.go (about) 1 // Copyright (C) MongoDB, Inc. 2017-present. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); you may 4 // not use this file except in compliance with the License. You may obtain 5 // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 // 7 // Based on gopkg.in/mgo.v2/bson by Gustavo Niemeyer 8 // See THIRD-PARTY-NOTICES for original license terms. 9 10 package bson 11 12 import ( 13 "bytes" 14 "encoding/hex" 15 "encoding/json" 16 "errors" 17 "fmt" 18 ) 19 20 // ErrInvalidHex indicates that a hex string cannot be converted to an ObjectID. 21 var ErrInvalidHex = errors.New("the provided hex string is not a valid ObjectID") 22 23 // ObjectID is the BSON ObjectID type. 24 type ObjectID [12]byte 25 26 // NilObjectID is the zero value for ObjectID. 27 var NilObjectID ObjectID 28 29 // Hex returns the hex encoding of the ObjectID as a string. 30 func (id ObjectID) Hex() string { 31 return hex.EncodeToString(id[:]) 32 } 33 34 func (id ObjectID) String() string { 35 return fmt.Sprintf("ObjectID(%q)", id.Hex()) 36 } 37 38 // IsZero returns true if id is the empty ObjectID. 39 func (id ObjectID) IsZero() bool { 40 return bytes.Equal(id[:], NilObjectID[:]) 41 } 42 43 // ObjectIDFromHex creates a new ObjectID from a hex string. It returns an error if the hex string is not a 44 // valid ObjectID. 45 func ObjectIDFromHex(s string) (ObjectID, error) { 46 b, err := hex.DecodeString(s) 47 if err != nil { 48 return NilObjectID, err 49 } 50 51 if len(b) != 12 { 52 return NilObjectID, ErrInvalidHex 53 } 54 55 var oid [12]byte 56 copy(oid[:], b[:]) 57 58 return oid, nil 59 } 60 61 // MarshalJSON returns the ObjectID as a string 62 func (id ObjectID) MarshalJSON() ([]byte, error) { 63 return json.Marshal(id.Hex()) 64 } 65 66 // UnmarshalJSON populates the byte slice with the ObjectID. If the byte slice is 24 bytes long, it 67 // will be populated with the hex representation of the ObjectID. If the byte slice is twelve bytes 68 // long, it will be populated with the BSON representation of the ObjectID. This method also accepts empty strings and 69 // decodes them as NilObjectID. For any other inputs, an error will be returned. 70 func (id *ObjectID) UnmarshalJSON(b []byte) error { 71 // Ignore "null" to keep parity with the standard library. Decoding a JSON null into a non-pointer ObjectID field 72 // will leave the field unchanged. For pointer values, encoding/json will set the pointer to nil and will not 73 // enter the UnmarshalJSON hook. 74 if string(b) == "null" { 75 return nil 76 } 77 78 var err error 79 switch len(b) { 80 case 12: 81 copy(id[:], b) 82 default: 83 // Extended JSON 84 var res interface{} 85 err := json.Unmarshal(b, &res) 86 if err != nil { 87 return err 88 } 89 str, ok := res.(string) 90 if !ok { 91 m, ok := res.(map[string]interface{}) 92 if !ok { 93 return errors.New("not an extended JSON ObjectID") 94 } 95 oid, ok := m["$oid"] 96 if !ok { 97 return errors.New("not an extended JSON ObjectID") 98 } 99 str, ok = oid.(string) 100 if !ok { 101 return errors.New("not an extended JSON ObjectID") 102 } 103 } 104 105 // An empty string is not a valid ObjectID, but we treat it as a special value that decodes as NilObjectID. 106 if len(str) == 0 { 107 copy(id[:], NilObjectID[:]) 108 return nil 109 } 110 111 if len(str) != 24 { 112 return fmt.Errorf("cannot unmarshal into an ObjectID, the length must be 24 but it is %d", len(str)) 113 } 114 115 _, err = hex.Decode(id[:], []byte(str)) 116 if err != nil { 117 return err 118 } 119 } 120 121 return err 122 }