将方法添加到嵌套的导出结构中

I'd like to add a method into the nested exported struct that is used in exported struct.

I have a []*ldap.Entry type returned by the ldap.Search().Entries

ldap.Entry type consists of Attributes []*EntryAttribute. My goal is to add an extra method into the ldap.EntryAttribute, e.g. MarshalJSON

I can add an extra code directly into the ldap package and it will work as I expect. But it is a dirty way:

// EntryAttribute holds a single attribute
type newEntryAttribute struct {
        // Name is the name of the attribute
        Name string
        // Values contain the string values of the attribute
        Values []string
        // ByteValues contain the raw values of the attribute
        ByteValues [][]byte
}

// Print outputs a human-readable description
func (e EntryAttribute) MarshalJSON() ([]byte, error) {
        b := newEntryAttribute(e)
        b.ByteValues = nil
        return json.Marshal(b)
}

How can I do that in a more elegant way?

The closest you can come is to create the method on your own type, which embeds the EntryAttribute type. Something like this:

package mine

import "github.com/go-ldap/ldap""

type EntryAttribute {
    ldap.EntryAttribute
}

func (e EntryAttribute) MarshalJSON() ([]byte, error) {
    // ...
}

But then, you must use your type, not the original type, everywhere in your program.

So far I have found the solution below. It is not elegant, but it doesn't require the package modification.

type myEntry struct {
        *ldap.Entry
        Attributes []*myEntryAttribute
}

type myEntryAttribute struct {
        *ldap.EntryAttribute
}

func (a *myEntryAttribute) MarshalJSON() ([]byte, error) {
        return json.Marshal(struct {
                Name   string
                Values []string 
        }{Name: a.Name, Values: a.Values})
}

func ldapEntry2myEntry(t interface{}) interface{} {
        switch e := t.(type) {
        case []*ldap.Entry:
                var res []interface{}
                for _, v := range e {
                        res = append(res, ldapEntry2myEntry(v))
                }
                return res
        case *ldap.Entry:
                var att []*myEntryAttribute
                for _, a := range e.Attributes {
                        att = append(att, &myEntryAttribute{a})
                }
                return &myEntry{e, att}
        }
        return nil
}

... ... ...

data, err := json.Marshal(ldapEntry2myEntry(sr.Entries))
if err != nil {
        log.Fatal("error")
}
fmt.Printf("%s
", data)

// or only one element

data, err := json.Marshal(ldapEntry2myEntry(sr.Entries[0]))
if err != nil {
        log.Fatal("error")
}
fmt.Printf("%s
", data)