private <O extends Objectable> MapXNode serializeObjectContent(
     PrismObject<O> object, SerializationContext ctx) throws SchemaException {
   MapXNode xmap = new MapXNode();
   if (object.getOid() != null) {
     xmap.put(XNode.KEY_OID, createPrimitiveXNodeStringAttr(object.getOid()));
   }
   if (object.getVersion() != null) {
     xmap.put(XNode.KEY_VERSION, createPrimitiveXNodeStringAttr(object.getVersion()));
   }
   PrismObjectDefinition<O> objectDefinition = object.getDefinition();
   serializeContainerValue(xmap, object.getValue(), objectDefinition, ctx);
   return xmap;
 }
  // region Serializing references - specific functionality
  private XNode serializeReferenceValue(
      PrismReferenceValue value, PrismReferenceDefinition definition, SerializationContext ctx)
      throws SchemaException {
    MapXNode xmap = new MapXNode();
    boolean containsOid = false;
    String namespace =
        definition != null
            ? definition.getNamespace()
            : null; // namespace for filter and description
    if (StringUtils.isNotBlank(value.getOid())) {
      containsOid = true;
      xmap.put(XNode.KEY_REFERENCE_OID, createPrimitiveXNodeStringAttr(value.getOid()));
    }
    QName relation = value.getRelation();
    if (relation != null) {
      xmap.put(XNode.KEY_REFERENCE_RELATION, createPrimitiveXNodeAttr(relation, DOMUtil.XSD_QNAME));
    }
    QName targetType = value.getTargetType();
    if (targetType != null) {
      xmap.put(XNode.KEY_REFERENCE_TYPE, createPrimitiveXNodeAttr(targetType, DOMUtil.XSD_QNAME));
    }
    String description = value.getDescription();
    if (description != null) {
      xmap.put(
          createReferenceQName(XNode.KEY_REFERENCE_DESCRIPTION, namespace),
          createPrimitiveXNode(description, DOMUtil.XSD_STRING));
    }
    SearchFilterType filter = value.getFilter();
    if (filter != null) {
      XNode xsubnode = filter.serializeToXNode();
      xmap.put(createReferenceQName(XNode.KEY_REFERENCE_FILTER, namespace), xsubnode);
    }
    if (value.getTargetName() != null) {
      if (SerializationContext.isSerializeReferenceNames(ctx)) {
        XNode xsubnode = createPrimitiveXNode(value.getTargetName(), PolyStringType.COMPLEX_TYPE);
        xmap.put(createReferenceQName(XNode.KEY_REFERENCE_TARGET_NAME, namespace), xsubnode);
      } else {
        String commentValue = " " + value.getTargetName().getOrig() + " ";
        xmap.setComment(commentValue);
      }
    }

    boolean isComposite = false;
    if (definition != null) {
      isComposite = definition.isComposite();
    }
    if ((serializeCompositeObjects || isComposite || !containsOid) && value.getObject() != null) {
      XNode xobjnode = serializeObjectContent(value.getObject(), ctx);
      xmap.put(createReferenceQName(XNode.KEY_REFERENCE_OBJECT, namespace), xobjnode);
    }

    return xmap;
  }
  private <C extends Containerable> void serializeContainerValue(
      MapXNode xmap,
      PrismContainerValue<C> containerVal,
      PrismContainerDefinition<C> containerDefinition,
      SerializationContext ctx)
      throws SchemaException {
    Long id = containerVal.getId();
    if (id != null) {
      xmap.put(XNode.KEY_CONTAINER_ID, createPrimitiveXNodeAttr(id, DOMUtil.XSD_LONG));
    }
    if (containerVal.getConcreteType() != null) {
      xmap.setTypeQName(containerVal.getConcreteType());
      xmap.setExplicitTypeDeclaration(true);
    }

    Collection<QName> serializedItems = new ArrayList<>();
    if (containerDefinition != null) {
      // We have to serialize in the definition order. Some data formats (XML) are
      // ordering-sensitive. We need to keep that ordering otherwise the resulting
      // document won't pass schema validation
      for (ItemDefinition itemDef : containerDefinition.getDefinitions()) {
        QName elementName = itemDef.getName();
        Item<?, ?> item = containerVal.findItem(elementName);
        if (item != null) {
          XNode xsubnode = serializeItem(item, ctx);
          xmap.put(elementName, xsubnode);
          serializedItems.add(elementName);
        }
      }
    }
    // There are some cases when we do not have list of all elements in a container.
    // E.g. in run-time schema. Therefore we must also iterate over items and not just item
    // definitions.
    if (containerVal.getItems() != null) {
      for (Item<?, ?> item : containerVal.getItems()) {
        QName elementName = item.getElementName();
        if (serializedItems.contains(elementName)) {
          continue;
        }
        XNode xsubnode = serializeItem(item, ctx);
        xmap.put(elementName, xsubnode);
      }
    }
  }
  public static <T> String serializeValue(
      T value,
      ItemDefinition def,
      QName itemName,
      QName parentName,
      PrismContext prismContext,
      String language)
      throws SchemaException {
    //		System.out.println("value serialization");
    if (value == null) {
      return null;
    }

    XNodeSerializer serializer = prismContext.getXnodeProcessor().createSerializer();

    if (value instanceof List) {
      List<T> values = (List<T>) value;
      if (values.isEmpty()) {
        return null;
      }

      if (def instanceof PrismPropertyDefinition) {
        PrismProperty prop = (PrismProperty) def.instantiate(itemName);
        for (T val : values) {
          PrismPropertyValue<T> pValue = new PrismPropertyValue<T>(val);
          prop.add(pValue);
        }

        XNode node = serializer.serializeItem(prop);
        if (node instanceof ListXNode) {
          ListXNode xList = (ListXNode) node;
          if (xList.size() == 1) {
            XNode sub = xList.iterator().next();
            if (!(sub instanceof MapXNode)) {
              throw new IllegalArgumentException("must be a map");
            }

            String s = prismContext.getParserDom().serializeToString(sub, parentName);
            //						System.out.println("serialized: " + s);
            return s;

          } else {
            MapXNode xmap = new MapXNode();
            xmap.put(itemName, xList);
            String s = prismContext.getParserDom().serializeToString(xmap, parentName);
            //						System.out.println("serialized: " + s);
            return s;
            //						throw new IllegalArgumentException("Check your data.");
          }

          //					MapXNode xmap = xList.new MapXNode();
          //					xmap.put(def.getName(), xList);

        }
        String s = prismContext.getParserDom().serializeToString(node, def.getName());
        //				System.out.println("serialized: " + s);
        return s;
      } else if (def instanceof PrismContainerDefinition) {
        PrismContainer pc = (PrismContainer) def.instantiate();
        for (T val : values) {
          //					PrismContainerValue pcVal = new PrismContainerValue<Containerable>((Containerable)
          // val);
          PrismContainerValue pcVal = ((Containerable) val).asPrismContainerValue();
          pc.add(pcVal.clone());
        }
        XNode node = serializer.serializeItem(pc);
        if (node instanceof ListXNode) {
          ListXNode xList = (ListXNode) node;
          MapXNode xmap = new MapXNode();
          xmap.put(def.getName(), xList);
          String s = prismContext.getParserDom().serializeToString(xmap, parentName);
          //					System.out.println("serialized: " + s);
          return s;
        }
        String s = prismContext.getParserDom().serializeToString(node, def.getName());
        //				System.out.println("serialized: " + s);
        return s;
      }
    }

    PrismValue pVal = null;

    if (value instanceof Containerable) {
      pVal = ((Containerable) value).asPrismContainerValue();
    } else if (value instanceof Referencable) {
      pVal = ((Referencable) value).asReferenceValue();
    } else {
      pVal = new PrismPropertyValue<T>(value);
    }

    //		Class clazz = prismContext.getSchemaRegistry().determineCompileTimeClass(itemName);
    //		PrismContainerDefinition def =
    // prismContext.getSchemaRegistry().determineDefinitionFromClass(clazz);
    //
    //		ItemDefinition def =
    // prismContext.getSchemaRegistry().findItemDefinitionByElementName(itemName);

    //		QName itemName = null;
    if (def != null) {
      itemName = def.getName();
    }

    XNode node = serializer.serializeItemValue(pVal, def);
    String s = prismContext.getParserDom().serializeToString(node, itemName);
    //		System.out.println("serialized: " + s);
    return s;
    //		throw new UnsupportedOperationException("need to be implemented");
  }
  public static <T> String serializeValue(
      T value,
      PrismPropertyDefinition def,
      QName itemName,
      PrismContext prismContext,
      String langXml)
      throws SchemaException {
    //		System.out.println("value serialization");
    if (value == null) {
      return null;
    }

    XNodeSerializer serializer = prismContext.getXnodeProcessor().createSerializer();

    if (value instanceof List) {
      List<T> values = (List<T>) value;
      if (values.isEmpty()) {
        return null;
      }

      if (def instanceof PrismPropertyDefinition) {
        PrismProperty prop = (PrismProperty) def.instantiate();
        for (T val : values) {
          PrismPropertyValue<T> pValue = new PrismPropertyValue<T>(val);
          prop.add(pValue);
        }
        XNode node = serializer.serializeItem(prop);
        if (node instanceof ListXNode) {
          ListXNode xList = (ListXNode) node;
          MapXNode xmap = new MapXNode();
          xmap.put(def.getName(), xList);
          String s = prismContext.getParserDom().serializeToString(xmap, def.getName());
          //					System.out.println("serialized: " + s);
          return s;
        }
        String s = prismContext.getParserDom().serializeToString(node, def.getName());
        //				System.out.println("serialized: " + s);
        return s;
      }
    }

    PrismValue pVal = null;

    if (value instanceof Containerable) {
      pVal = ((Containerable) value).asPrismContainerValue();
    } else if (value instanceof Referencable) {
      pVal = ((Referencable) value).asReferenceValue();
    } else {
      PrismProperty pp = def.instantiate();
      pVal = new PrismPropertyValue<T>(value);
      pp.add(pVal);
      XNode xnode = serializer.serializeItemValue(pVal, def);
      if (xnode == null) {
        throw new IllegalArgumentException("null node after serialization");
      }
      MapXNode xmap = null;
      if (xnode instanceof RootXNode) {
        XNode sub = ((RootXNode) xnode).getSubnode();
        if (!(sub instanceof MapXNode)) {
          throw new IllegalArgumentException("not uspported yet");
        }
        xmap = (MapXNode) sub;
      } else if (xnode instanceof MapXNode) {
        xmap = (MapXNode) xnode;
      } else if (xnode instanceof PrimitiveXNode) {
        String s = ((PrimitiveXNode) xnode).getStringValue();
        return s;
        //
      } else {
        throw new IllegalStateException("hmmm");
      }

      XNode node = xmap.get(itemName);
      String s = prismContext.getParserDom().serializeToString(node, itemName);
    }

    XNode node = serializer.serializeItemValue(pVal, def);
    String s = prismContext.getParserDom().serializeToString(node, itemName);
    //		System.out.println("serialized: " + s);
    return s;
    //		throw new UnsupportedOperationException("need to be implemented");

  }