Commit 2f061c0c authored by Kirill Smelkov's avatar Kirill Smelkov

go/zodb: Expose retrieving ZODB class name of a Go object as public API

It is useful in situations where one need to print potentially Broken
objects properly, because %T does not print that detail and using %#v
creates too much noise.
parent cab4dd52
...@@ -206,7 +206,7 @@ func (conn *Connection) get(class string, oid Oid) (IPersistent, error) { ...@@ -206,7 +206,7 @@ func (conn *Connection) get(class string, oid Oid) (IPersistent, error) {
conn.cache.Unlock() conn.cache.Unlock()
if checkClass { if checkClass {
if cls := zclassOf(obj); class != cls { if cls := ClassOf(obj); class != cls {
var err error = &wrongClassError{class, cls} var err error = &wrongClassError{class, cls}
xerr.Contextf(&err, "get %s", Xid{conn.at, oid}) xerr.Contextf(&err, "get %s", Xid{conn.at, oid})
return nil, err return nil, err
......
...@@ -278,15 +278,38 @@ type zclass struct { ...@@ -278,15 +278,38 @@ type zclass struct {
var classTab = make(map[string]*zclass) // {} class -> zclass var classTab = make(map[string]*zclass) // {} class -> zclass
var typeTab = make(map[reflect.Type]*zclass) // {} type -> zclass var typeTab = make(map[reflect.Type]*zclass) // {} type -> zclass
// zclassOf returns ZODB class of a Go object. // ClassOf returns ZODB class of a Go object.
// //
// If ZODB class was not registered for obj's type, "" is returned. // The following is returned:
func zclassOf(obj IPersistent) string { //
zc, ok := typeTab[reflect.TypeOf(obj).Elem()] // - if obj's type was registered (RegisterClass) -- corresponding class.
if !ok { // - for Broken objects -- ZODB.Broken("<broken-class>").
return "" // - else -- ZODB.Go("<fully-qualified-type(obj)>")
func ClassOf(obj IPersistent) string {
zb, broken := obj.(*Broken)
if broken {
return fmt.Sprintf("ZODB.Broken(%q)", zb.class)
}
typ := reflect.TypeOf(obj)
typ = typ.Elem() // *MyPersistent -> MyPersistent
zc, ok := typeTab[typ]
if ok {
return zc.class
}
// the type was not registered to ZODB
fullType := typ.PkgPath()
if typ.PkgPath() != "" {
fullType += "."
}
fullType += typ.Name()
if fullType == "" {
// fallback, since it is possible if the type is anonymous
// XXX not fully qualified
fullType = fmt.Sprintf("*%T", typ)
} }
return zc.class return fmt.Sprintf("ZODB.Go(%q)", fullType)
} }
var rIPersistent = reflect.TypeOf((*IPersistent)(nil)).Elem() // typeof(IPersistent) var rIPersistent = reflect.TypeOf((*IPersistent)(nil)).Elem() // typeof(IPersistent)
......
// Copyright (C) 2018 Nexedi SA and Contributors. // Copyright (C) 2018-2019 Nexedi SA and Contributors.
// Kirill Smelkov <kirr@nexedi.com> // Kirill Smelkov <kirr@nexedi.com>
// //
// This program is free software: you can Use, Study, Modify and Redistribute // This program is free software: you can Use, Study, Modify and Redistribute
// it under the terms of the GNU General Public License version 3, or (at your // it under the terms of the GNU General Public License version 3, or (at your
...@@ -51,6 +51,11 @@ func (o *myObjectState) PySetState(pystate interface{}) error { ...@@ -51,6 +51,11 @@ func (o *myObjectState) PySetState(pystate interface{}) error {
return nil return nil
} }
// Peristent that is not registered to ZODB.
type Unregistered struct {
Persistent
}
func init() { func init() {
t := reflect.TypeOf t := reflect.TypeOf
RegisterClass("t.zodb.MyObject", t(MyObject{}), t(myObjectState{})) RegisterClass("t.zodb.MyObject", t(MyObject{}), t(myObjectState{}))
...@@ -120,7 +125,7 @@ func TestPersistent(t *testing.T) { ...@@ -120,7 +125,7 @@ func TestPersistent(t *testing.T) {
} }
checkObj(obj, nil, 11, InvalidTid, GHOST, 0, nil) checkObj(obj, nil, 11, InvalidTid, GHOST, 0, nil)
assert.Equal(zclassOf(obj), "t.zodb.MyObject") assert.Equal(ClassOf(obj), "t.zodb.MyObject")
// t.zodb.MyOldObject -> *MyObject // t.zodb.MyOldObject -> *MyObject
xobj = newGhost("t.zodb.MyOldObject", 12, nil) xobj = newGhost("t.zodb.MyOldObject", 12, nil)
...@@ -130,7 +135,11 @@ func TestPersistent(t *testing.T) { ...@@ -130,7 +135,11 @@ func TestPersistent(t *testing.T) {
} }
checkObj(obj, nil, 12, InvalidTid, GHOST, 0, nil) checkObj(obj, nil, 12, InvalidTid, GHOST, 0, nil)
assert.Equal(zclassOf(obj), "t.zodb.MyObject") assert.Equal(ClassOf(obj), "t.zodb.MyObject")
// ClassOf(unregistered-obj)
obj2 := &Unregistered{}
assert.Equal(ClassOf(obj2), `ZODB.Go("lab.nexedi.com/kirr/neo/go/zodb.Unregistered")`)
// TODO activate - jar has to load, state changes // TODO activate - jar has to load, state changes
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment