Skip to content

Commit

Permalink
Java: Support use_vendor
Browse files Browse the repository at this point in the history
Adds support for use_vendor with java code, allowing custom qualified names for the vendored items.

Additionally, addresses an issue where vendored files were still generated despite being marked vendor and using the use_vendor option.
  • Loading branch information
brandonbodnar-wk committed Jul 9, 2018
1 parent f198cff commit 9ddef1e
Show file tree
Hide file tree
Showing 27 changed files with 5,488 additions and 18 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -241,14 +241,15 @@ intention to use the vendored code as advertised by the `vendor` annotation.
If no location is specified by the `vendor` annotation, the behavior is defined
by the language generator.

The `vendor` annotation is currently only supported by Go and Dart.
The `vendor` annotation is currently only supported by Go, Dart and Java.

The example below illustrates how this works.

bar.frugal ("providing" IDL):
```thrift
namespace go bar (vendor="github.com/Workiva/my-repo/gen-go/bar")
namespace dart bar (vendor="my-repo/gen-go")
namespace java bar (vendor="com.workiva.bar.custom.pkg")
struct Struct {}
```
Expand Down
7 changes: 6 additions & 1 deletion compiler/compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,12 @@ func generateFrugalRec(f *parser.Frugal, g generator.ProgramGenerator, generate

// Iterate through includes in order to ensure determinism in
// generated code.
for _, inclFrugal := range f.OrderedIncludes() {
for _, include := range f.OrderedIncludes() {
// Skip recursive generation if include is marked vendor and use_vendor option is enabled
if _, vendored := include.Annotations.Vendor(); vendored && g.UseVendor() {
continue
}
inclFrugal := f.ParsedIncludes[include.Name]
if err := generateFrugalRec(inclFrugal, g, globals.Recurse, lang); err != nil {
return err
}
Expand Down
6 changes: 3 additions & 3 deletions compiler/generator/dartlang/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ func (g *Generator) addToPubspec(dir string) error {
name = namespace.Value
}

if g.useVendor() && includesSet[include] {
if g.UseVendor() && includesSet[include] {
vendorPath, _ := namespace.Annotations.Vendor()
deps[toLibraryName(vendorPath)] = dep{
Hosted: hostedDep{Name: toLibraryName(vendorPath), URL: "https://pub.workiva.org"},
Expand Down Expand Up @@ -1867,7 +1867,7 @@ func (g *Generator) generateIncludeImport(include *parser.Include) (string, erro
name := include.Name

_, vendored := include.Annotations.Vendor()
vendored = vendored && g.useVendor()
vendored = vendored && g.UseVendor()
vendorPath := ""

if namespace := g.Frugal.NamespaceForInclude(name, lang); namespace != nil {
Expand Down Expand Up @@ -1911,7 +1911,7 @@ func (g *Generator) useEnums() bool {
return useEnums
}

func (g *Generator) useVendor() bool {
func (g *Generator) UseVendor() bool {
_, ok := g.Options[useVendorOption]
return ok
}
Expand Down
11 changes: 11 additions & 0 deletions compiler/generator/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ var Languages = LanguageOptions{
"suppress: suppress @Generated annotations entirely",
"async": "Generate async client code using futures",
"boxed_primitives": "Generate primitives as the boxed equivalents",
"use_vendor": "Use specified import references for vendored includes and do not generate code for them",
},
"dart": Options{
"library_prefix": "Generate code that can be used within an existing library. " +
Expand Down Expand Up @@ -100,6 +101,9 @@ type ProgramGenerator interface {

// DefaultOutputDir returns the default directory for generated code.
DefaultOutputDir() string

// UseVendor returns whether this generator supports using vendored includes
UseVendor() bool
}

// LanguageGenerator generates source code as implemented for specific
Expand Down Expand Up @@ -136,6 +140,9 @@ type LanguageGenerator interface {
GenerateScopeImports(*os.File, *parser.Scope) error
GeneratePublisher(*os.File, *parser.Scope) error
GenerateSubscriber(*os.File, *parser.Scope) error

// UseVendor returns whether this generator instance supports using vendored includes
UseVendor() bool
}

// GetPackageComponents returns the package string split on dots.
Expand Down Expand Up @@ -337,3 +344,7 @@ func (o *programGenerator) GetOutputDir(dir string, f *parser.Frugal) string {
func (o *programGenerator) DefaultOutputDir() string {
return o.LanguageGenerator.DefaultOutputDir()
}

func (o *programGenerator) UseVendor() bool {
return o.LanguageGenerator.UseVendor()
}
4 changes: 2 additions & 2 deletions compiler/generator/golang/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -1176,7 +1176,7 @@ func (g *Generator) generateIncludeImport(include *parser.Include, pkgPrefix str
namespace := g.Frugal.NamespaceForInclude(includeName, lang)

_, vendored := include.Annotations.Vendor()
vendored = vendored && g.useVendor()
vendored = vendored && g.UseVendor()
vendorPath := ""

if namespace != nil {
Expand Down Expand Up @@ -2258,7 +2258,7 @@ func (g *Generator) generateAsync() bool {
return ok
}

func (g *Generator) useVendor() bool {
func (g *Generator) UseVendor() bool {
_, ok := g.Options[useVendorOption]
return ok
}
Expand Down
4 changes: 4 additions & 0 deletions compiler/generator/html/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ func (g *Generator) DefaultOutputDir() string {
return defaultOutputDir
}

func (g *Generator) UseVendor() bool {
return false
}

func (g *Generator) generateStylesheet(file *os.File) error {
_, err := file.WriteString(css)
return err
Expand Down
21 changes: 21 additions & 0 deletions compiler/generator/java/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const (
defaultOutputDir = "gen-java"
tab = "\t"
generatedAnnotations = "generated_annotations"
useVendorOption = "use_vendor"
tabtab = tab + tab
tabtabtab = tab + tab + tab
tabtabtabtab = tab + tab + tab + tab
Expand Down Expand Up @@ -3272,11 +3273,26 @@ func containerType(typeName string) string {
}
}

func (g *Generator) isVendoredInclude(includeName string) bool {
include := g.Frugal.Include(includeName)
if include == nil {
return false
}
_, vendored := include.Annotations.Vendor()
return vendored
}

func (g *Generator) qualifiedTypeName(t *parser.Type) string {
param := t.ParamName()
include := t.IncludeName()
if include != "" {
if namespace := g.Frugal.NamespaceForInclude(include, lang); namespace != nil {
if g.UseVendor() && g.isVendoredInclude(include) {
if vendorPath, _ := namespace.Annotations.Vendor(); vendorPath != "" {
return fmt.Sprintf("%s.%s", vendorPath, param)
}
}

return fmt.Sprintf("%s.%s", namespace.Value, param)
}
}
Expand Down Expand Up @@ -3328,3 +3344,8 @@ func (g *Generator) generateAsync() bool {
_, ok := g.Options["async"]
return ok
}

func (g *Generator) UseVendor() bool {
_, ok := g.Options[useVendorOption]
return ok
}
4 changes: 4 additions & 0 deletions compiler/generator/python/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -1564,3 +1564,7 @@ func getAsyncOpt(options map[string]string) concurrencyModel {
}
return synchronous
}

func (g *Generator) UseVendor() bool {
return false
}
31 changes: 20 additions & 11 deletions compiler/parser/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,20 @@ type Include struct {
Annotations Annotations
}

type byIncludeName []Include

func (s byIncludeName) Len() int {
return len(s)
}

func (s byIncludeName) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}

func (s byIncludeName) Less(i, j int) bool {
return s[i].Name < s[j].Name
}

// Namespace represents an IDL namespace.
type Namespace struct {
Scope string
Expand Down Expand Up @@ -689,19 +703,14 @@ func (f *Frugal) ContainsFrugalDefinitions() bool {
return len(f.Scopes)+len(f.Services) > 0
}

// OrderedIncludes returns the ParsedIncludes in order, sorted by the include
// OrderedIncludes returns the Includes in order, sorted by the include
// name.
func (f *Frugal) OrderedIncludes() []*Frugal {
keys := make([]string, 0, len(f.ParsedIncludes))
for key := range f.ParsedIncludes {
keys = append(keys, key)
}
sort.Strings(keys)

includes := make([]*Frugal, 0, len(f.ParsedIncludes))
for _, key := range keys {
includes = append(includes, f.ParsedIncludes[key])
func (f *Frugal) OrderedIncludes() []Include {
includes := make([]Include, 0, len(f.Includes))
for _, include := range f.Includes {
includes = append(includes, *include)
}
sort.Sort(byIncludeName(includes))
return includes
}

Expand Down
Loading

0 comments on commit 9ddef1e

Please sign in to comment.