return 'jobject'
+def JavaDataTypeToCForCalledByNativeParam(java_type):
+ """Returns a C datatype to be when calling from native."""
+ if java_type == 'int':
+ return 'JniIntWrapper'
+ else:
+ return JavaDataTypeToC(java_type)
+
+
def JavaReturnValueToC(java_type):
"""Returns a valid C return value for the given java type."""
java_pod_type_map = {
_package = ''
_inner_classes = []
_remappings = []
+ _implicit_imports = []
@staticmethod
def SetFullyQualifiedClass(fully_qualified_class):
'Ljava/lang/String',
'Ljava/lang/Class',
]
+
prefix = ''
# Array?
while param[-2:] == '[]':
(param, JniParams._package.replace('/', '.'),
outer.replace('/', '.')))
+ JniParams._CheckImplicitImports(param)
+
# Type not found, falling back to same package as this class.
return (prefix + 'L' +
JniParams.RemapClassName(JniParams._package + '/' + param) + ';')
@staticmethod
+ def _CheckImplicitImports(param):
+ # Ensure implicit imports, such as java.lang.*, are not being treated
+ # as being in the same package.
+ if not JniParams._implicit_imports:
+ # This file was generated from android.jar and lists
+ # all classes that are implicitly imported.
+ with file(os.path.join(os.path.dirname(sys.argv[0]),
+ 'android_jar.classes'), 'r') as f:
+ JniParams._implicit_imports = f.readlines()
+ for implicit_import in JniParams._implicit_imports:
+ implicit_import = implicit_import.strip().replace('.class', '')
+ implicit_import = implicit_import.replace('/', '.')
+ if implicit_import.endswith('.' + param):
+ raise SyntaxError('Ambiguous class (%s) can not be used directly '
+ 'by JNI.\nPlease import it, probably:\n\n'
+ 'import %s;' %
+ (param, implicit_import))
+
+
+ @staticmethod
def Signature(params, returns, wrap):
"""Returns the JNI signature for the given datatypes."""
items = ['(']
class JNIFromJavaSource(object):
"""Uses the given java source file to generate the JNI header file."""
+ # Match single line comments, multiline comments, character literals, and
+ # double-quoted strings.
+ _comment_remover_regex = re.compile(
+ r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"',
+ re.DOTALL | re.MULTILINE)
+
def __init__(self, contents, fully_qualified_class, options):
- contents = self._RemoveComments(contents, options)
+ contents = self._RemoveComments(contents)
JniParams.SetFullyQualifiedClass(fully_qualified_class)
JniParams.ExtractImportsAndInnerClasses(contents)
jni_namespace = ExtractJNINamespace(contents) or options.namespace
[], options)
self.content = inl_header_file_generator.GetContent()
- def _RemoveComments(self, contents, options):
+ @classmethod
+ def _RemoveComments(cls, contents):
# We need to support both inline and block comments, and we need to handle
- # strings that contain '//' or '/*'. Rather than trying to do all that with
- # regexps, we just pipe the contents through the C preprocessor. We tell cpp
- # the file has already been preprocessed, so it just removes comments and
- # doesn't try to parse #include, #pragma etc.
- #
- # TODO(husky): This is a bit hacky. It would be cleaner to use a real Java
+ # strings that contain '//' or '/*'.
+ # TODO(bulach): This is a bit hacky. It would be cleaner to use a real Java
# parser. Maybe we could ditch JNIFromJavaSource and just always use
# JNIFromJavaP; or maybe we could rewrite this script in Java and use APT.
# http://code.google.com/p/chromium/issues/detail?id=138941
- p = subprocess.Popen(args=[options.cpp, '-fpreprocessed'],
- stdin=subprocess.PIPE,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- stdout, _ = p.communicate(contents)
- return stdout
+ def replacer(match):
+ # Replace matches that are comments with nothing; return literals/strings
+ # unchanged.
+ s = match.group(0)
+ if s.startswith('/'):
+ return ''
+ else:
+ return s
+ return cls._comment_remover_regex.sub(replacer, contents)
def GetContent(self):
return self.content
${INCLUDES}
+#include "base/android/jni_int_wrapper.h"
+
// Step 1: forward declarations.
namespace {
$CLASS_PATH_DEFINITIONS
for param in native.params])
def GetCalledByNativeParamsInDeclaration(self, called_by_native):
- return ',\n '.join([JavaDataTypeToC(param.datatype) + ' ' +
- param.name
- for param in called_by_native.params])
+ return ',\n '.join([
+ JavaDataTypeToCForCalledByNativeParam(param.datatype) + ' ' +
+ param.name
+ for param in called_by_native.params])
def GetForwardDeclaration(self, native):
template = Template("""
}
return template.substitute(values)
+ def GetArgument(self, param):
+ return ('as_jint(' + param.name + ')'
+ if param.datatype == 'int' else param.name)
+
+ def GetArgumentsInCall(self, params):
+ """Return a string of arguments to call from native into Java"""
+ return [self.GetArgument(p) for p in params]
+
def GetCalledByNativeValues(self, called_by_native):
"""Fills in necessary values for the CalledByNative methods."""
if called_by_native.static or called_by_native.is_constructor:
called_by_native)
if params_in_declaration:
params_in_declaration = ', ' + params_in_declaration
- params_in_call = ', '.join(param.name for param in called_by_native.params)
+ params_in_call = ', '.join(self.GetArgumentsInCall(called_by_native.params))
if params_in_call:
params_in_call = ', ' + params_in_call
pre_call = ''