def getAnnotations(metadata, decoded, prefix=''):
    """
    Function to gather @ additional props in a payload
    """
    allowed_annotations = ['odata', 'Redfish', 'Privileges', 'Message']
    if metadata is not None:
        schemaObj = metadata.schema_obj
    else:
        traverseLogger.warn("Cannot work on annotations without a service or metadata")
        return False, []
    additionalProps = list()
    # For every ...@ in decoded, check for its presence in refs
    #   get the schema file for it
    #   concat type info together
    annotationsFound = 0
    for key in [k for k in decoded if prefix + '@' in k and '@odata' not in k]:
        annotationsFound += 1
        splitKey = key.split('@', 1)
        fullItem = splitKey[1]
        if getNamespace(fullItem) not in allowed_annotations:
            traverseLogger.error("getAnnotations: {} is not an allowed annotation namespace, please check spelling/capitalization.".format(fullItem))
            continue
        elif metadata is not None:
            # add the namespace to the set of namespaces referenced by this service
            metadata.add_service_namespace(getNamespace(fullItem))
        annotationSchemaObj = schemaObj.getSchemaFromReference(getNamespace(fullItem))
        traverseLogger.debug('{}, {}, {}'.format(key, splitKey, decoded[key]))
        if annotationSchemaObj is not None:
            realType = annotationSchemaObj.name
            realItem = realType + '.' + fullItem.split('.', 1)[1]
            additionalProps.append(
                rfSchema.PropItem(annotationSchemaObj, realItem, key, decoded[key]))
    traverseLogger.debug("Annotations generated: {} out of {}".format(len(additionalProps), annotationsFound))
    return True, additionalProps
    def __init__(self,
                 name: str,
                 uri: str,
                 jsondata: dict,
                 typename: str,
                 context: str,
                 parent=None,
                 isComplex=False,
                 forceType=False):
        self.initiated = False
        self.parent = parent
        self.uri, self.name = uri, name
        self.rtime = 0
        self.status = -1
        self.isRegistry = False
        self.errorIndex = {}

        oem = config.get('oemcheck', True)

        # Check if this is a Registry resource
        parent_type = parent.typename if parent is not None and parent is not None else None
        if parent_type is not None and getType(
                parent_type) == 'MessageRegistryFile':
            traverseLogger.debug('{} is a Registry resource'.format(self.uri))
            self.isRegistry = True
            self.context = None
            context = None

        # Check if we provide a valid json
        self.jsondata = jsondata

        traverseLogger.debug("payload: {}".format(
            json.dumps(self.jsondata, indent=4, sort_keys=True)))

        if not isinstance(self.jsondata, dict):
            traverseLogger.error("Resource no longer a dictionary...")
            raise ValueError('This Resource is no longer a Dictionary')

        # Check for @odata.id (todo: regex)
        odata_id = self.jsondata.get('@odata.id')
        if odata_id is None and not isComplex:
            if self.isRegistry:
                traverseLogger.debug(
                    '{}: @odata.id missing, but not required for Registry resource'
                    .format(self.uri))
            else:
                traverseLogger.log(
                    'SERVICE',
                    '{}: Json does not contain @odata.id'.format(self.uri))

        # Get our real type (check for version)
        acquiredtype = typename if forceType else jsondata.get(
            '@odata.type', typename)
        if acquiredtype is None:
            traverseLogger.error(
                '{}:  Json does not contain @odata.type or NavType'.format(
                    uri))
            raise ValueError
        if acquiredtype is not typename and isComplex:
            context = None

        if typename is not None:
            if not oem and 'OemObject' in typename:
                acquiredtype = typename

        if currentService:
            if not oem and 'OemObject' in acquiredtype:
                pass
            else:
                if jsondata.get('@odata.type') is not None:
                    currentService.metadata.add_service_namespace(
                        getNamespace(jsondata.get('@odata.type')))
                if jsondata.get('@odata.context') is not None:
                    # add the namespace to the set of namespaces referenced by this service
                    ns = getNamespace(
                        jsondata.get('@odata.context').split('#')[-1])
                    if '/' not in ns and not ns.endswith('$entity'):
                        currentService.metadata.add_service_namespace(ns)

        # Provide a context for this (todo: regex)
        if context is None:
            context = self.jsondata.get('@odata.context')
            if context is None:
                context = createContext(acquiredtype)
                if self.isRegistry:
                    # If this is a Registry resource, @odata.context is not required; do our best to construct one
                    traverseLogger.debug(
                        '{}: @odata.context missing from Registry resource; constructed context {}'
                        .format(acquiredtype, context))
                elif isComplex:
                    pass
                else:
                    traverseLogger.debug(
                        '{}:  Json does not contain @odata.context'.format(
                            uri))

        self.context = context

        # Get Schema object
        self.schemaObj = rfSchema.getSchemaObject(acquiredtype, self.context)

        if self.schemaObj is None:
            traverseLogger.error(
                "ResourceObject creation: No schema XML for {} {} {}".format(
                    typename, acquiredtype, self.context))
            raise ValueError

        # Use string comprehension to get highest type
        if acquiredtype is typename and not forceType:
            acquiredtype = self.schemaObj.getHighestType(typename, parent_type)
            if not isComplex:
                traverseLogger.debug(
                    'No @odata.type present, assuming highest type {} {}'.
                    format(typename, acquiredtype))

        # Check if we provide a valid type (todo: regex)
        self.typename = acquiredtype
        typename = self.typename

        self.initiated = True

        # get our metadata
        metadata = currentService.metadata if currentService else None

        self.typeobj = rfSchema.getTypeObject(typename, self.schemaObj)

        self.propertyList = self.typeobj.getProperties(
            self.jsondata, topVersion=getNamespace(typename))
        propertyList = [prop.payloadName for prop in self.propertyList]

        # get additional
        self.additionalList = []
        propTypeObj = self.typeobj
        if propTypeObj.propPattern is not None and len(
                propTypeObj.propPattern) > 0:
            prop_pattern = propTypeObj.propPattern.get('Pattern', '.*')
            prop_type = propTypeObj.propPattern.get('Type',
                                                    'Resource.OemObject')

            regex = re.compile(prop_pattern)
            for key in [
                    k for k in self.jsondata
                    if k not in propertyList and regex.fullmatch(k)
            ]:
                val = self.jsondata.get(key)
                value_obj = rfSchema.PropItem(propTypeObj.schemaObj,
                                              propTypeObj.fulltype,
                                              key,
                                              val,
                                              customType=prop_type)
                self.additionalList.append(value_obj)

        if config['uricheck'] and self.typeobj.expectedURI is not None:
            my_id = self.jsondata.get('Id')
            self.errorIndex[
                'bad_uri_schema_uri'] = not self.typeobj.compareURI(
                    uri, my_id)
            self.errorIndex[
                'bad_uri_schema_odata'] = not self.typeobj.compareURI(
                    odata_id, my_id)

            if self.errorIndex['bad_uri_schema_uri']:
                traverseLogger.error('{}: URI not in Redfish.Uris: {}'.format(
                    uri, self.typename))
                if my_id != uri.rsplit('/', 1)[-1]:
                    traverseLogger.error(
                        'Id {} in payload doesn\'t seem to match URI'.format(
                            my_id))
            else:
                traverseLogger.debug('{} in Redfish.Uris: {}'.format(
                    uri, self.typename))

            if self.errorIndex['bad_uri_schema_odata']:
                traverseLogger.error(
                    '{}: odata_id not in Redfish.Uris: {}'.format(
                        odata_id, self.typename))
                if my_id != uri.rsplit('/', 1)[-1]:
                    traverseLogger.error(
                        'Id {} in payload doesn\'t seem to match URI'.format(
                            my_id))
            else:
                traverseLogger.debug('{} in Redfish.Uris: {}'.format(
                    odata_id, self.typename))

        # get annotation
        successService, annotationProps = getAnnotations(
            metadata, self.jsondata)
        if successService:
            self.additionalList.extend(annotationProps)

        # list illegitimate properties together
        self.unknownProperties = [
            k for k in self.jsondata if k not in propertyList +
            [prop.payloadName
             for prop in self.additionalList] and '@odata' not in k
        ]

        self.links = OrderedDict()

        sample = config.get('sample')
        linklimits = config.get('linklimits', {})
        self.links.update(
            self.typeobj.getLinksFromType(self.jsondata, self.context,
                                          self.propertyList, oem, linklimits,
                                          sample))

        self.links.update(
            getAllLinks(self.jsondata,
                        self.additionalList,
                        self.schemaObj,
                        context=context,
                        linklimits=linklimits,
                        sample_size=sample,
                        oemCheck=oem))