blob: d7af99ebfd673583c3a2f608f01d65c9829b7047 [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package java implements Java code generation from compiled VDL packages.
package java
import (
"path"
"v.io/v23/vdl"
"v.io/x/ref/lib/vdl/compile"
)
// pkgPathXlator is the function used to translate a VDL package path
// into a Java package path. If nil, no translation takes place.
var pkgPathXlator func(path string) string
// SetPkgPathXlator sets the function used to translate a VDL package
// path into a Java package path.
func SetPkgPathXlator(xlator func(path string) string) {
pkgPathXlator = xlator
}
// javaGenPkgPath returns the Java package path given the VDL package path.
func javaGenPkgPath(vdlPkgPath string) string {
if pkgPathXlator == nil {
return vdlPkgPath
}
return pkgPathXlator(vdlPkgPath)
}
// JavaFileInfo stores the name and contents of the generated Java file.
type JavaFileInfo struct {
Dir string
Name string
Data []byte
}
// Generate generates Java files for all VDL files in the provided package,
// returning the list of generated Java files as a slice. Since Java requires
// that each public class/interface gets defined in a separate file, this method
// will return one generated file per struct. (Interfaces actually generate
// two files because we create separate interfaces for clients and servers.)
// In addition, since Java doesn't support global variables (i.e., variables
// defined outside of a class), all constants are moved into a special "Consts"
// class and stored in a separate file. All client bindings are stored in a
// separate Client.java file. Finally, package documentation (if any) is stored
// in a "package-info.java" file.
//
// TODO(spetrovic): Run Java formatters on the generated files.
func Generate(pkg *compile.Package, env *compile.Env) (ret []JavaFileInfo) {
validateJavaConfig(pkg, env)
// One file for package documentation (if any).
if g := genJavaPackageFile(pkg, env); g != nil {
ret = append(ret, *g)
}
// Single file for all constants' definitions.
if g := genJavaConstFile(pkg, env); g != nil {
ret = append(ret, *g)
}
for _, file := range pkg.Files {
// Separate file for all typedefs.
for _, tdef := range file.TypeDefs {
switch tdef.Type.Kind() {
case vdl.Array:
ret = append(ret, genJavaArrayFile(tdef, env))
case vdl.Enum:
ret = append(ret, genJavaEnumFile(tdef, env))
case vdl.List:
ret = append(ret, genJavaListFile(tdef, env))
case vdl.Map:
ret = append(ret, genJavaMapFile(tdef, env))
case vdl.Union:
ret = append(ret, genJavaUnionFile(tdef, env))
case vdl.Set:
ret = append(ret, genJavaSetFile(tdef, env))
case vdl.Struct:
ret = append(ret, genJavaStructFile(tdef, env))
default:
ret = append(ret, genJavaPrimitiveFile(tdef, env))
}
}
// Separate file for all interface definitions.
for _, iface := range file.Interfaces {
ret = append(ret, genJavaClientFactoryFile(iface, env))
ret = append(ret, genJavaClientInterfaceFile(iface, env)) // client interface
ret = append(ret, genJavaClientImplFile(iface, env))
ret = append(ret, genJavaServerInterfaceFile(iface, env)) // server interface
ret = append(ret, genJavaServerWrapperFile(iface, env))
}
for _, err := range file.ErrorDefs {
// Separate file for all error defs.
ret = append(ret, genJavaErrorFile(file, err, env))
}
}
return
}
// The native types feature is hard to use correctly. E.g. the wire type
// must be statically registered in Java vdl package in order for the
// wire<->native conversion to work, which is hard to ensure.
//
// Restrict the feature to these whitelisted VDL packages for now.
var nativeTypePackageWhitelist = map[string]bool{
"time": true,
"v.io/v23/security": true,
"v.io/v23/security/access": true,
"v.io/x/ref/lib/vdl/testdata/nativetest": true,
}
func validateJavaConfig(pkg *compile.Package, env *compile.Env) {
vdlconfig := path.Join(pkg.GenPath, "vdl.config")
// Validate native type configuration. Since native types are hard to use, we
// restrict them to a built-in whitelist of packages for now.
if len(pkg.Config.Java.WireToNativeTypes) > 0 && !nativeTypePackageWhitelist[pkg.Path] {
env.Errors.Errorf("%s: Java.WireToNativeTypes is restricted to whitelisted VDL packages", vdlconfig)
}
}