code: def _generate_union_class_custom_annotations(self, ns, data_type):
          
          self.emit('def _process_custom_annotations(self, annotation_type, field_path, processor):')
          with self.indent(), emit_pass_if_nothing_emitted(self):
              self.emit(
                  (
                      'super({}, self)._process_custom_annotations(annotation_type, field_path, '
                      'processor)'
                  ).format(class_name_for_data_type(data_type))
              )
              self.emit()
  
              for field in data_type.fields:
                  recursive_processors = list(self._generate_custom_annotation_processors(
                      ns, field.data_type, field.custom_annotations))
  
                  # check if we have any annotations that apply to this field at all
                  if len(recursive_processors) == 0:
                      continue
  
                  field_name = fmt_func(field.name)
                  self.emit('if self.is_{}():'.format(field_name))
  
                  with self.indent():
                      for annotation_type, processor in recursive_processors:
                          annotation_class = class_name_for_annotation_type(annotation_type, ns)
                          self.emit('if annotation_type is {}:'.format(annotation_class))
                          with self.indent():
                              self.emit('self._value = {}'.format(
                                  generate_func_call(
                                      processor,
                                      args=[
                                          "'{{}}.{}'.format(field_path)".format(field_name),
                                          'self._value',
                                      ])
                              ))
                          self.emit()
docs: The _process_custom_annotations function allows client code to access
          custom annotations defined in the spec.