diff options
author | qsr@chromium.org <qsr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-06-03 08:43:37 +0000 |
---|---|---|
committer | qsr@chromium.org <qsr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-06-03 08:43:37 +0000 |
commit | 21075b5dc4f91266175d92b46c004c24bf69f73e (patch) | |
tree | 6dc8c72ca5c5648fed0e76d74c2e77776b4969c5 | |
parent | c4c9c8cf4af14e6944375330bd12712ce4eb5479 (diff) | |
download | chromium_src-21075b5dc4f91266175d92b46c004c24bf69f73e.zip chromium_src-21075b5dc4f91266175d92b46c004c24bf69f73e.tar.gz chromium_src-21075b5dc4f91266175d92b46c004c24bf69f73e.tar.bz2 |
Generate java bindings for constants.
This CL is the first CL introducing java bindings. It only generates constants.
This is a reland of https://codereview.chromium.org/291903003 with a custom
DEPS file to fix bot issue.
TBR=viettrungluu@chromium.org,rmcilroy@chromium.org
Review URL: https://codereview.chromium.org/312643003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@274431 0039d316-1c4b-4281-b951-d872f2087c98
9 files changed, 267 insertions, 2 deletions
diff --git a/mojo/android/javatests/DEPS b/mojo/android/javatests/DEPS new file mode 100644 index 0000000..78cf465 --- /dev/null +++ b/mojo/android/javatests/DEPS @@ -0,0 +1,4 @@ +include_rules = [ + # out should be allowed by default, but bots are failing on this. + "+out", +] diff --git a/mojo/android/javatests/src/org/chromium/mojo/bindings/BindingsTest.java b/mojo/android/javatests/src/org/chromium/mojo/bindings/BindingsTest.java new file mode 100644 index 0000000..1c4807b --- /dev/null +++ b/mojo/android/javatests/src/org/chromium/mojo/bindings/BindingsTest.java @@ -0,0 +1,33 @@ +// Copyright 2014 The Chromium 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 org.chromium.mojo.bindings; + +import android.test.suitebuilder.annotation.SmallTest; + +import junit.framework.TestCase; + +import org.chromium.mojo.bindings.test.sample.SampleServiceConstants; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; + +/** + * Testing generated classes and associated features. + */ +public class BindingsTest extends TestCase { + + /** + * Testing constants are correctly generated. + */ + @SmallTest + public void testConstants() throws NoSuchFieldException, SecurityException { + assertEquals(3, SampleServiceConstants.THREE); + Field threeField = SampleServiceConstants.class.getField("THREE"); + assertEquals(byte.class, threeField.getType()); + assertEquals(Modifier.FINAL, threeField.getModifiers() & Modifier.FINAL); + assertEquals(Modifier.STATIC, threeField.getModifiers() & Modifier.STATIC); + } + +} diff --git a/mojo/public/tools/bindings/generators/java_templates/constant_definition.tmpl b/mojo/public/tools/bindings/generators/java_templates/constant_definition.tmpl new file mode 100644 index 0000000..f69f657 --- /dev/null +++ b/mojo/public/tools/bindings/generators/java_templates/constant_definition.tmpl @@ -0,0 +1,5 @@ +{% from "java_macros.tmpl" import build_default %} + +{% macro constant_def(constant) %} +public static final {{constant.kind|java_type}} {{constant|name}} = {{build_default(module, constant.kind, constant.value)|indent(4)}}; +{% endmacro %} diff --git a/mojo/public/tools/bindings/generators/java_templates/constants.java.tmpl b/mojo/public/tools/bindings/generators/java_templates/constants.java.tmpl new file mode 100644 index 0000000..0a4e299 --- /dev/null +++ b/mojo/public/tools/bindings/generators/java_templates/constants.java.tmpl @@ -0,0 +1,12 @@ +{% from "constant_definition.tmpl" import constant_def %} +{% include "header.java.tmpl" %} + +public final class {{main_entity}} { +{% for constant in constants %} + + {{constant_def(constant)|indent(4)}} +{% endfor %} + + private {{main_entity}}() {} + +} diff --git a/mojo/public/tools/bindings/generators/java_templates/header.java.tmpl b/mojo/public/tools/bindings/generators/java_templates/header.java.tmpl new file mode 100644 index 0000000..ec6a88b --- /dev/null +++ b/mojo/public/tools/bindings/generators/java_templates/header.java.tmpl @@ -0,0 +1,11 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file is autogenerated by: +// mojo/public/tools/bindings/mojom_bindings_generator.py +// For: +// {{module.path}} +// + +package {{package}}; diff --git a/mojo/public/tools/bindings/generators/java_templates/java_macros.tmpl b/mojo/public/tools/bindings/generators/java_templates/java_macros.tmpl new file mode 100644 index 0000000..a8745d2 --- /dev/null +++ b/mojo/public/tools/bindings/generators/java_templates/java_macros.tmpl @@ -0,0 +1,3 @@ +{% macro build_default(module, kind, value) %} +({{kind|java_type}}) {{value|expression_to_text(module)}} +{% endmacro %} diff --git a/mojo/public/tools/bindings/generators/mojom_java_generator.py b/mojo/public/tools/bindings/generators/mojom_java_generator.py new file mode 100644 index 0000000..0b38127 --- /dev/null +++ b/mojo/public/tools/bindings/generators/mojom_java_generator.py @@ -0,0 +1,182 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Generates java source files from a mojom.Module.""" + +import argparse +import os +import re + +import mojom.generate.generator as generator +import mojom.generate.module as mojom +from mojom.generate.template_expander import UseJinja + + +GENERATOR_PREFIX = 'java' + +_spec_to_java_type = { + 'b': 'boolean', + 'd': 'double', + 'f': 'float', + 'h:d:c': 'org.chromium.mojo.system.DataPipe.ConsumerHandle', + 'h:d:p': 'org.chromium.mojo.system.DataPipe.ProducerHandle', + 'h:m': 'org.chromium.mojo.system.MessagePipeHandle', + 'h': 'org.chromium.mojo.system.UntypedHandle', + 'h:s': 'org.chromium.mojo.system.SharedBufferHandle', + 'i16': 'short', + 'i32': 'int', + 'i64': 'long', + 'i8': 'byte', + 's': 'String', + 'u16': 'short', + 'u32': 'int', + 'u64': 'long', + 'u8': 'byte', +} + + +def NameToComponent(name): + # insert '_' between anything and a Title name (e.g, HTTPEntry2FooBar -> + # HTTP_Entry2_FooBar) + name = re.sub('([^_])([A-Z][^A-Z_]+)', r'\1_\2', name) + # insert '_' between non upper and start of upper blocks (e.g., + # HTTP_Entry2_FooBar -> HTTP_Entry2_Foo_Bar) + name = re.sub('([^A-Z_])([A-Z])', r'\1_\2', name) + return [x.lower() for x in name.split('_')] + +def CapitalizeFirst(string): + return string[0].upper() + string[1:] + +def UpperCamelCase(name): + return ''.join([CapitalizeFirst(x) for x in NameToComponent(name)]) + +def CamelCase(name): + uccc = UpperCamelCase(name) + return uccc[0].lower() + uccc[1:] + +def ConstantStyle(name): + components = NameToComponent(name) + if components[0] == 'k': + components = components[1:] + return '_'.join([x.upper() for x in components]) + +def GetNameForElement(element): + if (isinstance(element, mojom.Enum) or + isinstance(element, mojom.Interface) or + isinstance(element, mojom.Struct)): + return UpperCamelCase(element.name) + if (isinstance(element, mojom.Method) or + isinstance(element, mojom.Parameter) or + isinstance(element, mojom.Field)): + return CamelCase(element.name) + if isinstance(element, mojom.EnumValue): + return (UpperCamelCase(element.enum_name) + '.' + + ConstantStyle(element.name)) + if (isinstance(element, mojom.NamedValue) or + isinstance(element, mojom.Constant)): + return ConstantStyle(element.name) + raise Exception("Unexpected element: " % element) + +def GetPackage(module): + if 'JavaPackage' in module.attributes: + package = module.attributes['JavaPackage'] + if isinstance(package, basestring): + return package + assert package[0] == 'EXPRESSION' + assert len(package[1]) == 1 + return package[1][0][1:-1].encode('string_escape') + # Default package. + return "org.chromium.mojom." + module.namespace + +def GetNameForKind(kind): + def _GetNameHierachy(kind): + hierachy = [] + if kind.parent_kind: + hierachy = _GetNameHierachy(kind.parent_kind) + hierachy.append(kind.name) + return hierachy + + elements = [GetPackage(kind.module)] + elements += _GetNameHierachy(kind) + return '.'.join(elements) + +def GetJavaType(kind): + if isinstance(kind, (mojom.Struct, mojom.Interface)): + return GetNameForKind(kind) + if isinstance(kind, mojom.Array): + return "%s[]" % GetJavaType(kind.kind) + if isinstance(kind, mojom.Enum): + return "int" + return _spec_to_java_type[kind.spec] + +def TranslateConstants(token, module): + def _TranslateNamedValue(named_value): + entity_name = GetNameForElement(named_value) + if named_value.parent_kind: + return GetJavaType(named_value.parent_kind) + '.' + entity_name + # Handle the case where named_value is a module level constant: + if not isinstance(named_value, mojom.EnumValue): + entity_name = (GetConstantsMainEntityName(named_value.module) + '.' + + entity_name) + return GetPackage(named_value.module) + '.' + entity_name + + if isinstance(token, mojom.NamedValue): + return _TranslateNamedValue(token) + # Add Long suffix to all number literals. + if re.match('^[0-9]+$', token): + return token + 'L' + return token + +def ExpressionToText(value, module): + if value[0] != "EXPRESSION": + raise Exception("Expected EXPRESSION, got" + value) + return "".join(generator.ExpressionMapper(value, + lambda token: TranslateConstants(token, module))) + +def GetConstantsMainEntityName(module): + # This constructs the name of the embedding classes for module level constants + # by extracting the mojom's filename and prepending it to Constants. + return (UpperCamelCase(module.path.split('/')[-1].rsplit('.', 1)[0]) + + 'Constants') + +class Generator(generator.Generator): + + java_filters = { + "expression_to_text": ExpressionToText, + "java_type": GetJavaType, + "name": GetNameForElement, + "verify_token_type": generator.VerifyTokenType, + } + + def GetJinjaExports(self): + return { + "module": self.module, + "package": GetPackage(self.module), + } + + @UseJinja("java_templates/constants.java.tmpl", filters=java_filters, + lstrip_blocks=True, trim_blocks=True) + def GenerateConstantsSource(self, module): + exports = self.GetJinjaExports() + exports.update({"main_entity": GetConstantsMainEntityName(module), + "constants": module.constants}) + return exports + + def GenerateFiles(self, unparsed_args): + parser = argparse.ArgumentParser() + parser.add_argument("--java_output_directory", dest="java_output_directory") + args = parser.parse_args(unparsed_args) + if self.output_dir and args.java_output_directory: + self.output_dir = os.path.join(args.java_output_directory, + GetPackage(self.module).replace('.', '/')) + if not os.path.exists(self.output_dir): + try: + os.makedirs(self.output_dir) + except: + # Ignore errors on directory creation. + pass + + if self.module.constants: + self.Write(self.GenerateConstantsSource(self.module), + "%s.java" % GetConstantsMainEntityName(self.module)) diff --git a/mojo/public/tools/bindings/mojom_bindings_generator.gypi b/mojo/public/tools/bindings/mojom_bindings_generator.gypi index 3fe0c63..dcb273dd 100644 --- a/mojo/public/tools/bindings/mojom_bindings_generator.gypi +++ b/mojo/public/tools/bindings/mojom_bindings_generator.gypi @@ -5,13 +5,14 @@ { 'rules': [ { - 'rule_name': 'Generate C++ source files from mojom files', + 'rule_name': 'Generate C++, JS and Java source files from mojom files', 'extension': 'mojom', 'variables': { 'mojom_base_output_dir': '<!(python <(DEPTH)/build/inverse_depth.py <(DEPTH))', 'mojom_bindings_generator': '<(DEPTH)/mojo/public/tools/bindings/mojom_bindings_generator.py', + 'java_out_dir': '<(PRODUCT_DIR)/java_mojo/<(_target_name)/src', }, 'inputs': [ '<(mojom_bindings_generator)', @@ -34,11 +35,16 @@ '<(DEPTH)/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_definition.tmpl', '<(DEPTH)/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_declaration.tmpl', '<(DEPTH)/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_definition.tmpl', + '<(DEPTH)/mojo/public/tools/bindings/generators/java_templates/constant_definition.tmpl', + '<(DEPTH)/mojo/public/tools/bindings/generators/java_templates/constants.java.tmpl', + '<(DEPTH)/mojo/public/tools/bindings/generators/java_templates/header.java.tmpl', + '<(DEPTH)/mojo/public/tools/bindings/generators/java_templates/java_macros.tmpl', '<(DEPTH)/mojo/public/tools/bindings/generators/js_templates/enum_definition.tmpl', '<(DEPTH)/mojo/public/tools/bindings/generators/js_templates/interface_definition.tmpl', '<(DEPTH)/mojo/public/tools/bindings/generators/js_templates/module.js.tmpl', '<(DEPTH)/mojo/public/tools/bindings/generators/js_templates/struct_definition.tmpl', '<(DEPTH)/mojo/public/tools/bindings/generators/mojom_cpp_generator.py', + '<(DEPTH)/mojo/public/tools/bindings/generators/mojom_java_generator.py', '<(DEPTH)/mojo/public/tools/bindings/generators/mojom_js_generator.py', '<(DEPTH)/mojo/public/tools/bindings/pylib/mojom/__init__.py', '<(DEPTH)/mojo/public/tools/bindings/pylib/mojom/error.py', @@ -66,6 +72,7 @@ '--use_chromium_bundled_pylibs', '-d', '<(DEPTH)', '-o', '<(SHARED_INTERMEDIATE_DIR)/<(mojom_base_output_dir)/<(RULE_INPUT_DIRNAME)', + '--java_output_directory=<(java_out_dir)', ], 'message': 'Generating Mojo bindings from <(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT).mojom', 'process_outputs_as_sources': 1, @@ -80,6 +87,11 @@ '<(DEPTH)', '<(SHARED_INTERMEDIATE_DIR)', ], + 'variables': { + 'generated_src_dirs': [ + '<(PRODUCT_DIR)/java_mojo/<(_target_name)/src', + ], + }, }, 'hard_dependency': 1, } diff --git a/mojo/public/tools/bindings/mojom_bindings_generator.py b/mojo/public/tools/bindings/mojom_bindings_generator.py index aee3b8c..9332576 100755 --- a/mojo/public/tools/bindings/mojom_bindings_generator.py +++ b/mojo/public/tools/bindings/mojom_bindings_generator.py @@ -53,6 +53,9 @@ def LoadGenerators(generators_string): elif generator_name.lower() == "javascript": generator_name = os.path.join(script_dir, "generators", "mojom_js_generator.py") + elif generator_name.lower() == "java": + generator_name = os.path.join(script_dir, "generators", + "mojom_java_generator.py") # Specified generator python module: elif generator_name.endswith(".py"): pass @@ -153,7 +156,7 @@ def main(): parser.add_argument("-o", "--output_dir", dest="output_dir", default=".", help="output directory for generated files") parser.add_argument("-g", "--generators", dest="generators_string", - metavar="GENERATORS", default="c++,javascript", + metavar="GENERATORS", default="c++,javascript,java", help="comma-separated list of generators") parser.add_argument("--debug_print_intermediate", action="store_true", help="print the intermediate representation") |