docs: function addProperty(name, value, constructor, opts) {
          opts = opts || {};
  
          var metadata,
              isStatic,
              isFinal,
              isConst,
              forcePublic = !!(opts.forcePublic || constructor[$class].isVanilla),
              target;
  
          if (opts.metadata) {
              metadata = opts.metadata;
              isFinal = metadata.isFinal;
              isConst = metadata.isConst;
              isStatic = !!opts.isStatic || isConst;
          } else {
              metadata = propertyMeta(value, name);
              if (!metadata) {
                  throw new Error('Value of property "' + name + '"  in class "' + constructor.prototype.$name + '" cannot be parsed (undefined values are not allowed).');
              }
              metadata.isFinal = isFinal = !!opts.isFinal;
              metadata.isConst = isConst = !!opts.isConst;
              isStatic = !!opts.isStatic || isConst;
  
              if (isStatic) {
                  if (constructor[$class].staticProperties[name]) {
                      metadata.allowed = constructor[$class].staticProperties[name].allowed;
                  }
              } else {
                  if (constructor[$class].properties[name]) {
                      metadata.allowed = constructor[$class].properties[name].allowed;
                  }
              }
          }
  
          // Force public if told so
          if (forcePublic) {
              forcePublicMetadata(metadata);
          }
  
          // Check if the metadata was fine (if not then the property is undefined)
          if (!metadata) {
              throw new Error('Value of ' + (isConst ? 'constant ' : (isStatic ? 'static ' : '')) + ' property "' + name + '" defined in class "' + constructor.prototype.$name + '" can\'t be undefined (use null instead).');
          }
          // Check if its a constant and its value is immutable
          if (isConst && !metadata.isImmutable) {
              throw new Error('Value for constant "' + name + '" defined in class "' + constructor.prototype.$name + '" must be a primitive type (immutable).');
          }
          // Check if it's a private property classified as final
          if (metadata.isPrivate && isFinal) {
              throw new Error((isStatic ? 'Static property' : 'Property') + ' "' + name + '" cannot be classified as final in class "' + constructor.prototype.$name + '".');
          }
  
          target = isStatic ? constructor[$class].staticMethods : constructor[$class].methods;
  
          // Check if a method with the same name exists
          if (isObject(target[name])) {
              throw new Error((isConst ? 'Constant property' : (isStatic ? 'Static property' : 'Property')) + ' "' + name + '" is overwriting a ' + (isStatic ? 'static ' : '') + 'method with the same name in class "' + constructor.prototype.$name + '".');
          }
  
          target = isStatic ? constructor[$class].staticProperties : constructor[$class].properties;
  
          if (isObject(target[name])) {
              // Force public if told so
              if (target[name].forcedPublic) {
                  forcePublicMetadata(metadata);
              } else {
                  // Are we overriding a private property?
                  if (target[name].isPrivate) {
                      throw new Error('Cannot override private ' + (isConst ? 'constant ' : (isStatic ? 'static ' : '')) + ' property "' + name + ' in class "' + constructor.prototype.$name + '".');
                  }
              }
              // Are we overriding a constant?
              if (target[name].isConst) {
                  throw new Error('Cannot override constant property "' + name + '" in class "' + constructor.prototype.$name + '".');
              }
              // Are we overriding a final property?
              if (target[name].isFinal) {
                  throw new Error('Cannot override final property "' + name + '" in class "' + constructor.prototype.$name + '".');
              }
          }
  
          target[name] = metadata;
          metadata.value = value;
          if (!isStatic) {
              constructor[$class].ownMembers[name] = true;
          }
  
          // Add it to the constructor or the prototype only if public
          if (metadata.isPublic || !hasDefineProperty) {
              target = isStatic ? constructor : constructor.prototype;
              target[name] = value;
          }
  
          if (isFinal) {
              metadata.isFinal = isFinal;
          } else if (isConst) {
              metadata.isConst = isConst;
          }
  
          if (metadata.isProtected) {
              if (metadata.allowed) {
                  insert(metadata.allowed, constructor[$class].id);
              } else {
                  metadata.allowed = [constructor[$class].id];
              }
          } else if (metadata.isPrivate) {
              metadata.allowed = constructor[$class].id;
          }
      }