3 # Copyright (c) 2014 Intel Corporation. All rights reserved.
4 # Use of this source code is governed by a BSD-style license that can be
5 # found in the LICENSE file.
9 from collections import OrderedDict
10 from string import Template
12 def ConvertClassExpressionToClassType(class_name):
13 """ Turn "final HashMap<String>" to HashMap.class. """
14 return '%s.class' % class_name.split()[-1].split('<')[0]
17 def ConvertPrimitiveTypeToObject(class_name):
28 return primitive_map.get(class_name, class_name)
31 class ParamStringType(object):
34 BRIDGE_DECLARE_FOR_WRAPPER = 3
35 BRIDGE_PASS_TO_SUPER = 4
36 BRIDGE_PASS_TO_WRAPPER = 5
37 INTERNAL_PASS_TO_BRIDGE = 6
38 BRIDGE_OVERRIDE_CONDITION = 7
40 WRAPPER_DECLARE_FOR_BRIDGE = 9
41 WRAPPER_PASS_TO_BRIDGE = 10
44 class MethodStringType(object):
45 BRIDGE_CONSTRUCTOR = 1
50 WRAPPER_CONSTRUCTOR = 6
57 """Internal representaion of a method."""
58 ANNOTATION_PRE_WRAPLINE = 'preWrapperLines'
59 ANNOTATION_POST_WRAPLINE = 'postWrapLines'
61 def __init__(self, class_name, class_loader,
62 is_constructor, is_static, is_abstract,
63 method_name, method_return, params, annotation, doc=''):
64 self._class_name = class_name
65 self._class_loader = class_loader
66 self._is_constructor = is_constructor
67 self._is_static = is_static
68 self._is_abstract = is_abstract
69 self._method_name = method_name
70 self._method_return = method_return
71 self._params = OrderedDict() # Use OrderedDict to avoid parameter misorder.
72 self._method_annotations = {}
73 self._method_doc = doc
74 self._class_java_data = ''
75 self._method_declare_name = ''
76 self._internal_params_declare = ''
77 self._bridge_params_declare = ''
78 self._bridge_params_declare_for_wrapper = ''
79 self._bridge_params_pass_to_super = ''
80 self._bridge_params_pass_to_wrapper = ''
81 self._internal_params_pass_to_bridge = ''
82 self._bridge_override_condition = ''
83 self._wrapper_params_declare = ''
84 self._wrapper_params_declare_for_bridge = ''
85 self._wrapper_params_pass_to_bridge = ''
86 self._strings_prepared = False
87 self.ParseMethodParams(params)
88 self.ParseMethodAnnotation(annotation)
90 def IsInternalClass(self, clazz):
91 return self._class_loader.IsInternalClass(clazz)
93 def LoadJavaClass(self, clazz):
94 return self._class_loader.LoadJavaClass(clazz)
96 def GenerateDoc(self, doc):
97 return self._class_loader.GenerateDoc(doc)
100 def is_constructor(self):
101 return self._is_constructor
105 return self._is_static
108 def is_abstract(self):
109 return self._is_abstract
112 def method_name(self):
113 return self._method_name
116 def method_return(self):
117 return self._method_return
124 def method_annotations(self):
125 return self._method_annotations
128 def method_doc(self):
129 return self._method_doc
131 def ParseMethodParams(self, params):
132 # TODO(shouqun): Currently, generic parameters are not supported.
133 # The support of generic types should be added if such cases happen.
134 if not params or params == '':
136 for param in params.split(','):
137 param = param.strip()
138 param_list = param.split()
139 param_type = ' '.join(param_list[:-1]) # To handle modifiers
140 param_name = param_list[-1]
141 self._params[param_name] = param_type
143 def ParseMethodAnnotation(self, annotation):
144 pre_wrapline_re = re.compile('preWrapperLines\s*=\s*\{\s*('
145 '?P<pre_wrapline>(".*")(,\s*".*")*)\s*\}')
146 for match in re.finditer(pre_wrapline_re, annotation):
147 pre_wrapline = self.FormatWrapperLine(match.group('pre_wrapline'))
148 self._method_annotations[self.ANNOTATION_PRE_WRAPLINE] = pre_wrapline
150 post_wrapline_re = re.compile('postWrapperLines\s*=\s*\{\s*('
151 '?P<post_wrapline>(".*")(,\s*".*")*)\s*\}')
152 for match in re.finditer(post_wrapline_re, annotation):
153 post_wrapline = self.FormatWrapperLine(match.group('post_wrapline'))
154 self._method_annotations[self.ANNOTATION_POST_WRAPLINE] = post_wrapline
156 def FormatWrapperLine(self, annotation_value):
157 """ annotaion_value is a java string array which each element is an
158 individual line. Probably like: ' "line1",\n "line2"'
159 This method is turnning it to ' line1\n line2'
162 exec('lines = [%s]' % annotation_value.replace('\n', ''))
163 template = Template('\n'.join(lines))
165 for arg in range(1, len(self.params.keys())+1):
166 values['param%d' % arg] = self.params.keys()[arg-1]
167 return template.substitute(values)
169 def GetBridgeParamsStringDeclareForWrapper(self):
170 self.PrepareStrings()
171 return self._bridge_params_declare_for_wrapper
173 def GetWrapperParamsStringDeclareForBridge(self):
174 self.PrepareStrings()
175 return self._wrapper_params_declare_for_bridge
177 def GetMethodDeclareName(self):
178 self.PrepareStrings()
179 return self._method_declare_name
181 def PrepareStrings(self):
182 if self._strings_prepared:
184 self._class_java_data = self.LoadJavaClass(self._class_name)
185 self._method_declare_name = self.GenerateMethodDeclareName()
187 self._internal_params_declare = ', '.join(
188 self.GetFormattedParamArray(ParamStringType.INTERNAL_DECLARE))
189 self._bridge_params_declare = ', '.join(
190 self.GetFormattedParamArray(ParamStringType.BRIDGE_DECLARE))
191 self._bridge_params_declare_for_wrapper = ', '.join(
192 self.GetFormattedParamArray(
193 ParamStringType.BRIDGE_DECLARE_FOR_WRAPPER, insert_empty=True))
194 self._bridge_params_pass_to_super = ', '.join(
195 self.GetFormattedParamArray(ParamStringType.BRIDGE_PASS_TO_SUPER))
196 self._bridge_params_pass_to_wrapper = ', '.join(
197 self.GetFormattedParamArray(
198 ParamStringType.BRIDGE_PASS_TO_WRAPPER, insert_empty=True))
199 self._internal_params_pass_to_bridge = ', '.join(
200 self.GetFormattedParamArray(ParamStringType.INTERNAL_PASS_TO_BRIDGE))
201 self._bridge_override_condition = ' && '.join(
202 self.GetFormattedParamArray(ParamStringType.BRIDGE_OVERRIDE_CONDITION))
203 self._wrapper_params_declare = ', '.join(
204 self.GetFormattedParamArray(ParamStringType.WRAPPER_DECLARE))
205 self._wrapper_params_declare_for_bridge = ', '.join(
206 self.GetFormattedParamArray(ParamStringType.WRAPPER_DECLARE_FOR_BRIDGE,
208 self._wrapper_params_pass_to_bridge = ', '.join(
209 self.GetFormattedParamArray(
210 ParamStringType.WRAPPER_PASS_TO_BRIDGE, insert_empty=True))
212 self._strings_prepared = True
214 def GetFormattedParamArray(self, param_string_type,
215 append_empty=False, insert_empty=False):
216 """ Return the array of params with specified format.
217 append or insert an empty string on demand for cases
218 that need extra splitter when using the array.
220 formatted_params = []
221 for param_name in self._params:
222 param_type = self._params[param_name]
223 formatted_param = self.FormatSingleParam(
224 param_type, param_name, param_string_type)
226 formatted_params.append(formatted_param)
228 formatted_params.append('')
230 formatted_params.insert(0, '')
231 return formatted_params
233 def FormatSingleParam(self, param_type, param_name, param_string_type):
234 is_internal_class = self.IsInternalClass(param_type)
235 if is_internal_class:
236 java_data = self.LoadJavaClass(param_type)
237 if param_string_type == ParamStringType.INTERNAL_DECLARE:
238 # the way internal declares its params, will be used in bridge's override
240 # XWalkViewInternal view => XWalkViewInternal view
241 return '%s %s' % (param_type, param_name)
242 elif param_string_type == ParamStringType.BRIDGE_DECLARE:
243 # the way bridge declares its params, will be used in bridge's wrapper
244 # call and super call.
245 # XWalkViewInternal view => XWalkViewBridge view
246 if is_internal_class:
247 return '%s %s' % (java_data.UseAsTypeInBridgeAndBridgeSuperCall(),
250 return '%s %s' % (param_type, param_name)
251 elif param_string_type == ParamStringType.BRIDGE_DECLARE_FOR_WRAPPER:
252 # the way bridge declares its params for wrapper, will turn the param
253 # type to class<?> value for reflection to use.
254 # XWalkViewInternal view => "org.xwalk.core.XWalkView"
255 # DirectionInternal direnction => enumDirectionClass
256 # String name => String.class
257 if is_internal_class:
258 return '"%s"' % java_data.GetFullWrapperName()
260 # TODO(wang16): Here only detects enum declared in the same class as
261 # the method itself. Using enum across class is not supported.
262 enums = self._class_java_data.enums
263 if param_type in enums:
264 return enums[param_type].EnumClassName()
266 return ConvertClassExpressionToClassType(param_type)
267 elif param_string_type == ParamStringType.BRIDGE_PASS_TO_SUPER:
268 # the way bridge passes the param to super
269 # XWalkViewInternal view => view
270 if is_internal_class:
271 return java_data.UseAsInstanceInBridgeSuperCall(param_name)
274 elif param_string_type == ParamStringType.BRIDGE_PASS_TO_WRAPPER:
275 # the way bridge passes the param to wrapper
276 # XWalkViewInternal view => view.getWrapper()
277 # DirectionInternal direction => ConvertDirectionInternal(direction)
278 if is_internal_class:
279 return java_data.UseAsInstanceInBridgeCall(param_name)
281 # TODO(wang16): Here only detects enum declared in the same class as
282 # the method itself. Using enum across class is not supported.
283 enums = self._class_java_data.enums
284 if param_type in enums:
285 return 'Convert%s(%s)' % (param_type, param_name)
288 elif param_string_type == ParamStringType.INTERNAL_PASS_TO_BRIDGE:
289 # the way bridge accepts param from internal
290 # XWalkViewInternal view => (XWalkViewBridge) view
291 if is_internal_class:
292 return java_data.UseAsInstanceInBridgeOverrideCall(param_name)
295 elif param_string_type == ParamStringType.BRIDGE_OVERRIDE_CONDITION:
296 # the way bridge uses as the condition for whether call super or
297 # call wrapper in override call
298 # XWalkViewInternal view => (view instanceof XWalkViewBridge)
299 if is_internal_class:
300 return'(%s instanceof %s)' % (
302 java_data.UseAsTypeInBridgeAndBridgeSuperCall())
305 elif param_string_type == ParamStringType.WRAPPER_DECLARE:
306 # the way wrapper declare the param
307 # XWalkViewInternal view => XWalkView view
308 # DirectionInternal direction => Direction direction
309 if is_internal_class:
310 return '%s %s' % (java_data.UseAsTypeInWrapperCall(), param_name)
311 elif param_type in self._class_java_data.enums:
312 # TODO(wang16): Here only detects enum declared in the same class as
313 # the method itself. Using enum across class is not supported.
314 return '%s %s' % (param_type.replace('Internal', ''), param_name)
316 return '%s %s' % (param_type, param_name)
317 elif param_string_type == ParamStringType.WRAPPER_DECLARE_FOR_BRIDGE:
318 # the way wrapper declares its params for bridge, will turn the param
319 # type to class<?> value for reflection to use.
320 # XWalkViewInternal view => "org.xwalk.core.internal.XWalkViewBridge"
321 # DirectionInternal direction => enumDirectionClass
322 # String name => String.class
324 # TODO(wang16): Currently there is no internal classes for static method.
325 # Need to support it in future.
326 if is_internal_class:
327 return '"%s"' % java_data.GetFullBridgeName()
329 # TODO(wang16): Here only detects enum declared in the same class as
330 # the method itself. Using enum across class is not supported.
331 enums = self._class_java_data.enums
332 if param_type in enums:
333 return enums[param_type].EnumClassName()
335 return ConvertClassExpressionToClassType(param_type)
336 elif param_string_type == ParamStringType.WRAPPER_PASS_TO_BRIDGE:
337 # the way wrapper passes param to bridge
338 # XWalkViewInternal view => view.getBridge()
339 # DirectionInternal direction => ConvertDirection(direction)
340 if is_internal_class:
341 return java_data.UseAsInstanceInWrapperCall(param_name)
342 elif param_type in self._class_java_data.enums:
343 # TODO(wang16): Here only detects enum declared in the same class as
344 # the method itself. Using enum across class is not supported.
345 return 'Convert%s(%s)' % (param_type.replace('Internal', ''),
352 def GenerateMethodDeclareName(self):
353 name = self.method_name
354 for param_name in self.params:
355 # Remove modifier and generic type.
356 name += ConvertClassExpressionToClassType(
357 self.params[param_name]).replace('.class', '')
358 if self._is_constructor:
359 return '%sConstructor' % name
361 return '%sMethod' % name
363 def GenerateBridgeConstructor(self):
365 ' public ${NAME}(${PARAMS}, Object wrapper) {\n' +
366 ' super(${PARAMS_PASSING});\n' +
367 ' this.wrapper = wrapper;\n' +
369 ' reflectionInit();\n' +
370 ' } catch (Exception e) {\n' +
371 ' ReflectionHelper.handleException(e);\n'+
374 value = {'NAME': self._class_java_data.bridge_name,
375 'PARAMS': self._bridge_params_declare,
376 'PARAMS_PASSING': self._bridge_params_pass_to_super}
377 return template.substitute(value)
379 def GenerateBridgeStaticMethod(self):
380 no_return_value = self._method_return == 'void'
382 ' public static ${RETURN_TYPE} ${NAME}($PARAMS) {\n' +
383 ' ${RETURN}${CLASS_NAME}.${NAME}(${PARAMS_PASSING});\n' +
385 value = {'RETURN_TYPE': self.method_return,
386 'NAME': self.method_name,
387 'PARAMS': self._bridge_params_declare,
388 'RETURN': '' if no_return_value else 'return ',
389 'CLASS_NAME': self._class_name,
390 'PARAMS_PASSING': self._bridge_params_pass_to_super}
391 return template.substitute(value)
393 def GenerateBridgeOverrideMethod(self):
394 no_return_value = self._method_return == 'void'
395 if not self._bridge_override_condition:
396 return ' @Override\n'
399 ' public ${RETURN_TYPE} ${NAME}(${PARAMS}) {\n' +
400 ' if (${IF_CONDITION}) {\n' +
401 ' ${RETURN}${NAME}(${BRIDGE_PARAMS_PASSING});\n' +
403 ' ${RETURN}super.${NAME}(${PARAMS_PASSING});\n' +
406 value = {'NAME': self.method_name,
407 'RETURN_TYPE': self.method_return,
408 'PARAMS': self._internal_params_declare,
409 'RETURN': '' if no_return_value else 'return ',
410 'IF_CONDITION': self._bridge_override_condition,
411 'PARAMS_PASSING': self._bridge_params_pass_to_super,
412 'BRIDGE_PARAMS_PASSING': self._internal_params_pass_to_bridge}
413 return template.substitute(value)
415 def GenerateBridgeWrapperMethod(self):
416 no_return_value = self._method_return == 'void'
417 return_is_internal = self.IsInternalClass(self._method_return)
418 if return_is_internal:
419 return_type_java_data = self.LoadJavaClass(self._method_return)
422 ' public ${RETURN_TYPE} ${NAME}(${PARAMS}) {\n' +
423 ' ${RETURN}ReflectionHelper.invokeMethod(\n' +
424 ' ${METHOD_DECLARE_NAME}, wrapper${PARAMS_PASSING});\n' +
427 return_statement = ''
428 elif return_is_internal:
429 return_statement = 'return (%s)' % return_type_java_data.bridge_name
431 return_statement = 'return (%s)' % (
432 ConvertPrimitiveTypeToObject(self.method_return))
433 value = {'RETURN_TYPE': self.method_return,
434 'NAME': self.method_name,
435 'METHOD_DECLARE_NAME': self._method_declare_name,
436 'PARAMS': self._bridge_params_declare,
437 'RETURN': return_statement,
438 'PARAMS_PASSING': self._bridge_params_pass_to_wrapper}
439 return template.substitute(value)
441 def GenerateBridgeSuperMethod(self):
442 no_return_value = self._method_return == 'void'
443 return_is_internal = self.IsInternalClass(self._method_return)
444 if return_is_internal:
445 return_type_java_data = self.LoadJavaClass(self._method_return)
447 if self._is_abstract:
450 if self._class_java_data.HasCreateInternallyAnnotation():
453 ' public void ${NAME}Super(${PARAMS}) {\n' +
454 ' if (internal == null) {\n' +
455 ' super.${NAME}(${PARAM_PASSING});\n' +
457 ' internal.${NAME}(${PARAM_PASSING});\n' +
462 ' public ${RETURN_TYPE} ${NAME}Super(${PARAMS}) {\n' +
463 ' ${INTERNAL_RETURN_TYPE} ret;\n' +
464 ' if (internal == null) {\n' +
465 ' ret = super.${NAME}(${PARAM_PASSING});\n' +
467 ' ret = internal.${NAME}(${PARAM_PASSING});\n' +
469 ' ${IF_NULL_RETURN_NULL}\n' +
470 ' return ${RETURN_VALUE};\n' +
475 ' public void ${NAME}Super(${PARAMS}) {\n' +
476 ' super.${NAME}(${PARAM_PASSING});\n' +
480 ' public ${RETURN_TYPE} ${NAME}Super(${PARAMS}) {\n' +
481 ' ${INTERNAL_RETURN_TYPE} ret;\n' +
482 ' ret = super.${NAME}(${PARAM_PASSING});\n' +
483 ' ${IF_NULL_RETURN_NULL}\n' +
484 ' return ${RETURN_VALUE};\n' +
487 if return_is_internal:
488 return_value = return_type_java_data.UseAsReturnInBridgeSuperCall('ret')
489 method_return = return_type_java_data.bridge_name
492 method_return = self._method_return
494 if ConvertPrimitiveTypeToObject(method_return) != method_return:
495 # it's returning prmitive type, so it can't be null.
496 if_null_return_null = ''
498 if_null_return_null = 'if (ret == null) return null;'
500 'RETURN_TYPE': method_return,
501 'INTERNAL_RETURN_TYPE': self.method_return,
502 'NAME': self.method_name,
503 'PARAM_PASSING': self._bridge_params_pass_to_super,
504 'PARAMS': self._bridge_params_declare,
505 'IF_NULL_RETURN_NULL': if_null_return_null,
506 'RETURN_VALUE': return_value
509 return template.substitute(value)
511 def GenerateWrapperConstructor(self):
512 # TODO(wang16): Currently, only support pre/post wrapper lines for
516 ' public ${CLASS_NAME}(${PARAMS}) {\n' +
517 '${PRE_WRAP_LINES}\n' +
518 ' bridge = ReflectionHelper.createInstance(' +
519 '\"${CONSTRUCTOR_DECLARE_NAME}\"${PARAMS_PASSING}, this);\n' +
521 ' reflectionInit();\n' +
522 ' } catch(Exception e) {\n' +
523 ' ReflectionHelper.handleException(e);\n' +
525 '${POST_WRAP_LINES}\n' +
527 value = {'CLASS_NAME': self._class_java_data.wrapper_name,
528 'DOC': self.GenerateDoc(self.method_doc),
529 'PARAMS': self._wrapper_params_declare,
530 'PARAMS_PASSING': self._wrapper_params_pass_to_bridge,
531 'CONSTRUCTOR_DECLARE_NAME': self._method_declare_name,
532 'PRE_WRAP_LINES': self._method_annotations.get(
533 self.ANNOTATION_PRE_WRAPLINE, ''),
534 'POST_WRAP_LINES': self._method_annotations.get(
535 self.ANNOTATION_POST_WRAPLINE, '')}
536 return template.substitute(value)
538 def GenerateWrapperStaticMethod(self):
539 no_return_value = self._method_return == 'void'
541 ' public static ${RETURN_TYPE} ${NAME}(${PARAMS}) {\n' +
542 ' Class<?> clazz = ReflectionHelper.loadClass(' +
543 '\"${FULL_BRIDGE_NAME}\");\n' +
544 ' Method method = ReflectionHelper.loadMethod(clazz, ' +
545 '\"${NAME}\"${PARAMS_DECLARE_FOR_BRIDGE});\n' +
546 ' ${RETURN}ReflectionHelper.invokeMethod(method, null' +
547 '${PARAMS_PASSING});\n' +
552 return_state = 'return (%s)' % ConvertPrimitiveTypeToObject(
554 value = {'RETURN_TYPE': self.method_return,
555 'NAME': self.method_name,
556 'FULL_BRIDGE_NAME': self._class_java_data.GetFullBridgeName(),
557 'PARAMS_DECLARE_FOR_BRIDGE':
558 self._wrapper_params_declare_for_bridge,
559 'PARAMS_PASSING': self._wrapper_params_pass_to_bridge,
560 'PARAMS': self._wrapper_params_declare,
561 'RETURN': return_state}
562 return template.substitute(value)
564 def GenerateWrapperBridgeMethod(self):
565 no_return_value = self._method_return == 'void'
566 return_is_internal = self.IsInternalClass(self._method_return)
567 if return_is_internal:
568 return_type_java_data = self.LoadJavaClass(self._method_return)
573 ' public abstract ${RETURN_TYPE} ${NAME}(${PARAMS});\n\n')
574 elif return_is_internal:
577 ' public ${RETURN_TYPE} ${NAME}(${PARAMS}) {\n' +
578 ' return (${RETURN_TYPE})ReflectionHelper.' +
579 'getBridgeOrWrapper(\n' +
580 ' ReflectionHelper.invokeMethod(' +
581 '${METHOD_DECLARE_NAME}, bridge${PARAMS_PASSING}));\n' +
586 ' public ${RETURN_TYPE} ${NAME}(${PARAMS}) {\n' +
587 ' ${RETURN}ReflectionHelper.invokeMethod(' +
588 '${METHOD_DECLARE_NAME}, bridge${PARAMS_PASSING});\n' +
590 if return_is_internal:
591 return_type = return_type_java_data.wrapper_name
593 return_type = self.method_return
597 return_state = 'return (%s)' % ConvertPrimitiveTypeToObject(return_type)
598 value = {'RETURN_TYPE': return_type,
599 'RETURN': return_state,
600 'DOC': self.GenerateDoc(self.method_doc),
601 'NAME': self.method_name,
602 'PARAMS': self._wrapper_params_declare,
603 'METHOD_DECLARE_NAME': self._method_declare_name,
604 'PARAMS_PASSING': self._wrapper_params_pass_to_bridge}
605 return template.substitute(value)
607 def GenerateWrapperInterface(self):
608 return_is_internal = self.IsInternalClass(self._method_return)
609 if return_is_internal:
610 return_type_java_data = self.LoadJavaClass(self._method_return)
614 ' public ${RETURN_TYPE} ${NAME}(${PARAMS});\n\n')
615 if return_is_internal:
616 return_type = return_type_java_data.wrapper_name
618 return_type = self.method_return
619 value = {'RETURN_TYPE': return_type,
620 'DOC': self.GenerateDoc(self.method_doc),
621 'NAME': self.method_name,
622 'PARAMS': self._wrapper_params_declare}
623 return template.substitute(value)
625 def GenerateMethodsStringForBridge(self):
626 self.PrepareStrings()
627 if self._is_constructor:
628 return self.GenerateBridgeConstructor()
629 elif self._is_static:
630 return self.GenerateBridgeStaticMethod()
632 return '%s%s%s%s' % (
633 ' private Method %s;\n' % self._method_declare_name,
634 self.GenerateBridgeOverrideMethod(),
635 self.GenerateBridgeWrapperMethod(),
636 self.GenerateBridgeSuperMethod())
638 def GenerateMethodsStringForWrapper(self):
639 self.PrepareStrings()
640 if self._is_constructor:
641 return self.GenerateWrapperConstructor()
642 elif self._is_static:
643 return self.GenerateWrapperStaticMethod()
644 elif self._is_abstract:
645 return self.GenerateWrapperBridgeMethod()
648 ' private Method %s;\n' % self._method_declare_name,
649 self.GenerateWrapperBridgeMethod())
651 def GenerateMethodsStringForInterface(self):
652 self.PrepareStrings()
653 return self.GenerateWrapperInterface()