diff --git a/jsonLoader.go b/jsonLoader.go index 0b40574..085efe7 100644 --- a/jsonLoader.go +++ b/jsonLoader.go @@ -46,11 +46,38 @@ var osFS = osFileSystem(os.Open) // JSON loader interface type JSONLoader interface { - jsonSource() interface{} - loadJSON() (interface{}, error) - loadSchema() (*Schema, error) + JsonSource() interface{} + LoadJSON() (interface{}, error) + JsonReference() (gojsonreference.JsonReference, error) + LoaderFactory() JSONLoaderFactory } +type JSONLoaderFactory interface { + New(source string) JSONLoader +} + +type DefaultJSONLoaderFactory struct { +} + +type FileSystemJSONLoaderFactory struct { + fs http.FileSystem +} + +func (d DefaultJSONLoaderFactory) New(source string) JSONLoader { + return &jsonReferenceLoader{ + fs: osFS, + source: source, + } +} + +func (f FileSystemJSONLoaderFactory) New(source string) JSONLoader { + return &jsonReferenceLoader{ + fs: f.fs, + source: source, + } +} + + // osFileSystem is a functional wrapper for os.Open that implements http.FileSystem. type osFileSystem func(string) (*os.File, error) @@ -66,10 +93,18 @@ type jsonReferenceLoader struct { source string } -func (l *jsonReferenceLoader) jsonSource() interface{} { +func (l *jsonReferenceLoader) JsonSource() interface{} { return l.source } +func (l *jsonReferenceLoader) JsonReference() (gojsonreference.JsonReference, error) { + return gojsonreference.NewJsonReference(l.JsonSource().(string)) +} + +func (l *jsonReferenceLoader) LoaderFactory() JSONLoaderFactory { + return &DefaultJSONLoaderFactory{} +} + // NewReferenceLoader returns a JSON reference loader using the given source and the local OS file system. func NewReferenceLoader(source string) *jsonReferenceLoader { return &jsonReferenceLoader{ @@ -86,11 +121,11 @@ func NewReferenceLoaderFileSystem(source string, fs http.FileSystem) *jsonRefere } } -func (l *jsonReferenceLoader) loadJSON() (interface{}, error) { +func (l *jsonReferenceLoader) LoadJSON() (interface{}, error) { var err error - reference, err := gojsonreference.NewJsonReference(l.jsonSource().(string)) + reference, err := gojsonreference.NewJsonReference(l.JsonSource().(string)) if err != nil { return nil, err } @@ -131,32 +166,6 @@ func (l *jsonReferenceLoader) loadJSON() (interface{}, error) { } -func (l *jsonReferenceLoader) loadSchema() (*Schema, error) { - - var err error - - d := Schema{} - d.pool = newSchemaPool(l.fs) - d.referencePool = newSchemaReferencePool() - - d.documentReference, err = gojsonreference.NewJsonReference(l.jsonSource().(string)) - if err != nil { - return nil, err - } - - spd, err := d.pool.GetDocument(d.documentReference) - if err != nil { - return nil, err - } - - err = d.parse(spd.Document) - if err != nil { - return nil, err - } - - return &d, nil - -} func (l *jsonReferenceLoader) loadFromHTTP(address string) (interface{}, error) { @@ -201,44 +210,25 @@ type jsonStringLoader struct { source string } -func (l *jsonStringLoader) jsonSource() interface{} { +func (l *jsonStringLoader) JsonSource() interface{} { return l.source } -func NewStringLoader(source string) *jsonStringLoader { - return &jsonStringLoader{source: source} +func (l *jsonStringLoader) JsonReference() (gojsonreference.JsonReference, error) { + return gojsonreference.NewJsonReference("#") } -func (l *jsonStringLoader) loadJSON() (interface{}, error) { - - return decodeJsonUsingNumber(strings.NewReader(l.jsonSource().(string))) - +func (l *jsonStringLoader) LoaderFactory() JSONLoaderFactory { + return &DefaultJSONLoaderFactory{} } -func (l *jsonStringLoader) loadSchema() (*Schema, error) { - - var err error - - document, err := l.loadJSON() - if err != nil { - return nil, err - } - - d := Schema{} - d.pool = newSchemaPool(osFS) - d.referencePool = newSchemaReferencePool() - d.documentReference, err = gojsonreference.NewJsonReference("#") - d.pool.SetStandaloneDocument(document) - if err != nil { - return nil, err - } +func NewStringLoader(source string) *jsonStringLoader { + return &jsonStringLoader{source: source} +} - err = d.parse(document) - if err != nil { - return nil, err - } +func (l *jsonStringLoader) LoadJSON() (interface{}, error) { - return &d, nil + return decodeJsonUsingNumber(strings.NewReader(l.JsonSource().(string))) } @@ -249,19 +239,27 @@ type jsonGoLoader struct { source interface{} } -func (l *jsonGoLoader) jsonSource() interface{} { +func (l *jsonGoLoader) JsonSource() interface{} { return l.source } +func (l *jsonGoLoader) JsonReference() (gojsonreference.JsonReference, error) { + return gojsonreference.NewJsonReference("#") +} + +func (l *jsonGoLoader) LoaderFactory() JSONLoaderFactory { + return &DefaultJSONLoaderFactory{} +} + func NewGoLoader(source interface{}) *jsonGoLoader { return &jsonGoLoader{source: source} } -func (l *jsonGoLoader) loadJSON() (interface{}, error) { +func (l *jsonGoLoader) LoadJSON() (interface{}, error) { // convert it to a compliant JSON first to avoid types "mismatches" - jsonBytes, err := json.Marshal(l.jsonSource()) + jsonBytes, err := json.Marshal(l.JsonSource()) if err != nil { return nil, err } @@ -270,33 +268,6 @@ func (l *jsonGoLoader) loadJSON() (interface{}, error) { } -func (l *jsonGoLoader) loadSchema() (*Schema, error) { - - var err error - - document, err := l.loadJSON() - if err != nil { - return nil, err - } - - d := Schema{} - d.pool = newSchemaPool(osFS) - d.referencePool = newSchemaReferencePool() - d.documentReference, err = gojsonreference.NewJsonReference("#") - d.pool.SetStandaloneDocument(document) - if err != nil { - return nil, err - } - - err = d.parse(document) - if err != nil { - return nil, err - } - - return &d, nil - -} - func decodeJsonUsingNumber(r io.Reader) (interface{}, error) { var document interface{} diff --git a/schema.go b/schema.go index 577c786..6f60147 100644 --- a/schema.go +++ b/schema.go @@ -42,7 +42,39 @@ var ( ) func NewSchema(l JSONLoader) (*Schema, error) { - return l.loadSchema() + ref, err := l.JsonReference() + if err != nil { + return nil, err + } + + d := Schema{} + d.pool = newSchemaPool(l.LoaderFactory()) + d.documentReference = ref + d.referencePool=newSchemaReferencePool() + + var doc interface{} + if ref.String() != "#" { + // Get document from schema pool + spd, err := d.pool.GetDocument(d.documentReference) + if err != nil { + return nil, err + } + doc = spd.Document + } else { + // Load JSON directly + doc, err = l.LoadJSON() + if err != nil { + return nil, err + } + d.pool.SetStandaloneDocument(doc) + } + + err = d.parse(doc) + if err != nil { + return nil, err + } + + return &d, nil } type Schema struct { diff --git a/schemaPool.go b/schemaPool.go index 70ae731..f2ad641 100644 --- a/schemaPool.go +++ b/schemaPool.go @@ -28,7 +28,6 @@ package gojsonschema import ( "errors" - "net/http" "github.com/xeipuuv/gojsonreference" ) @@ -40,15 +39,15 @@ type schemaPoolDocument struct { type schemaPool struct { schemaPoolDocuments map[string]*schemaPoolDocument standaloneDocument interface{} - fs http.FileSystem + jsonLoaderFactory JSONLoaderFactory } -func newSchemaPool(fs http.FileSystem) *schemaPool { +func newSchemaPool(f JSONLoaderFactory) *schemaPool { p := &schemaPool{} p.schemaPoolDocuments = make(map[string]*schemaPoolDocument) p.standaloneDocument = nil - p.fs = fs + p.jsonLoaderFactory = f return p } @@ -96,8 +95,8 @@ func (p *schemaPool) GetDocument(reference gojsonreference.JsonReference) (*sche return spd, nil } - jsonReferenceLoader := NewReferenceLoaderFileSystem(reference.String(), p.fs) - document, err := jsonReferenceLoader.loadJSON() + jsonReferenceLoader := p.jsonLoaderFactory.New(reference.String()) + document, err := jsonReferenceLoader.LoadJSON() if err != nil { return nil, err } diff --git a/validation.go b/validation.go index 2dc0df2..60d637e 100644 --- a/validation.go +++ b/validation.go @@ -55,7 +55,7 @@ func (v *Schema) Validate(l JSONLoader) (*Result, error) { // load document - root, err := l.loadJSON() + root, err := l.LoadJSON() if err != nil { return nil, err }