diff --git a/app/code/Magento/Bundle/Block/Adminhtml/Sales/Order/Items/Renderer.php b/app/code/Magento/Bundle/Block/Adminhtml/Sales/Order/Items/Renderer.php
index ad9a0b9bbbebfba225c71f532e14a860598e1567..914da1144bc0b22ef41acc2ff6be9d358259fa72 100644
--- a/app/code/Magento/Bundle/Block/Adminhtml/Sales/Order/Items/Renderer.php
+++ b/app/code/Magento/Bundle/Block/Adminhtml/Sales/Order/Items/Renderer.php
@@ -6,12 +6,42 @@
 namespace Magento\Bundle\Block\Adminhtml\Sales\Order\Items;
 
 use Magento\Catalog\Model\Product\Type\AbstractType;
+use Magento\Framework\Serialize\Serializer\Json;
 
 /**
  * Adminhtml sales order item renderer
  */
 class Renderer extends \Magento\Sales\Block\Adminhtml\Items\Renderer\DefaultRenderer
 {
+    /**
+     * Serializer
+     *
+     * @var Json
+     */
+    private $serializer;
+
+    /**
+     * @param \Magento\Backend\Block\Template\Context $context
+     * @param \Magento\CatalogInventory\Api\StockRegistryInterface $stockRegistry
+     * @param \Magento\CatalogInventory\Api\StockConfigurationInterface $stockConfiguration
+     * @param \Magento\Framework\Registry $registry
+     * @param array $data
+     * @param \Magento\Framework\Serialize\Serializer\Json $serializer
+     */
+    public function __construct(
+        \Magento\Backend\Block\Template\Context $context,
+        \Magento\CatalogInventory\Api\StockRegistryInterface $stockRegistry,
+        \Magento\CatalogInventory\Api\StockConfigurationInterface $stockConfiguration,
+        \Magento\Framework\Registry $registry,
+        array $data = [],
+        Json $serializer = null
+    ) {
+        $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance()
+            ->get(Json::class);
+
+        parent::__construct($context, $stockRegistry, $stockConfiguration, $registry, $data);
+    }
+
     /**
      * Truncate string
      *
@@ -153,7 +183,7 @@ class Renderer extends \Magento\Sales\Block\Adminhtml\Items\Renderer\DefaultRend
             $options = $item->getOrderItem()->getProductOptions();
         }
         if (isset($options['bundle_selection_attributes'])) {
-            return unserialize($options['bundle_selection_attributes']);
+            return $this->serializer->unserialize($options['bundle_selection_attributes']);
         }
         return null;
     }
diff --git a/app/code/Magento/Bundle/Block/Adminhtml/Sales/Order/View/Items/Renderer.php b/app/code/Magento/Bundle/Block/Adminhtml/Sales/Order/View/Items/Renderer.php
index 01e122a56b52d635ceed284a2a2d370a93677181..0cb7cc0b45ad5f7459c28f87639c77b8760ba810 100644
--- a/app/code/Magento/Bundle/Block/Adminhtml/Sales/Order/View/Items/Renderer.php
+++ b/app/code/Magento/Bundle/Block/Adminhtml/Sales/Order/View/Items/Renderer.php
@@ -6,12 +6,54 @@
 namespace Magento\Bundle\Block\Adminhtml\Sales\Order\View\Items;
 
 use Magento\Catalog\Model\Product\Type\AbstractType;
+use Magento\Framework\Serialize\Serializer\Json;
 
 /**
  * Adminhtml sales order item renderer
  */
 class Renderer extends \Magento\Sales\Block\Adminhtml\Order\View\Items\Renderer\DefaultRenderer
 {
+    /**
+     * Serializer
+     *
+     * @var Json
+     */
+    private $serializer;
+
+    /**
+     * @param \Magento\Backend\Block\Template\Context $context
+     * @param \Magento\CatalogInventory\Api\StockRegistryInterface $stockRegistry
+     * @param \Magento\CatalogInventory\Api\StockConfigurationInterface $stockConfiguration
+     * @param \Magento\Framework\Registry $registry
+     * @param \Magento\GiftMessage\Helper\Message $messageHelper
+     * @param \Magento\Checkout\Helper\Data $checkoutHelper
+     * @param array $data
+     * @param \Magento\Framework\Serialize\Serializer\Json $serializer
+     */
+    public function __construct(
+        \Magento\Backend\Block\Template\Context $context,
+        \Magento\CatalogInventory\Api\StockRegistryInterface $stockRegistry,
+        \Magento\CatalogInventory\Api\StockConfigurationInterface $stockConfiguration,
+        \Magento\Framework\Registry $registry,
+        \Magento\GiftMessage\Helper\Message $messageHelper,
+        \Magento\Checkout\Helper\Data $checkoutHelper,
+        array $data = [],
+        Json $serializer = null
+    ) {
+        $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance()
+            ->get(Json::class);
+
+        parent::__construct(
+            $context,
+            $stockRegistry,
+            $stockConfiguration,
+            $registry,
+            $messageHelper,
+            $checkoutHelper,
+            $data
+        );
+    }
+
     /**
      * Truncate string
      *
@@ -110,7 +152,7 @@ class Renderer extends \Magento\Sales\Block\Adminhtml\Order\View\Items\Renderer\
             $options = $item->getOrderItem()->getProductOptions();
         }
         if (isset($options['bundle_selection_attributes'])) {
-            return unserialize($options['bundle_selection_attributes']);
+            return $this->serializer->unserialize($options['bundle_selection_attributes']);
         }
         return null;
     }
diff --git a/app/code/Magento/Bundle/Block/Sales/Order/Items/Renderer.php b/app/code/Magento/Bundle/Block/Sales/Order/Items/Renderer.php
index f8b243c84c05855f7c868a5746e4cc7f1132405e..a8e85e6c5fa66ac407ed10c4c1d2f032d205221f 100644
--- a/app/code/Magento/Bundle/Block/Sales/Order/Items/Renderer.php
+++ b/app/code/Magento/Bundle/Block/Sales/Order/Items/Renderer.php
@@ -6,6 +6,7 @@
 namespace Magento\Bundle\Block\Sales\Order\Items;
 
 use Magento\Catalog\Model\Product\Type\AbstractType;
+use Magento\Framework\Serialize\Serializer\Json;
 
 /**
  * Order item render block
@@ -14,6 +15,33 @@ use Magento\Catalog\Model\Product\Type\AbstractType;
  */
 class Renderer extends \Magento\Sales\Block\Order\Item\Renderer\DefaultRenderer
 {
+    /**
+     * Serializer
+     *
+     * @var Json
+     */
+    private $serializer;
+
+    /**
+     * @param \Magento\Framework\View\Element\Template\Context $context
+     * @param \Magento\Framework\Stdlib\StringUtils $string
+     * @param \Magento\Catalog\Model\Product\OptionFactory $productOptionFactory
+     * @param array $data
+     * @param \Magento\Framework\Serialize\Serializer\Json $serializer
+     */
+    public function __construct(
+        \Magento\Framework\View\Element\Template\Context $context,
+        \Magento\Framework\Stdlib\StringUtils $string,
+        \Magento\Catalog\Model\Product\OptionFactory $productOptionFactory,
+        array $data = [],
+        Json $serializer = null
+    ) {
+        $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance()
+            ->get(Json::class);
+
+        parent::__construct($context, $string, $productOptionFactory, $data);
+    }
+
     /**
      * @param mixed $item
      * @return bool
@@ -100,7 +128,7 @@ class Renderer extends \Magento\Sales\Block\Order\Item\Renderer\DefaultRenderer
             $options = $item->getOrderItem()->getProductOptions();
         }
         if (isset($options['bundle_selection_attributes'])) {
-            return unserialize($options['bundle_selection_attributes']);
+            return $this->serializer->unserialize($options['bundle_selection_attributes']);
         }
         return null;
     }
diff --git a/app/code/Magento/Bundle/Helper/Catalog/Product/Configuration.php b/app/code/Magento/Bundle/Helper/Catalog/Product/Configuration.php
index 8305bb0137ed2b091b0d70916917276dcfc4b7a7..3ad004fabead10b6073e82cf0e2091f74eecfbc5 100644
--- a/app/code/Magento/Bundle/Helper/Catalog/Product/Configuration.php
+++ b/app/code/Magento/Bundle/Helper/Catalog/Product/Configuration.php
@@ -35,21 +35,32 @@ class Configuration extends AbstractHelper implements ConfigurationInterface
      */
     protected $escaper;
 
+    /**
+     * Serializer interface instance.
+     *
+     * @var \Magento\Framework\Serialize\Serializer\Json
+     */
+    private $serializer;
+
     /**
      * @param \Magento\Framework\App\Helper\Context $context
      * @param \Magento\Catalog\Helper\Product\Configuration $productConfiguration
      * @param \Magento\Framework\Pricing\Helper\Data $pricingHelper
      * @param \Magento\Framework\Escaper $escaper
+     * @param \Magento\Framework\Serialize\Serializer\Json|null $serializer
      */
     public function __construct(
         \Magento\Framework\App\Helper\Context $context,
         \Magento\Catalog\Helper\Product\Configuration $productConfiguration,
         \Magento\Framework\Pricing\Helper\Data $pricingHelper,
-        \Magento\Framework\Escaper $escaper
+        \Magento\Framework\Escaper $escaper,
+        \Magento\Framework\Serialize\Serializer\Json $serializer = null
     ) {
         $this->productConfiguration = $productConfiguration;
         $this->pricingHelper = $pricingHelper;
         $this->escaper = $escaper;
+        $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance()
+            ->get(\Magento\Framework\Serialize\Serializer\Json::class);
         parent::__construct($context);
     }
 
@@ -113,7 +124,10 @@ class Configuration extends AbstractHelper implements ConfigurationInterface
 
         // get bundle options
         $optionsQuoteItemOption = $item->getOptionByCode('bundle_option_ids');
-        $bundleOptionsIds = $optionsQuoteItemOption ? unserialize($optionsQuoteItemOption->getValue()) : [];
+        $bundleOptionsIds = $optionsQuoteItemOption
+            ? $this->serializer->unserialize($optionsQuoteItemOption->getValue())
+            : [];
+
         if ($bundleOptionsIds) {
             /** @var \Magento\Bundle\Model\ResourceModel\Option\Collection $optionsCollection */
             $optionsCollection = $typeInstance->getOptionsByIds($bundleOptionsIds, $product);
@@ -121,7 +135,7 @@ class Configuration extends AbstractHelper implements ConfigurationInterface
             // get and add bundle selections collection
             $selectionsQuoteItemOption = $item->getOptionByCode('bundle_selection_ids');
 
-            $bundleSelectionIds = unserialize($selectionsQuoteItemOption->getValue());
+            $bundleSelectionIds = $this->serializer->unserialize($selectionsQuoteItemOption->getValue());
 
             if (!empty($bundleSelectionIds)) {
                 $selectionsCollection = $typeInstance->getSelectionsByIds($bundleSelectionIds, $product);
diff --git a/app/code/Magento/Bundle/Model/Product/Price.php b/app/code/Magento/Bundle/Model/Product/Price.php
index d0aee24945f9d21df7c3d73350093206065b0429..f5043f1f7edc67c861b7e31fb5386f790adbf1f0 100644
--- a/app/code/Magento/Bundle/Model/Product/Price.php
+++ b/app/code/Magento/Bundle/Model/Product/Price.php
@@ -39,6 +39,13 @@ class Price extends \Magento\Catalog\Model\Product\Type\Price
      */
     protected $_catalogData = null;
 
+    /**
+     * Serializer interface instance.
+     *
+     * @var \Magento\Framework\Serialize\Serializer\Json
+     */
+    private $serializer;
+
     /**
      * Price constructor.
      *
@@ -52,7 +59,7 @@ class Price extends \Magento\Catalog\Model\Product\Type\Price
      * @param \Magento\Catalog\Api\Data\ProductTierPriceInterfaceFactory $tierPriceFactory
      * @param \Magento\Framework\App\Config\ScopeConfigInterface $config
      * @param \Magento\Catalog\Helper\Data $catalogData
-     *
+     * @param \Magento\Framework\Serialize\Serializer\Json|null $serializer
      * @SuppressWarnings(PHPMD.ExcessiveParameterList)
      */
     public function __construct(
@@ -65,9 +72,12 @@ class Price extends \Magento\Catalog\Model\Product\Type\Price
         GroupManagementInterface $groupManagement,
         \Magento\Catalog\Api\Data\ProductTierPriceInterfaceFactory $tierPriceFactory,
         \Magento\Framework\App\Config\ScopeConfigInterface $config,
-        \Magento\Catalog\Helper\Data $catalogData
+        \Magento\Catalog\Helper\Data $catalogData,
+        \Magento\Framework\Serialize\Serializer\Json $serializer = null
     ) {
         $this->_catalogData = $catalogData;
+        $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance()
+            ->get(\Magento\Framework\Serialize\Serializer\Json::class);
         parent::__construct(
             $ruleFactory,
             $storeManager,
@@ -154,7 +164,7 @@ class Price extends \Magento\Catalog\Model\Product\Type\Price
     {
         $customOption = $product->getCustomOption('bundle_selection_ids');
         if ($customOption) {
-            $selectionIds = unserialize($customOption->getValue());
+            $selectionIds = $this->serializer->unserialize($customOption->getValue());
             if (!empty($selectionIds) && is_array($selectionIds)) {
                 return $selectionIds;
             }
diff --git a/app/code/Magento/Bundle/Model/Product/Type.php b/app/code/Magento/Bundle/Model/Product/Type.php
index 3e8ae11c4faf362831ead26e549621ea483b9c7c..cef57f610fc2103eb729d7957b1ac5eef6b4d567 100644
--- a/app/code/Magento/Bundle/Model/Product/Type.php
+++ b/app/code/Magento/Bundle/Model/Product/Type.php
@@ -9,8 +9,8 @@
 namespace Magento\Bundle\Model\Product;
 
 use Magento\Catalog\Api\ProductRepositoryInterface;
-use Magento\Framework\App\ObjectManager;
 use Magento\Framework\Pricing\PriceCurrencyInterface;
+use Magento\Framework\Serialize\Serializer\Json;
 
 /**
  * Bundle Type Model
@@ -168,6 +168,7 @@ class Type extends \Magento\Catalog\Model\Product\Type\AbstractType
      * @param PriceCurrencyInterface $priceCurrency
      * @param \Magento\CatalogInventory\Api\StockRegistryInterface $stockRegistry
      * @param \Magento\CatalogInventory\Api\StockStateInterface $stockState
+     * @param \Magento\Framework\Serialize\Serializer\Json $serializer
      *
      * @SuppressWarnings(PHPMD.ExcessiveParameterList)
      */
@@ -192,7 +193,8 @@ class Type extends \Magento\Catalog\Model\Product\Type\AbstractType
         \Magento\Store\Model\StoreManagerInterface $storeManager,
         PriceCurrencyInterface $priceCurrency,
         \Magento\CatalogInventory\Api\StockRegistryInterface $stockRegistry,
-        \Magento\CatalogInventory\Api\StockStateInterface $stockState
+        \Magento\CatalogInventory\Api\StockStateInterface $stockState,
+        Json $serializer = null
     ) {
         $this->_catalogProduct = $catalogProduct;
         $this->_catalogData = $catalogData;
@@ -206,6 +208,7 @@ class Type extends \Magento\Catalog\Model\Product\Type\AbstractType
         $this->priceCurrency = $priceCurrency;
         $this->_stockRegistry = $stockRegistry;
         $this->_stockState = $stockState;
+
         parent::__construct(
             $catalogProductOption,
             $eavConfig,
@@ -215,7 +218,8 @@ class Type extends \Magento\Catalog\Model\Product\Type\AbstractType
             $filesystem,
             $coreRegistry,
             $logger,
-            $productRepository
+            $productRepository,
+            $serializer
         );
     }
 
@@ -277,7 +281,7 @@ class Type extends \Magento\Catalog\Model\Product\Type\AbstractType
 
             if ($product->hasCustomOptions()) {
                 $customOption = $product->getCustomOption('bundle_selection_ids');
-                $selectionIds = unserialize($customOption->getValue());
+                $selectionIds = $this->serializer->unserialize($customOption->getValue());
                 if (!empty($selectionIds)) {
                     $selections = $this->getSelectionsByIds($selectionIds, $product);
                     foreach ($selections->getItems() as $selection) {
@@ -305,7 +309,7 @@ class Type extends \Magento\Catalog\Model\Product\Type\AbstractType
 
             if ($product->hasCustomOptions()) {
                 $customOption = $product->getCustomOption('bundle_selection_ids');
-                $selectionIds = unserialize($customOption->getValue());
+                $selectionIds = $this->serializer->unserialize($customOption->getValue());
                 $selections = $this->getSelectionsByIds($selectionIds, $product);
                 foreach ($selections->getItems() as $selection) {
                     $qtyOption = $product->getCustomOption('selection_qty_' . $selection->getSelectionId());
@@ -331,7 +335,7 @@ class Type extends \Magento\Catalog\Model\Product\Type\AbstractType
     {
         if ($product->hasCustomOptions()) {
             $customOption = $product->getCustomOption('bundle_selection_ids');
-            $selectionIds = unserialize($customOption->getValue());
+            $selectionIds = $this->serializer->unserialize($customOption->getValue());
             $selections = $this->getSelectionsByIds($selectionIds, $product);
             $virtualCount = 0;
             foreach ($selections->getItems() as $selection) {
@@ -697,8 +701,14 @@ class Type extends \Magento\Catalog\Model\Product\Type\AbstractType
                     $this->checkIsResult($_result);
 
                     $result[] = $_result[0]->setParentProductId($product->getId())
-                        ->addCustomOption('bundle_option_ids', serialize(array_map('intval', $optionIds)))
-                        ->addCustomOption('bundle_selection_attributes', serialize($attributes));
+                        ->addCustomOption(
+                            'bundle_option_ids',
+                            $this->serializer->serialize(array_map('intval', $optionIds))
+                        )
+                        ->addCustomOption(
+                            'bundle_selection_attributes',
+                            $this->serializer->serialize($attributes)
+                        );
 
                     if ($isStrictProcessMode) {
                         $_result[0]->setCartQty($qty);
@@ -715,8 +725,13 @@ class Type extends \Magento\Catalog\Model\Product\Type\AbstractType
                 foreach ($result as $item) {
                     $item->addCustomOption('bundle_identity', $uniqueKey);
                 }
-                $product->addCustomOption('bundle_option_ids', serialize(array_map('intval', $optionIds)));
-                $product->addCustomOption('bundle_selection_ids', serialize($selectionIds));
+                $product->addCustomOption(
+                    'bundle_option_ids',
+                    $this->serializer->serialize(
+                        array_map('intval', $optionIds)
+                    )
+                );
+                $product->addCustomOption('bundle_selection_ids', $this->serializer->serialize($selectionIds));
 
                 return $result;
             }
@@ -826,7 +841,10 @@ class Type extends \Magento\Catalog\Model\Product\Type\AbstractType
         $usedOptions = $product->getData($this->_keyUsedOptions);
         $usedOptionsIds = $product->getData($this->_keyUsedOptionsIds);
 
-        if (!$usedOptions || serialize($usedOptionsIds) != serialize($optionIds)) {
+        if (
+            !$usedOptions
+            || $this->serializer->serialize($usedOptionsIds) != $this->serializer->serialize($optionIds)
+        ) {
             $usedOptions = $this->_bundleOption
                 ->create()
                 ->getResourceCollection()
@@ -858,10 +876,10 @@ class Type extends \Magento\Catalog\Model\Product\Type\AbstractType
 
         if ($product->hasCustomOptions()) {
             $customOption = $product->getCustomOption('bundle_option_ids');
-            $optionIds = unserialize($customOption->getValue());
+            $optionIds = $this->serializer->unserialize($customOption->getValue());
             $options = $this->getOptionsByIds($optionIds, $product);
             $customOption = $product->getCustomOption('bundle_selection_ids');
-            $selectionIds = unserialize($customOption->getValue());
+            $selectionIds = $this->serializer->unserialize($customOption->getValue());
             $selections = $this->getSelectionsByIds($selectionIds, $product);
             foreach ($selections->getItems() as $selection) {
                 if ($selection->isSalable()) {
@@ -1010,10 +1028,10 @@ class Type extends \Magento\Catalog\Model\Product\Type\AbstractType
         $productOptionIds = $this->getOptionsIds($product);
         $productSelections = $this->getSelectionsCollection($productOptionIds, $product);
         $selectionIds = $product->getCustomOption('bundle_selection_ids');
-        $selectionIds = unserialize($selectionIds->getValue());
+        $selectionIds = $this->serializer->unserialize($selectionIds->getValue());
         $buyRequest = $product->getCustomOption('info_buyRequest');
-        $buyRequest = new \Magento\Framework\DataObject(unserialize($buyRequest->getValue()));
-        $bundleOption = $buyRequest->getBundleOption();
+ 	 	$buyRequest = new \Magento\Framework\DataObject($this->serializer->unserialize($buyRequest->getValue()));
+ 	 	$bundleOption = $buyRequest->getBundleOption();
 
         if (empty($bundleOption)) {
             throw new \Magento\Framework\Exception\LocalizedException($this->getSpecifyOptionMessage());
diff --git a/app/code/Magento/Bundle/Model/Sales/Order/Pdf/Items/AbstractItems.php b/app/code/Magento/Bundle/Model/Sales/Order/Pdf/Items/AbstractItems.php
index 2b479b4a2506ec5f62cadbb3f70082bc08dc83eb..d96294eacc0b7a22257f7276abdaa07516af7465 100644
--- a/app/code/Magento/Bundle/Model/Sales/Order/Pdf/Items/AbstractItems.php
+++ b/app/code/Magento/Bundle/Model/Sales/Order/Pdf/Items/AbstractItems.php
@@ -6,12 +6,60 @@
 namespace Magento\Bundle\Model\Sales\Order\Pdf\Items;
 
 use Magento\Catalog\Model\Product\Type\AbstractType;
+use Magento\Framework\App\ObjectManager;
+use Magento\Framework\Serialize\Serializer\Json;
 
 /**
- * Sales Order Pdf Items renderer
+ * Order pdf items renderer
+ *
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  */
 abstract class AbstractItems extends \Magento\Sales\Model\Order\Pdf\Items\AbstractItems
 {
+    /**
+     * Serializer
+     *
+     * @var Json
+     */
+    private $serializer;
+
+    /**
+     * Constructor
+     *
+     * @param \Magento\Framework\Model\Context $context
+     * @param \Magento\Framework\Registry $registry
+     * @param \Magento\Tax\Helper\Data $taxData
+     * @param \Magento\Framework\Filesystem $filesystem
+     * @param \Magento\Framework\Filter\FilterManager $filterManager
+     * @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource
+     * @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection
+     * @param array $data
+     * @param \Magento\Framework\Serialize\Serializer\Json $serializer
+     */
+    public function __construct(
+        \Magento\Framework\Model\Context $context,
+        \Magento\Framework\Registry $registry,
+        \Magento\Tax\Helper\Data $taxData,
+        \Magento\Framework\Filesystem $filesystem,
+        \Magento\Framework\Filter\FilterManager $filterManager,
+        \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
+        \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
+        array $data = [],
+        Json $serializer = null
+    ) {
+        $this->serializer = $serializer ?: ObjectManager::getInstance()->get(Json::class);
+        parent::__construct(
+            $context,
+            $registry,
+            $taxData,
+            $filesystem,
+            $filterManager,
+            $resource,
+            $resourceCollection,
+            $data
+        );
+    }
+
     /**
      * Getting all available children for Invoice, Shipment or CreditMemo item
      *
@@ -157,7 +205,7 @@ abstract class AbstractItems extends \Magento\Sales\Model\Order\Pdf\Items\Abstra
             $options = $item->getOrderItem()->getProductOptions();
         }
         if (isset($options['bundle_selection_attributes'])) {
-            return unserialize($options['bundle_selection_attributes']);
+            return $this->serializer->unserialize($options['bundle_selection_attributes']);
         }
         return null;
     }
diff --git a/app/code/Magento/Bundle/Model/Sales/Order/Pdf/Items/Creditmemo.php b/app/code/Magento/Bundle/Model/Sales/Order/Pdf/Items/Creditmemo.php
index 2ac6e484bb5b51902c5e4cc0743791dfb5561e8f..b9efefa03ebe11083dab8edee385a03f2dd772af 100644
--- a/app/code/Magento/Bundle/Model/Sales/Order/Pdf/Items/Creditmemo.php
+++ b/app/code/Magento/Bundle/Model/Sales/Order/Pdf/Items/Creditmemo.php
@@ -5,8 +5,11 @@
  */
 namespace Magento\Bundle\Model\Sales\Order\Pdf\Items;
 
+use Magento\Framework\App\ObjectManager;
+use Magento\Framework\Serialize\Serializer\Json;
+
 /**
- * Sales Order Creditmemo Pdf default items renderer
+ * Order creditmemo pdf default items renderer
  */
 class Creditmemo extends AbstractItems
 {
@@ -18,6 +21,8 @@ class Creditmemo extends AbstractItems
     protected $string;
 
     /**
+     * Constructor
+     *
      * @param \Magento\Framework\Model\Context $context
      * @param \Magento\Framework\Registry $registry
      * @param \Magento\Tax\Helper\Data $taxData
@@ -27,6 +32,8 @@ class Creditmemo extends AbstractItems
      * @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource
      * @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection
      * @param array $data
+     * @param \Magento\Framework\Serialize\Serializer\Json|null $serializer
+     * @SuppressWarnings(PHPMD.ExcessiveParameterList)
      */
     public function __construct(
         \Magento\Framework\Model\Context $context,
@@ -37,7 +44,8 @@ class Creditmemo extends AbstractItems
         \Magento\Framework\Stdlib\StringUtils $string,
         \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
         \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
-        array $data = []
+        array $data = [],
+        Json $serializer = null
     ) {
         $this->string = $string;
         parent::__construct(
@@ -48,7 +56,8 @@ class Creditmemo extends AbstractItems
             $filterManager,
             $resource,
             $resourceCollection,
-            $data
+            $data,
+            $serializer
         );
     }
 
diff --git a/app/code/Magento/Bundle/Model/Sales/Order/Pdf/Items/Invoice.php b/app/code/Magento/Bundle/Model/Sales/Order/Pdf/Items/Invoice.php
index 9b5d0b4a9c0188727eab52350525397bfc412cc5..e164ffa394a9687a51563d25d8bbd9c7d11aad47 100644
--- a/app/code/Magento/Bundle/Model/Sales/Order/Pdf/Items/Invoice.php
+++ b/app/code/Magento/Bundle/Model/Sales/Order/Pdf/Items/Invoice.php
@@ -3,13 +3,15 @@
  * Copyright © 2016 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-
-// @codingStandardsIgnoreFile
-
 namespace Magento\Bundle\Model\Sales\Order\Pdf\Items;
 
+use Magento\Framework\App\ObjectManager;
+use Magento\Framework\Serialize\Serializer\Json;
+
 /**
- * Sales Order Invoice Pdf default items renderer
+ * Order invoice pdf default items renderer
+ *
+ * @codingStandardsIgnoreFile
  */
 class Invoice extends AbstractItems
 {
@@ -19,6 +21,8 @@ class Invoice extends AbstractItems
     protected $string;
 
     /**
+     * Constructor
+     *
      * @param \Magento\Framework\Model\Context $context
      * @param \Magento\Framework\Registry $registry
      * @param \Magento\Tax\Helper\Data $taxData
@@ -28,6 +32,8 @@ class Invoice extends AbstractItems
      * @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource
      * @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection
      * @param array $data
+     * @param \Magento\Framework\Serialize\Serializer\Json|null $serializer
+     * @SuppressWarnings(PHPMD.ExcessiveParameterList)
      */
     public function __construct(
         \Magento\Framework\Model\Context $context,
@@ -38,7 +44,8 @@ class Invoice extends AbstractItems
         \Magento\Framework\Stdlib\StringUtils $coreString,
         \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
         \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
-        array $data = []
+        array $data = [],
+        Json $serializer = null
     ) {
         $this->string = $coreString;
         parent::__construct(
@@ -49,7 +56,8 @@ class Invoice extends AbstractItems
             $filterManager,
             $resource,
             $resourceCollection,
-            $data
+            $data,
+            $serializer
         );
     }
 
diff --git a/app/code/Magento/Bundle/Model/Sales/Order/Pdf/Items/Shipment.php b/app/code/Magento/Bundle/Model/Sales/Order/Pdf/Items/Shipment.php
index fec75878c305319241eb1e845fb8896bdc63a4a3..0df79bd57b1b4f2523a2f10bcb584b0ad3233f80 100644
--- a/app/code/Magento/Bundle/Model/Sales/Order/Pdf/Items/Shipment.php
+++ b/app/code/Magento/Bundle/Model/Sales/Order/Pdf/Items/Shipment.php
@@ -5,8 +5,11 @@
  */
 namespace Magento\Bundle\Model\Sales\Order\Pdf\Items;
 
+use Magento\Framework\App\ObjectManager;
+use Magento\Framework\Serialize\Serializer\Json;
+
 /**
- * Sales Order Shipment Pdf items renderer
+ * Order shipment pdf items renderer
  */
 class Shipment extends AbstractItems
 {
@@ -16,6 +19,8 @@ class Shipment extends AbstractItems
     protected $string;
 
     /**
+     * Constructor
+     *
      * @param \Magento\Framework\Model\Context $context
      * @param \Magento\Framework\Registry $registry
      * @param \Magento\Tax\Helper\Data $taxData
@@ -25,6 +30,8 @@ class Shipment extends AbstractItems
      * @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource
      * @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection
      * @param array $data
+     * @param \Magento\Framework\Serialize\Serializer\Json|null $serializer
+     * @SuppressWarnings(PHPMD.ExcessiveParameterList)
      */
     public function __construct(
         \Magento\Framework\Model\Context $context,
@@ -35,7 +42,8 @@ class Shipment extends AbstractItems
         \Magento\Framework\Stdlib\StringUtils $string,
         \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
         \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
-        array $data = []
+        array $data = [],
+        Json $serializer = null
     ) {
         $this->string = $string;
         parent::__construct(
@@ -46,7 +54,8 @@ class Shipment extends AbstractItems
             $filterManager,
             $resource,
             $resourceCollection,
-            $data
+            $data,
+            $serializer
         );
     }
 
diff --git a/app/code/Magento/Bundle/Pricing/Price/ConfiguredPrice.php b/app/code/Magento/Bundle/Pricing/Price/ConfiguredPrice.php
index e6c0f90e24a5cd3ef1bd59bcdd20ebb98b14f962..2069b91426fad1f16352691c2280b060259832ef 100644
--- a/app/code/Magento/Bundle/Pricing/Price/ConfiguredPrice.php
+++ b/app/code/Magento/Bundle/Pricing/Price/ConfiguredPrice.php
@@ -32,21 +32,32 @@ class ConfiguredPrice extends CatalogPrice\FinalPrice implements ConfiguredPrice
      */
     protected $item;
 
+    /**
+     * Serializer interface instance.
+     *
+     * @var \Magento\Framework\Serialize\Serializer\Json
+     */
+    private $serializer;
+
     /**
      * @param Product $saleableItem
      * @param float $quantity
      * @param BundleCalculatorInterface $calculator
      * @param \Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency
      * @param ItemInterface $item
+     * @param \Magento\Framework\Serialize\Serializer\Json|null $serializer
      */
     public function __construct(
         Product $saleableItem,
         $quantity,
         BundleCalculatorInterface $calculator,
         \Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency,
-        ItemInterface $item = null
+        ItemInterface $item = null,
+        \Magento\Framework\Serialize\Serializer\Json $serializer = null
     ) {
         $this->item = $item;
+        $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance()
+            ->get(\Magento\Framework\Serialize\Serializer\Json::class);
         parent::__construct($saleableItem, $quantity, $calculator, $priceCurrency);
     }
 
@@ -74,13 +85,16 @@ class ConfiguredPrice extends CatalogPrice\FinalPrice implements ConfiguredPrice
 
         // get bundle options
         $optionsQuoteItemOption = $this->item->getOptionByCode('bundle_option_ids');
-        $bundleOptionsIds = $optionsQuoteItemOption ? unserialize($optionsQuoteItemOption->getValue()) : [];
+        $bundleOptionsIds = $optionsQuoteItemOption
+            ? $this->serializer->unserialize($optionsQuoteItemOption->getValue())
+            : [];
+
         if ($bundleOptionsIds) {
             /** @var \Magento\Bundle\Model\ResourceModel\Option\Collection $optionsCollection */
             $optionsCollection = $typeInstance->getOptionsByIds($bundleOptionsIds, $bundleProduct);
             // get and add bundle selections collection
             $selectionsQuoteItemOption = $this->item->getOptionByCode('bundle_selection_ids');
-            $bundleSelectionIds = unserialize($selectionsQuoteItemOption->getValue());
+            $bundleSelectionIds = $this->serializer->unserialize($selectionsQuoteItemOption->getValue());
             if ($bundleSelectionIds) {
                 $selectionsCollection = $typeInstance->getSelectionsByIds($bundleSelectionIds, $bundleProduct);
                 $bundleOptions = $optionsCollection->appendSelections($selectionsCollection, true);
diff --git a/app/code/Magento/Bundle/Test/Unit/Block/Adminhtml/Sales/Order/Items/RendererTest.php b/app/code/Magento/Bundle/Test/Unit/Block/Adminhtml/Sales/Order/Items/RendererTest.php
index aee7b81edc1c4e57a6edc5d29ed7fb3a9687f5ad..af02f9d6129c4d400a7437a289cee0e9aec3f938 100644
--- a/app/code/Magento/Bundle/Test/Unit/Block/Adminhtml/Sales/Order/Items/RendererTest.php
+++ b/app/code/Magento/Bundle/Test/Unit/Block/Adminhtml/Sales/Order/Items/RendererTest.php
@@ -13,6 +13,9 @@ class RendererTest extends \PHPUnit_Framework_TestCase
     /** @var \Magento\Bundle\Block\Adminhtml\Sales\Order\Items\Renderer $model */
     protected $model;
 
+    /** @var \Magento\Framework\Serialize\Serializer\Json|\PHPUnit_Framework_MockObject_MockObject $serializer */
+    protected $serializer;
+
     protected function setUp()
     {
         $this->orderItem = $this->getMock(
@@ -22,9 +25,12 @@ class RendererTest extends \PHPUnit_Framework_TestCase
             '',
             false
         );
-
+        $this->serializer = $this->getMock(\Magento\Framework\Serialize\Serializer\Json::class);
         $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
-        $this->model = $objectManager->getObject(\Magento\Bundle\Block\Adminhtml\Sales\Order\Items\Renderer::class);
+        $this->model = $objectManager->getObject(
+            \Magento\Bundle\Block\Adminhtml\Sales\Order\Items\Renderer::class,
+            ['serializer' => $this->serializer]
+        );
     }
 
     /**
@@ -221,21 +227,25 @@ class RendererTest extends \PHPUnit_Framework_TestCase
         ];
     }
 
-    /**
-     * @dataProvider getSelectionAttributesDataProvider
-     */
-    public function testGetSelectionAttributes($productOptions, $result)
+    public function testGetSelectionAttributes()
     {
-        $this->orderItem->expects($this->any())->method('getProductOptions')->will($this->returnValue($productOptions));
-        $this->assertSame($result, $this->model->getSelectionAttributes($this->orderItem));
+        $this->orderItem->expects($this->any())->method('getProductOptions')->will($this->returnValue([]));
+        $this->assertNull($this->model->getSelectionAttributes($this->orderItem));
     }
 
-    public function getSelectionAttributesDataProvider()
+    public function testGetSelectionAttributesWithBundle()
     {
-        return [
-            [[], null],
-            [['bundle_selection_attributes' => 'a:1:{i:0;i:1;}'], [0 => 1]],
-        ];
+        $bundleAttributes = 'Serialized value';
+        $options = ['bundle_selection_attributes' => $bundleAttributes];
+        $unserializedResult = 'result of "bundle_selection_attributes" unserialization';
+
+        $this->serializer->expects($this->any())
+            ->method('unserialize')
+            ->with($bundleAttributes)
+            ->will($this->returnValue($unserializedResult));
+        $this->orderItem->expects($this->any())->method('getProductOptions')->will($this->returnValue($options));
+
+        $this->assertEquals($unserializedResult, $this->model->getSelectionAttributes($this->orderItem));
     }
 
     public function testGetOrderOptions()
diff --git a/app/code/Magento/Bundle/Test/Unit/Block/Adminhtml/Sales/Order/View/Items/RendererTest.php b/app/code/Magento/Bundle/Test/Unit/Block/Adminhtml/Sales/Order/View/Items/RendererTest.php
index 72c4a40fbbb54f1ea43ddf6337ce7d17be5fc2df..a2802f5c39ac653da9eda0e3f1afa410dc3224ab 100644
--- a/app/code/Magento/Bundle/Test/Unit/Block/Adminhtml/Sales/Order/View/Items/RendererTest.php
+++ b/app/code/Magento/Bundle/Test/Unit/Block/Adminhtml/Sales/Order/View/Items/RendererTest.php
@@ -13,6 +13,9 @@ class RendererTest extends \PHPUnit_Framework_TestCase
     /** @var \Magento\Bundle\Block\Adminhtml\Sales\Order\View\Items\Renderer $model */
     protected $model;
 
+    /** @var \Magento\Framework\Serialize\Serializer\Json|\PHPUnit_Framework_MockObject_MockObject $serializer */
+    protected $serializer;
+
     protected function setUp()
     {
         $this->orderItem = $this->getMock(
@@ -22,10 +25,11 @@ class RendererTest extends \PHPUnit_Framework_TestCase
             '',
             false
         );
-
+        $this->serializer = $this->getMock(\Magento\Framework\Serialize\Serializer\Json::class);
         $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
         $this->model = $objectManager->getObject(
-            \Magento\Bundle\Block\Adminhtml\Sales\Order\View\Items\Renderer::class
+            \Magento\Bundle\Block\Adminhtml\Sales\Order\View\Items\Renderer::class,
+            ['serializer' => $this->serializer]
         );
     }
 
@@ -141,13 +145,25 @@ class RendererTest extends \PHPUnit_Framework_TestCase
         ];
     }
 
-    /**
-     * @dataProvider getSelectionAttributesDataProvider
-     */
-    public function testGetSelectionAttributes($productOptions, $result)
+    public function testGetSelectionAttributes()
     {
-        $this->orderItem->expects($this->any())->method('getProductOptions')->will($this->returnValue($productOptions));
-        $this->assertSame($result, $this->model->getSelectionAttributes($this->orderItem));
+        $this->orderItem->expects($this->any())->method('getProductOptions')->will($this->returnValue([]));
+        $this->assertNull($this->model->getSelectionAttributes($this->orderItem));
+    }
+
+    public function testGetSelectionAttributesWithBundle()
+    {
+        $bundleAttributes = 'Serialized value';
+        $options = ['bundle_selection_attributes' => $bundleAttributes];
+        $unserializedResult = 'result of "bundle_selection_attributes" unserialization';
+
+        $this->serializer->expects($this->any())
+            ->method('unserialize')
+            ->with($bundleAttributes)
+            ->will($this->returnValue($unserializedResult));
+
+        $this->orderItem->expects($this->any())->method('getProductOptions')->will($this->returnValue($options));
+        $this->assertEquals($unserializedResult, $this->model->getSelectionAttributes($this->orderItem));
     }
 
     public function getSelectionAttributesDataProvider()
diff --git a/app/code/Magento/Bundle/Test/Unit/Block/Sales/Order/Items/RendererTest.php b/app/code/Magento/Bundle/Test/Unit/Block/Sales/Order/Items/RendererTest.php
index d81908bd625068920715aa3c15416eb8409ffa29..1e2c0ed3b5df8804ee556b0969103eecf033dd22 100644
--- a/app/code/Magento/Bundle/Test/Unit/Block/Sales/Order/Items/RendererTest.php
+++ b/app/code/Magento/Bundle/Test/Unit/Block/Sales/Order/Items/RendererTest.php
@@ -13,6 +13,9 @@ class RendererTest extends \PHPUnit_Framework_TestCase
     /** @var \Magento\Bundle\Block\Sales\Order\Items\Renderer $model */
     protected $model;
 
+    /** @var \Magento\Framework\Serialize\Serializer\Json|\PHPUnit_Framework_MockObject_MockObject $serializer */
+    protected $serializer;
+
     protected function setUp()
     {
         $this->orderItem = $this->getMock(
@@ -23,8 +26,12 @@ class RendererTest extends \PHPUnit_Framework_TestCase
             false
         );
 
+        $this->serializer = $this->getMock(\Magento\Framework\Serialize\Serializer\Json::class);
         $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
-        $this->model = $objectManager->getObject(\Magento\Bundle\Block\Sales\Order\Items\Renderer::class);
+        $this->model = $objectManager->getObject(
+            \Magento\Bundle\Block\Sales\Order\Items\Renderer::class,
+            ['serializer' => $this->serializer]
+        );
     }
 
     /**
@@ -221,21 +228,25 @@ class RendererTest extends \PHPUnit_Framework_TestCase
         ];
     }
 
-    /**
-     * @dataProvider getSelectionAttributesDataProvider
-     */
-    public function testGetSelectionAttributes($productOptions, $result)
+    public function testGetSelectionAttributes()
     {
-        $this->orderItem->expects($this->any())->method('getProductOptions')->will($this->returnValue($productOptions));
-        $this->assertSame($result, $this->model->getSelectionAttributes($this->orderItem));
+        $this->orderItem->expects($this->any())->method('getProductOptions')->will($this->returnValue([]));
+        $this->assertNull($this->model->getSelectionAttributes($this->orderItem));
     }
 
-    public function getSelectionAttributesDataProvider()
+    public function testGetSelectionAttributesWithBundle()
     {
-        return [
-            [[], null],
-            [['bundle_selection_attributes' => 'a:1:{i:0;i:1;}'], [0 => 1]],
-        ];
+        $bundleAttributes = 'Serialized value';
+        $options = ['bundle_selection_attributes' => $bundleAttributes];
+        $unserializedResult = 'result of "bundle_selection_attributes" unserialization';
+
+        $this->serializer->expects($this->any())
+            ->method('unserialize')
+            ->with($bundleAttributes)
+            ->will($this->returnValue($unserializedResult));
+        $this->orderItem->expects($this->any())->method('getProductOptions')->will($this->returnValue($options));
+
+        $this->assertEquals($unserializedResult, $this->model->getSelectionAttributes($this->orderItem));
     }
 
     /**
diff --git a/app/code/Magento/Bundle/Test/Unit/Helper/Catalog/Product/ConfigurationTest.php b/app/code/Magento/Bundle/Test/Unit/Helper/Catalog/Product/ConfigurationTest.php
index 0919e95a9a09de549758c79a0f94eab871598a90..656d37c710ddda841f05a443ea82eb95a7e78db0 100644
--- a/app/code/Magento/Bundle/Test/Unit/Helper/Catalog/Product/ConfigurationTest.php
+++ b/app/code/Magento/Bundle/Test/Unit/Helper/Catalog/Product/ConfigurationTest.php
@@ -27,6 +27,11 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase
     /** @var \Magento\Catalog\Model\Product\Configuration\Item\ItemInterface|\PHPUnit_Framework_MockObject_MockObject */
     protected $item;
 
+    /**
+     * @var \Magento\Framework\Serialize\Serializer\Json
+     */
+    private $serializer;
+
     protected function setUp()
     {
         $this->pricingHelper = $this->getMock(
@@ -48,6 +53,16 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase
             \Magento\Catalog\Model\Product\Configuration\Item\ItemInterface::class,
             ['getQty', 'getProduct', 'getOptionByCode', 'getFileDownloadParams']
         );
+        $this->serializer = $this->getMockBuilder(\Magento\Framework\Serialize\Serializer\Json::class)
+            ->getMockForAbstractClass();
+
+        $this->serializer->expects($this->any())
+            ->method('unserialize')
+            ->willReturnCallback(
+                function ($value) {
+                    return json_decode($value, true);
+                }
+            );
 
         $this->helper = (new ObjectManager($this))->getObject(
             \Magento\Bundle\Helper\Catalog\Product\Configuration::class,
@@ -55,6 +70,7 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase
                 'pricingHelper' => $this->pricingHelper,
                 'productConfiguration' => $this->productConfiguration,
                 'escaper' => $this->escaper,
+                'serializer' => $this->serializer
             ]
         );
     }
@@ -127,8 +143,7 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase
 
     public function testGetBundleOptionsEmptyBundleSelectionIds()
     {
-        $optionIds = 'a:1:{i:0;i:1;}';
-
+        $optionIds = '{"0":"1"}';
         $collection = $this->getMock(\Magento\Bundle\Model\ResourceModel\Option\Collection::class, [], [], '', false);
         $product = $this->getMock(
             \Magento\Catalog\Model\Product::class,
@@ -152,7 +167,7 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase
 
         $selectionOption->expects($this->once())->method('getValue')->will($this->returnValue(''));
         $itemOption->expects($this->once())->method('getValue')->will($this->returnValue($optionIds));
-        $typeInstance->expects($this->once())->method('getOptionsByIds')->with(unserialize($optionIds), $product)
+        $typeInstance->expects($this->once())->method('getOptionsByIds')->with(json_decode($optionIds, true), $product)
             ->will($this->returnValue($collection));
         $product->expects($this->once())->method('getTypeInstance')->will($this->returnValue($typeInstance));
         $this->item->expects($this->once())->method('getProduct')->will($this->returnValue($product));
@@ -169,8 +184,8 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase
      */
     public function testGetOptions()
     {
-        $optionIds = 'a:1:{i:0;i:1;}';
-        $selectionIds = 'a:1:{i:0;s:1:"2";}';
+        $optionIds = '{"0":"1"}';
+        $selectionIds =  '{"0":"2"}';
         $selectionId = '2';
         $product = $this->getMock(
             \Magento\Catalog\Model\Product::class,
@@ -237,9 +252,11 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase
         $collection->expects($this->once())->method('appendSelections')->with($collection2, true)
             ->will($this->returnValue([$bundleOption]));
         $itemOption->expects($this->once())->method('getValue')->will($this->returnValue($optionIds));
-        $typeInstance->expects($this->once())->method('getOptionsByIds')->with(unserialize($optionIds), $product)
+        $typeInstance->expects($this->once())->method('getOptionsByIds')->with(json_decode($optionIds, true), $product)
             ->will($this->returnValue($collection));
-        $typeInstance->expects($this->once())->method('getSelectionsByIds')->with(unserialize($selectionIds), $product)
+        $typeInstance->expects($this->once())
+            ->method('getSelectionsByIds')
+            ->with(json_decode($selectionIds, true), $product)
             ->will($this->returnValue($collection2));
         $product->expects($this->once())->method('getTypeInstance')->will($this->returnValue($typeInstance));
         $product->expects($this->any())->method('getCustomOption')->with('selection_qty_' . $selectionId)
diff --git a/app/code/Magento/Bundle/Test/Unit/Model/Product/PriceTest.php b/app/code/Magento/Bundle/Test/Unit/Model/Product/PriceTest.php
index 10ca7335668470db793498273a998b64e34f4c4f..3dae21a30968d9061d7fbb6892b9aa146e0fae0d 100644
--- a/app/code/Magento/Bundle/Test/Unit/Model/Product/PriceTest.php
+++ b/app/code/Magento/Bundle/Test/Unit/Model/Product/PriceTest.php
@@ -64,6 +64,13 @@ class PriceTest extends \PHPUnit_Framework_TestCase
      */
     private $groupManagement;
 
+    /**
+     * Serializer interface instance.
+     *
+     * @var \Magento\Framework\Serialize\Serializer\Json
+     */
+    private $serializer;
+
     /**
      * Set up.
      *
@@ -97,6 +104,16 @@ class PriceTest extends \PHPUnit_Framework_TestCase
             false
         );
         $scopeConfig = $this->getMock(\Magento\Framework\App\Config\ScopeConfigInterface::class);
+        $this->serializer = $this->getMockBuilder(\Magento\Framework\Serialize\Serializer\Json::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->serializer->expects($this->any())
+            ->method('unserialize')
+            ->willReturnCallback(
+                function ($value) {
+                    return json_decode($value, true);
+                }
+            );
 
         $objectManagerHelper = new ObjectManagerHelper($this);
         $this->model = $objectManagerHelper->getObject(
@@ -111,7 +128,8 @@ class PriceTest extends \PHPUnit_Framework_TestCase
                 'groupManagement' => $this->groupManagement,
                 'tierPriceFactory' => $tpFactory,
                 'config' => $scopeConfig,
-                'catalogData' => $this->catalogHelperMock
+                'catalogData' => $this->catalogHelperMock,
+                'serializer' => $this->serializer
             ]
         );
     }
@@ -222,7 +240,7 @@ class PriceTest extends \PHPUnit_Framework_TestCase
     public function dataProviderWithEmptyOptions()
     {
         return [
-            ['a:0:{}'],
+            ['{}'],
             [''],
             [null],
         ];
@@ -268,8 +286,10 @@ class PriceTest extends \PHPUnit_Framework_TestCase
             ->method('getStoreId')
             ->willReturn($storeId);
 
-        $customOptionValue = 'a:1:{i:0;s:1:"1";}';
-        $dataObjectMock->expects($this->once())->method('getValue')->willReturn($customOptionValue);
+        $dataObjectMock->expects($this->once())
+            ->method('getValue')
+            ->willReturn('{"0":1}');
+
         $productTypeMock->expects($this->once())
             ->method('getSelectionsByIds')
             ->with([1], $productMock)
diff --git a/app/code/Magento/Bundle/Test/Unit/Model/Product/TypeTest.php b/app/code/Magento/Bundle/Test/Unit/Model/Product/TypeTest.php
index 2be68359909ef547a8f4b03a5d807aebfe509ed4..62036a33724449af8adda45b7c297fa7e2cd562e 100644
--- a/app/code/Magento/Bundle/Test/Unit/Model/Product/TypeTest.php
+++ b/app/code/Magento/Bundle/Test/Unit/Model/Product/TypeTest.php
@@ -9,6 +9,10 @@ use Magento\Bundle\Model\ResourceModel\Option\Collection;
 use Magento\Bundle\Model\ResourceModel\Selection\Collection as SelectionCollection;
 use Magento\Catalog\Model\Product\Option\Type\DefaultType;
 use Magento\Framework\Exception\LocalizedException;
+use Magento\Framework\DataObject;
+use Magento\Framework\Serialize\Serializer\Json;
+use Magento\Bundle\Model\Selection;
+use Magento\Catalog\Model\Product;
 
 /**
  * Class TypeTest
@@ -71,6 +75,11 @@ class TypeTest extends \PHPUnit_Framework_TestCase
      */
     private $priceCurrency;
 
+    /**
+     * @var Json
+     */
+    private $serializer;
+
     /**
      * @return void
      */
@@ -78,7 +87,19 @@ class TypeTest extends \PHPUnit_Framework_TestCase
     {
         $this->bundleCollection =
             $this->getMockBuilder(\Magento\Bundle\Model\ResourceModel\Selection\CollectionFactory::class)
-            ->setMethods(['create'])
+            ->setMethods(
+                [
+                    'create',
+                    'addAttributeToSelect',
+                    'setFlag',
+                    'setPositionOrder',
+                    'addStoreFilter',
+                    'setStoreId',
+                    'addFilterByRequiredOptions',
+                    'setOptionIdsFilter',
+                    'getItemById'
+                ]
+            )
             ->disableOriginalConstructor()
             ->getMock();
         $this->catalogData = $this->getMockBuilder(\Magento\Catalog\Helper\Data::class)
@@ -121,6 +142,12 @@ class TypeTest extends \PHPUnit_Framework_TestCase
         )
             ->disableOriginalConstructor()
             ->getMock();
+
+        $this->serializer = $this->getMockBuilder(Json::class)
+            ->setMethods(null)
+            ->disableOriginalConstructor()
+            ->getMock();
+
         $objectHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
         $this->model = $objectHelper->getObject(
             \Magento\Bundle\Model\Product\Type::class,
@@ -135,7 +162,7 @@ class TypeTest extends \PHPUnit_Framework_TestCase
                 'stockState' => $this->stockState,
                 'catalogProduct' => $this->catalogProduct,
                 'priceCurrency' => $this->priceCurrency,
-
+                'serializer' => $this->serializer
             ]
         );
     }
@@ -1535,7 +1562,7 @@ class TypeTest extends \PHPUnit_Framework_TestCase
         $sku = 'sku';
         $itemSku = 'item';
         $selectionIds = [1, 2, 3];
-        $serializeIds = serialize($selectionIds);
+        $serializeIds = json_encode($selectionIds);
         $productMock = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
             ->setMethods(['__wakeup', 'getData', 'hasCustomOptions', 'getCustomOption'])
             ->disableOriginalConstructor()
@@ -1612,7 +1639,7 @@ class TypeTest extends \PHPUnit_Framework_TestCase
     {
         $weight = 5;
         $selectionIds = [1, 2, 3];
-        $serializeIds = serialize($selectionIds);
+        $serializeIds = json_encode($selectionIds);
         $productMock = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
             ->setMethods(['__wakeup', 'getData', 'hasCustomOptions', 'getCustomOption'])
             ->disableOriginalConstructor()
@@ -1666,7 +1693,7 @@ class TypeTest extends \PHPUnit_Framework_TestCase
         $weight = 5;
         $qtyOption = 5;
         $selectionIds = [1, 2, 3];
-        $serializeIds = serialize($selectionIds);
+        $serializeIds = json_encode($selectionIds);
         $productMock = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
             ->setMethods(['__wakeup', 'getData', 'hasCustomOptions', 'getCustomOption'])
             ->disableOriginalConstructor()
@@ -1741,7 +1768,7 @@ class TypeTest extends \PHPUnit_Framework_TestCase
     public function testIsVirtual()
     {
         $selectionIds = [1, 2, 3];
-        $serializeIds = serialize($selectionIds);
+        $serializeIds = json_encode($selectionIds);
 
         $productMock = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
             ->disableOriginalConstructor()
@@ -2551,4 +2578,168 @@ class TypeTest extends \PHPUnit_Framework_TestCase
 
         $this->assertTrue($this->model->hasOptions($product));
     }
+
+    /**
+     * Bundle product without options should not be possible to buy.
+     *
+     * @expectedException \Magento\Framework\Exception\LocalizedException
+     * @expectedExceptionMessage Please specify product option
+     */
+    public function testCheckProductBuyStateEmptyOptionsException()
+    {
+        $this->mockBundleCollection();
+        $product = $this->getProductMock();
+        $product->method('getCustomOption')->willReturnMap([
+            ['bundle_selection_ids', new DataObject(['value' => ''])],
+            ['info_buyRequest', new DataObject(['value' => json_encode(['bundle_option' => ''])])],
+        ]);
+        $product->setCustomOption(json_encode([]));
+
+        $this->model->checkProductBuyState($product);
+    }
+
+    /**
+     * Previously selected options are not more available for buying.
+     *
+     * @param object $element
+     * @param string $expectedMessage
+     * @param bool $check
+     *
+     * @throws LocalizedException
+     *
+     * @expectedException \Magento\Framework\Exception\LocalizedException
+     * @dataProvider notAvailableOptionProvider
+     */
+    public function testCheckProductBuyStateMissedOptionException($element, $expectedMessage, $check)
+    {
+        $this->mockBundleCollection();
+        $product = $this->getProductMock();
+        $product->method('getCustomOption')->willReturnMap([
+            ['bundle_selection_ids', new DataObject(['value' => json_encode([1])])],
+            ['info_buyRequest', new DataObject(['value' => json_encode(['bundle_option' => [1]])])],
+        ]);
+        $product->setCustomOption(json_encode([]));
+
+        $this->bundleCollection->method('getItemById')->willReturn($element);
+        $this->catalogProduct->setSkipSaleableCheck($check);
+
+        try {
+            $this->model->checkProductBuyState($product);
+        } catch (LocalizedException $e) {
+            $this->assertContains(
+                $expectedMessage,
+                $e->getMessage()
+            );
+            throw $e;
+        }
+    }
+
+    /**
+     * In case of missed selection for required options, bundle product should be not able to buy.
+     *
+     * @expectedException \Magento\Framework\Exception\LocalizedException
+     */
+    public function testCheckProductBuyStateRequiredOptionException()
+    {
+        $this->mockBundleCollection();
+        $product = $this->getProductMock();
+        $product->method('getCustomOption')->willReturnMap([
+            ['bundle_selection_ids', new DataObject(['value' => json_encode([])])],
+            ['info_buyRequest', new DataObject(['value' => json_encode(['bundle_option' => [1]])])],
+        ]);
+        $product->setCustomOption(json_encode([]));
+
+        $falseSelection = $this->getMockBuilder(Selection::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['isSalable'])
+            ->getMock();
+        $falseSelection->method('isSalable')->willReturn(false);
+
+        $this->bundleCollection->method('getItemById')->willReturn($falseSelection);
+        $this->catalogProduct->setSkipSaleableCheck(false);
+
+        try {
+            $this->model->checkProductBuyState($product);
+        } catch (LocalizedException $e) {
+            $this->assertContains(
+                'Please select all required options',
+                $e->getMessage()
+            );
+
+            throw $e;
+        }
+    }
+
+    /**
+     * Prepare product mock for testing.
+     *
+     * @return \PHPUnit_Framework_MockObject_MockObject
+     */
+    public function getProductMock()
+    {
+        $product = $this->getMockBuilder(Product::class)
+            ->disableOriginalConstructor()
+            ->setMethods([
+                '_wakeup',
+                'getHasOptions',
+                'getId',
+                'getStoreId',
+                'getCustomOption',
+                'getTypeInstance',
+                'setStoreFilter',
+            ])
+            ->getMock();
+        $product->method('getTypeInstance')->willReturn($product);
+        $product->method('setStoreFilter')->willReturn($product);
+        $optionCollectionCache = new DataObject();
+        $optionCollectionCache->setAllIds([]);
+        $optionCollectionCache->setItems([
+            new DataObject([
+                'required' => true,
+                'id' => 1
+            ]),
+        ]);
+        $product->setData('_cache_instance_options_collection', $optionCollectionCache);
+        return $product;
+    }
+
+    /**
+     * Preparation mocks for checkProductsBuyState.
+     */
+    public function mockBundleCollection()
+    {
+        $this->bundleCollection->method('create')->willReturn($this->bundleCollection);
+        $this->bundleCollection->method('addAttributeToSelect')->willReturn($this->bundleCollection);
+        $this->bundleCollection->method('setFlag')->willReturn($this->bundleCollection);
+        $this->bundleCollection->method('setPositionOrder')->willReturn($this->bundleCollection);
+        $this->bundleCollection->method('addStoreFilter')->willReturn($this->bundleCollection);
+        $this->bundleCollection->method('setStoreId')->willReturn($this->bundleCollection);
+        $this->bundleCollection->method('addFilterByRequiredOptions')->willReturn($this->bundleCollection);
+        $this->bundleCollection->method('setOptionIdsFilter')->willReturn($this->bundleCollection);
+    }
+
+    /**
+     * Data provider for not available option.
+     * @return array
+     */
+    public function notAvailableOptionProvider()
+    {
+        $falseSelection = $this->getMockBuilder(Selection::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['isSalable'])
+            ->getMock();
+        $falseSelection->method('isSalable')->willReturn(false);
+        return [
+            [
+                false,
+                'The required options you selected are not available',
+                false,
+            ],
+            [
+                $falseSelection,
+                'The required options you selected are not available',
+                false
+            ],
+        ];
+    }
 }
diff --git a/app/code/Magento/Bundle/Test/Unit/Model/Sales/Order/Pdf/Items/AbstractItemsTest.php b/app/code/Magento/Bundle/Test/Unit/Model/Sales/Order/Pdf/Items/AbstractItemsTest.php
index 83c38d8d9ad32bfb077b0f626122992cc05a0c1a..b74deab061f245ebaf7ab24332db95ab0dff4671 100644
--- a/app/code/Magento/Bundle/Test/Unit/Model/Sales/Order/Pdf/Items/AbstractItemsTest.php
+++ b/app/code/Magento/Bundle/Test/Unit/Model/Sales/Order/Pdf/Items/AbstractItemsTest.php
@@ -13,6 +13,9 @@ class AbstractItemsTest extends \PHPUnit_Framework_TestCase
     /** @var \Magento\Bundle\Model\Sales\Order\Pdf\Items\Shipment $model */
     protected $model;
 
+    /** @var \Magento\Framework\Serialize\Serializer\Json $serializer */
+    protected $serializer;
+
     protected function setUp()
     {
         $this->orderItem = $this->getMock(
@@ -24,7 +27,13 @@ class AbstractItemsTest extends \PHPUnit_Framework_TestCase
         );
 
         $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
-        $this->model = $objectManager->getObject(\Magento\Bundle\Model\Sales\Order\Pdf\Items\Shipment::class);
+        $this->serializer = $this->getMock(\Magento\Framework\Serialize\Serializer\Json::class);
+        $this->model = $objectManager->getObject(
+            \Magento\Bundle\Model\Sales\Order\Pdf\Items\Shipment::class,
+            [
+                'serializer' => $this->serializer
+            ]
+        );
     }
 
     /**
@@ -234,21 +243,25 @@ class AbstractItemsTest extends \PHPUnit_Framework_TestCase
         ];
     }
 
-    /**
-     * @dataProvider getSelectionAttributesDataProvider
-     */
-    public function testGetSelectionAttributes($productOptions, $result)
+    public function testGetSelectionAttributes()
     {
-        $this->orderItem->expects($this->any())->method('getProductOptions')->will($this->returnValue($productOptions));
-        $this->assertSame($result, $this->model->getSelectionAttributes($this->orderItem));
+        $this->orderItem->expects($this->any())->method('getProductOptions')->will($this->returnValue([]));
+        $this->assertNull($this->model->getSelectionAttributes($this->orderItem));
     }
 
-    public function getSelectionAttributesDataProvider()
+    public function testGetSelectionAttributesWithBundle()
     {
-        return [
-            [[], null],
-            [['bundle_selection_attributes' => 'a:1:{i:0;i:1;}'], [0 => 1]],
-        ];
+        $bundleAttributes = 'Serialized value';
+        $options = ['bundle_selection_attributes' => $bundleAttributes];
+        $unserializedResult = 'result of "bundle_selection_attributes" unserialization';
+
+        $this->serializer->expects($this->any())
+            ->method('unserialize')
+            ->with($bundleAttributes)
+            ->will($this->returnValue($unserializedResult));
+        $this->orderItem->expects($this->any())->method('getProductOptions')->will($this->returnValue($options));
+
+        $this->assertEquals($unserializedResult, $this->model->getSelectionAttributes($this->orderItem));
     }
 
     public function testGetOrderOptions()
diff --git a/app/code/Magento/Catalog/Helper/Product/Configuration.php b/app/code/Magento/Catalog/Helper/Product/Configuration.php
index eb9e84afa8402ace13d612a20fd74d7f4b302e80..2e8290a1ed2adebe96c06250c29d9c3c0238a657 100644
--- a/app/code/Magento/Catalog/Helper/Product/Configuration.php
+++ b/app/code/Magento/Catalog/Helper/Product/Configuration.php
@@ -5,6 +5,8 @@
  */
 namespace Magento\Catalog\Helper\Product;
 
+use Magento\Framework\App\ObjectManager;
+use Magento\Framework\Serialize\Serializer\Json;
 use Magento\Catalog\Helper\Product\Configuration\ConfigurationInterface;
 use Magento\Framework\App\Helper\AbstractHelper;
 
@@ -36,21 +38,29 @@ class Configuration extends AbstractHelper implements ConfigurationInterface
      */
     protected $string;
 
+    /**
+     * @var Json
+     */
+    private $serializer;
+
     /**
      * @param \Magento\Framework\App\Helper\Context $context
      * @param \Magento\Catalog\Model\Product\OptionFactory $productOptionFactory
      * @param \Magento\Framework\Filter\FilterManager $filter
      * @param \Magento\Framework\Stdlib\StringUtils $string
+     * @param Json $serializer
      */
     public function __construct(
         \Magento\Framework\App\Helper\Context $context,
         \Magento\Catalog\Model\Product\OptionFactory $productOptionFactory,
         \Magento\Framework\Filter\FilterManager $filter,
-        \Magento\Framework\Stdlib\StringUtils $string
+        \Magento\Framework\Stdlib\StringUtils $string,
+        Json $serializer = null
     ) {
         $this->_productOptionFactory = $productOptionFactory;
         $this->filter = $filter;
         $this->string = $string;
+        $this->serializer = $serializer ?: ObjectManager::getInstance()->get(Json::class);
         parent::__construct($context);
     }
 
@@ -105,7 +115,7 @@ class Configuration extends AbstractHelper implements ConfigurationInterface
 
         $addOptions = $item->getOptionByCode('additional_options');
         if ($addOptions) {
-            $options = array_merge($options, unserialize($addOptions->getValue()));
+            $options = array_merge($options, $this->serializer->unserialize($addOptions->getValue()));
         }
 
         return $options;
diff --git a/app/code/Magento/Catalog/Model/CustomOptions/CustomOptionProcessor.php b/app/code/Magento/Catalog/Model/CustomOptions/CustomOptionProcessor.php
index 5b55f9cb66cfeffae4e468bd98131dd723b1f2be..7fe7147d1d2724e30452cd6de1c0bd46def267e5 100644
--- a/app/code/Magento/Catalog/Model/CustomOptions/CustomOptionProcessor.php
+++ b/app/code/Magento/Catalog/Model/CustomOptions/CustomOptionProcessor.php
@@ -28,22 +28,33 @@ class CustomOptionProcessor implements CartItemProcessorInterface
     /** @var \Magento\Catalog\Model\Product\Option\UrlBuilder */
     private $urlBuilder;
 
+    /**
+     * Serializer interface instance.
+     *
+     * @var \Magento\Framework\Serialize\Serializer\Json
+     */
+    private $serializer;
+
     /**
      * @param DataObject\Factory $objectFactory
      * @param ProductOptionFactory $productOptionFactory
      * @param ProductOptionExtensionFactory $extensionFactory
      * @param CustomOptionFactory $customOptionFactory
+     * @param \Magento\Framework\Serialize\Serializer\Json|null $serializer
      */
     public function __construct(
         \Magento\Framework\DataObject\Factory $objectFactory,
         \Magento\Quote\Model\Quote\ProductOptionFactory $productOptionFactory,
         \Magento\Quote\Api\Data\ProductOptionExtensionFactory $extensionFactory,
-        \Magento\Catalog\Model\CustomOptions\CustomOptionFactory $customOptionFactory
+        \Magento\Catalog\Model\CustomOptions\CustomOptionFactory $customOptionFactory,
+        \Magento\Framework\Serialize\Serializer\Json $serializer = null
     ) {
         $this->objectFactory = $objectFactory;
         $this->productOptionFactory = $productOptionFactory;
         $this->extensionFactory = $extensionFactory;
         $this->customOptionFactory = $customOptionFactory;
+        $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance()
+            ->get(\Magento\Framework\Serialize\Serializer\Json::class);
     }
 
     /**
@@ -99,7 +110,7 @@ class CustomOptionProcessor implements CartItemProcessorInterface
     protected function getOptions(CartItemInterface $cartItem)
     {
         $buyRequest = !empty($cartItem->getOptionByCode('info_buyRequest'))
-            ? unserialize($cartItem->getOptionByCode('info_buyRequest')->getValue())
+            ? $this->serializer->unserialize($cartItem->getOptionByCode('info_buyRequest')->getValue())
             : null;
         return is_array($buyRequest) && isset($buyRequest['options'])
             ? $buyRequest['options']
diff --git a/app/code/Magento/Catalog/Model/Product/Option/Type/Date.php b/app/code/Magento/Catalog/Model/Product/Option/Type/Date.php
index afa44c42d87b8e6351b8334e60fc49ebd87ca5b2..3d121cbc741c3000f42560efae0c361f11745c29 100644
--- a/app/code/Magento/Catalog/Model/Product/Option/Type/Date.php
+++ b/app/code/Magento/Catalog/Model/Product/Option/Type/Date.php
@@ -22,19 +22,30 @@ class Date extends \Magento\Catalog\Model\Product\Option\Type\DefaultType
      */
     protected $_localeDate;
 
+    /**
+     * Serializer interface instance.
+     *
+     * @var \Magento\Framework\Serialize\Serializer\Json
+     */
+    private $serializer;
+
     /**
      * @param \Magento\Checkout\Model\Session $checkoutSession
      * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
      * @param \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate
      * @param array $data
+     * @param \Magento\Framework\Serialize\Serializer\Json|null $serializer
      */
     public function __construct(
         \Magento\Checkout\Model\Session $checkoutSession,
         \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
         \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate,
-        array $data = []
+        array $data = [],
+        \Magento\Framework\Serialize\Serializer\Json $serializer = null
     ) {
         $this->_localeDate = $localeDate;
+        $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance()
+            ->get(\Magento\Framework\Serialize\Serializer\Json::class);
         parent::__construct($checkoutSession, $scopeConfig, $data);
     }
 
@@ -269,7 +280,7 @@ class Date extends \Magento\Catalog\Model\Product\Option\Type\DefaultType
         $confItem = $this->getConfigurationItem();
         $infoBuyRequest = $confItem->getOptionByCode('info_buyRequest');
         try {
-            $value = unserialize($infoBuyRequest->getValue());
+            $value = $this->serializer->unserialize($infoBuyRequest->getValue());
             if (is_array($value) && isset($value['options']) && isset($value['options'][$this->getOption()->getId()])
             ) {
                 return $value['options'][$this->getOption()->getId()];
diff --git a/app/code/Magento/Catalog/Model/Product/Option/Type/File.php b/app/code/Magento/Catalog/Model/Product/Option/Type/File.php
index 70c20a4e314903ce9defb0e40f50c912a83d7307..865e57f9b71f0b42617da27e698bf2c8f0e6a627 100644
--- a/app/code/Magento/Catalog/Model/Product/Option/Type/File.php
+++ b/app/code/Magento/Catalog/Model/Product/Option/Type/File.php
@@ -9,6 +9,8 @@ use Magento\Framework\App\Filesystem\DirectoryList;
 use Magento\Framework\Filesystem;
 use Magento\Framework\Exception\LocalizedException;
 use Magento\Catalog\Model\Product\Exception as ProductException;
+use Magento\Framework\Serialize\Serializer\Json;
+use Magento\Framework\App\ObjectManager;
 
 /**
  * Catalog product option file type
@@ -70,6 +72,11 @@ class File extends \Magento\Catalog\Model\Product\Option\Type\DefaultType
      */
     protected $validatorFile;
 
+    /**
+     * @var Json
+     */
+    private $serializer;
+
     /**
      * @var Filesystem
      */
@@ -86,6 +93,7 @@ class File extends \Magento\Catalog\Model\Product\Option\Type\DefaultType
      * @param \Magento\Framework\Escaper $escaper
      * @param array $data
      * @param Filesystem $filesystem
+     * @param Json|null $serializer
      * @SuppressWarnings(PHPMD.ExcessiveParameterList)
      */
     public function __construct(
@@ -98,7 +106,8 @@ class File extends \Magento\Catalog\Model\Product\Option\Type\DefaultType
         \Magento\Catalog\Model\Product\Option\UrlBuilder $urlBuilder,
         \Magento\Framework\Escaper $escaper,
         array $data = [],
-        Filesystem $filesystem = null
+        Filesystem $filesystem = null,
+        Json $serializer = null
     ) {
         $this->_itemOptionFactory = $itemOptionFactory;
         $this->_urlBuilder = $urlBuilder;
@@ -108,6 +117,7 @@ class File extends \Magento\Catalog\Model\Product\Option\Type\DefaultType
         $this->_rootDirectory = $this->filesystem->getDirectoryRead(DirectoryList::MEDIA);
         $this->validatorInfo = $validatorInfo;
         $this->validatorFile = $validatorFile;
+        $this->serializer = $serializer ? $serializer : ObjectManager::getInstance()->get(Json::class);
         parent::__construct($checkoutSession, $scopeConfig, $data);
     }
 
@@ -275,7 +285,7 @@ class File extends \Magento\Catalog\Model\Product\Option\Type\DefaultType
 
             // Save option in request, because we have no $_FILES['options']
             $requestOptions[$this->getOption()->getId()] = $value;
-            $result = serialize($value);
+            $result = $this->serializer->serialize($value);
         } else {
             /*
              * Clear option info from request, so it won't be stored in our db upon
@@ -306,7 +316,7 @@ class File extends \Magento\Catalog\Model\Product\Option\Type\DefaultType
     {
         if ($this->_formattedOptionValue === null) {
             try {
-                $value = unserialize($optionValue);
+                $value = $this->serializer->unserialize($optionValue);
 
                 $customOptionUrlParams = $this->getCustomOptionUrlParams() ? $this->getCustomOptionUrlParams() : [
                     'id' => $this->getConfigurationItemOption()->getId(),
@@ -316,7 +326,7 @@ class File extends \Magento\Catalog\Model\Product\Option\Type\DefaultType
                 $value['url'] = ['route' => $this->_customOptionDownloadUrl, 'params' => $customOptionUrlParams];
 
                 $this->_formattedOptionValue = $this->_getOptionHtml($value);
-                $this->getConfigurationItemOption()->setValue(serialize($value));
+                $this->getConfigurationItemOption()->setValue($this->serializer->serialize($value));
                 return $this->_formattedOptionValue;
             } catch (\Exception $e) {
                 return $optionValue;
@@ -364,7 +374,7 @@ class File extends \Magento\Catalog\Model\Product\Option\Type\DefaultType
         if (is_array($value)) {
             return $value;
         } elseif (is_string($value) && !empty($value)) {
-            return unserialize($value);
+            return $this->serializer->unserialize($value);
         } else {
             return [];
         }
@@ -386,11 +396,13 @@ class File extends \Magento\Catalog\Model\Product\Option\Type\DefaultType
      *
      * @param string $optionValue Prepared for cart option value
      * @return string
+     *
+     * @deprecated
      */
     public function getEditableOptionValue($optionValue)
     {
         try {
-            $value = unserialize($optionValue);
+            $value = $this->serializer->unserialize($optionValue);
             return sprintf(
                 '%s [%d]',
                 $this->_escaper->escapeHtml($value['title']),
@@ -409,6 +421,8 @@ class File extends \Magento\Catalog\Model\Product\Option\Type\DefaultType
      * @return string|null
      *
      * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     *
+     * @deprecated
      */
     public function parseOptionValue($optionValue, $productOptionValues)
     {
@@ -417,7 +431,7 @@ class File extends \Magento\Catalog\Model\Product\Option\Type\DefaultType
             $confItemOptionId = $matches[1];
             $option = $this->_itemOptionFactory->create()->load($confItemOptionId);
             try {
-                unserialize($option->getValue());
+                $this->serializer->unserialize($option->getValue());
                 return $option->getValue();
             } catch (\Exception $e) {
                 return null;
@@ -436,7 +450,7 @@ class File extends \Magento\Catalog\Model\Product\Option\Type\DefaultType
     public function prepareOptionValueForRequest($optionValue)
     {
         try {
-            $result = unserialize($optionValue);
+            $result = $this->serializer->unserialize($optionValue);
             return $result;
         } catch (\Exception $e) {
             return null;
@@ -452,7 +466,7 @@ class File extends \Magento\Catalog\Model\Product\Option\Type\DefaultType
     {
         $quoteOption = $this->getConfigurationItemOption();
         try {
-            $value = unserialize($quoteOption->getValue());
+            $value = $this->serializer->unserialize($quoteOption->getValue());
             if (!isset($value['quote_path'])) {
                 throw new \Exception();
             }
diff --git a/app/code/Magento/Catalog/Model/Product/Type/AbstractType.php b/app/code/Magento/Catalog/Model/Product/Type/AbstractType.php
index 11b8d03fc7ee5cc23dd627e65ad9651a5b243b7d..8745903acc4a8256e3232b8f94070eaeeac143a6 100644
--- a/app/code/Magento/Catalog/Model/Product/Type/AbstractType.php
+++ b/app/code/Magento/Catalog/Model/Product/Type/AbstractType.php
@@ -161,6 +161,13 @@ abstract class AbstractType
      */
     protected $productRepository;
 
+    /**
+     * Serializer interface instance.
+     *
+     * @var \Magento\Framework\Serialize\Serializer\Json
+     */
+    protected $serializer;
+
     /**
      * Construct
      *
@@ -173,6 +180,7 @@ abstract class AbstractType
      * @param \Magento\Framework\Registry $coreRegistry
      * @param \Psr\Log\LoggerInterface $logger
      * @param ProductRepositoryInterface $productRepository
+     * @param \Magento\Framework\Serialize\Serializer\Json|null $serializer
      * @SuppressWarnings(PHPMD.ExcessiveParameterList)
      */
     public function __construct(
@@ -184,7 +192,8 @@ abstract class AbstractType
         \Magento\Framework\Filesystem $filesystem,
         \Magento\Framework\Registry $coreRegistry,
         \Psr\Log\LoggerInterface $logger,
-        ProductRepositoryInterface $productRepository
+        ProductRepositoryInterface $productRepository,
+        \Magento\Framework\Serialize\Serializer\Json $serializer = null
     ) {
         $this->_catalogProductOption = $catalogProductOption;
         $this->_eavConfig = $eavConfig;
@@ -195,6 +204,8 @@ abstract class AbstractType
         $this->_filesystem = $filesystem;
         $this->_logger = $logger;
         $this->productRepository = $productRepository;
+        $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance()
+            ->get(\Magento\Framework\Serialize\Serializer\Json::class);
     }
 
     /**
@@ -394,8 +405,7 @@ abstract class AbstractType
         $product->prepareCustomOptions();
         $buyRequest->unsetData('_processing_params');
         // One-time params only
-        $product->addCustomOption('info_buyRequest', serialize($buyRequest->getData()));
-
+        $product->addCustomOption('info_buyRequest', $this->serializer->serialize($buyRequest->getData()));
         if ($options) {
             $optionIds = array_keys($options);
             $product->addCustomOption('option_ids', implode(',', $optionIds));
@@ -645,7 +655,7 @@ abstract class AbstractType
         $optionArr = [];
         $info = $product->getCustomOption('info_buyRequest');
         if ($info) {
-            $optionArr['info_buyRequest'] = unserialize($info->getValue());
+            $optionArr['info_buyRequest'] = $this->serializer->unserialize($info->getValue());
         }
 
         $optionIds = $product->getCustomOption('option_ids');
diff --git a/app/code/Magento/Catalog/Test/Unit/Helper/Product/ConfigurationTest.php b/app/code/Magento/Catalog/Test/Unit/Helper/Product/ConfigurationTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..902f63c578ab66b96361779ee01928a4f9dbada4
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Unit/Helper/Product/ConfigurationTest.php
@@ -0,0 +1,81 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Catalog\Test\Unit\Helper\Product;
+
+class ConfigurationTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Framework\Serialize\Serializer\Json|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $serializer;
+
+    /**
+     * @var \Magento\Catalog\Helper\Product\Configuration
+     */
+    protected $helper;
+
+    protected function setUp()
+    {
+        $contextMock = $this->getMock(\Magento\Framework\App\Helper\Context::class, [], [], '', false);
+        $optionFactoryMock = $this->getMock(\Magento\Catalog\Model\Product\OptionFactory::class, [], [], '', false);
+        $filterManagerMock = $this->getMock(\Magento\Framework\Filter\FilterManager::class, [], [], '', false);
+        $stringUtilsMock = $this->getMock(\Magento\Framework\Stdlib\StringUtils::class, [], [], '', false);
+        $this->serializer = $this->getMock(\Magento\Framework\Serialize\Serializer\Json::class, [], [], '', false);
+
+        $this->helper = new \Magento\Catalog\Helper\Product\Configuration(
+            $contextMock,
+            $optionFactoryMock,
+            $filterManagerMock,
+            $stringUtilsMock,
+            $this->serializer
+        );
+    }
+
+    /**
+     * Retrieves product additional options
+     */
+    public function testGetAdditionalOptionOnly()
+    {
+        $additionalOptionResult = ['additional_option' => 1];
+
+        $itemMock = $this->getMock(
+            \Magento\Catalog\Model\Product\Configuration\Item\ItemInterface::class,
+            [],
+            [],
+            '',
+            false
+        );
+        $optionMock = $this->getMock(
+            \Magento\Catalog\Model\Product\Configuration\Item\Option\OptionInterface::class,
+            [],
+            [],
+            '',
+            false
+        );
+        $additionalOptionMock = $this->getMock(
+            \Magento\Catalog\Model\Product\Configuration\Item\Option\OptionInterface::class,
+            [],
+            [],
+            '',
+            false
+        );
+        $productMock = $this->getMock(\Magento\Catalog\Model\Product::class, [], [], '', false);
+
+        $this->serializer->expects($this->once())->method('unserialize')->willReturn($additionalOptionResult);
+        $optionMock->expects($this->once())->method('getValue')->willReturn(null);
+        $additionalOptionMock->expects($this->once())->method('getValue');
+
+        $itemMock->expects($this->once())->method('getProduct')->willReturn($productMock);
+        $itemMock->expects($this->any())->method('getOptionByCode')->will($this->returnValueMap(
+            [
+                ['option_ids', $optionMock],
+                ['additional_options', $additionalOptionMock]
+            ]
+        ));
+
+        $this->assertEquals($additionalOptionResult, $this->helper->getCustomOptions($itemMock));
+    }
+}
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/CustomOptions/CustomOptionProcessorTest.php b/app/code/Magento/Catalog/Test/Unit/Model/CustomOptions/CustomOptionProcessorTest.php
index e3bdffbf5aefc74c881a14fa72970c0056d760ed..5e8e8bde253ae5c1f75005b63105b3937459afcb 100644
--- a/app/code/Magento/Catalog/Test/Unit/Model/CustomOptions/CustomOptionProcessorTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Model/CustomOptions/CustomOptionProcessorTest.php
@@ -51,6 +51,9 @@ class CustomOptionProcessorTest extends \PHPUnit_Framework_TestCase
     /** @var CustomOptionProcessor */
     protected $processor;
 
+    /** @var \Magento\Framework\Serialize\Serializer\Json */
+    private $serializer;
+
     protected function setUp()
     {
         $this->objectFactory = $this->getMockBuilder(\Magento\Framework\DataObject\Factory::class)
@@ -90,12 +93,16 @@ class CustomOptionProcessorTest extends \PHPUnit_Framework_TestCase
         $this->buyRequest = $this->getMockBuilder(\Magento\Framework\DataObject::class)
             ->disableOriginalConstructor()
             ->getMock();
+        $this->serializer = $this->getMockBuilder(\Magento\Framework\Serialize\Serializer\Json::class)
+            ->setMethods(['unserialize'])
+            ->getMockForAbstractClass();
 
         $this->processor = new CustomOptionProcessor(
             $this->objectFactory,
             $this->productOptionFactory,
             $this->extensionFactory,
-            $this->customOptionFactory
+            $this->customOptionFactory,
+            $this->serializer
         );
 
     }
@@ -126,6 +133,9 @@ class CustomOptionProcessorTest extends \PHPUnit_Framework_TestCase
         $this->assertSame($this->buyRequest, $this->processor->convertToBuyRequest($this->cartItem));
     }
 
+    /**
+     * @covers \Magento\Catalog\Model\CustomOptions\CustomOptionProcessor::getOptions()
+     */
     public function testProcessCustomOptions()
     {
         $optionId = 23;
@@ -136,9 +146,12 @@ class CustomOptionProcessorTest extends \PHPUnit_Framework_TestCase
             ->method('getOptionByCode')
             ->with('info_buyRequest')
             ->willReturn($quoteItemOption);
-        $quoteItemOption->expects($this->once())
+        $quoteItemOption->expects($this->any())
             ->method('getValue')
-            ->willReturn('a:1:{s:7:"options";a:1:{i:' . $optionId . ';a:2:{i:0;s:1:"5";i:1;s:1:"6";}}} ');
+            ->willReturn('{"options":{"' . $optionId . '":["5","6"]}}');
+        $this->serializer->expects($this->any())
+            ->method('unserialize')
+            ->willReturn(json_decode($quoteItemOption->getValue(), true));
         $this->customOptionFactory->expects($this->once())
             ->method('create')
             ->willReturn($this->customOption);
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/Option/Type/FileTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/Option/Type/FileTest.php
index 6682b295476325f2df099faa183d5edb451cadb5..5584f63a2ddf80d047bfe0329f3916523498b75d 100644
--- a/app/code/Magento/Catalog/Test/Unit/Model/Product/Option/Type/FileTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/Option/Type/FileTest.php
@@ -11,6 +11,11 @@ use Magento\Framework\Filesystem;
 use Magento\Framework\Filesystem\Directory\ReadInterface;
 use Magento\Framework\Filesystem\DriverPool;
 
+/**
+ * Class FileTest.
+ *
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
 class FileTest extends \PHPUnit_Framework_TestCase
 {
     /**
@@ -33,6 +38,21 @@ class FileTest extends \PHPUnit_Framework_TestCase
      */
     private $filesystemMock;
 
+    /**
+     * @var \Magento\Framework\Serialize\Serializer\Json|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $serializer;
+
+    /**
+     * @var \Magento\Catalog\Model\Product\Option\UrlBuilder|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $urlBuilder;
+
+    /**
+     * @var \Magento\Framework\Escaper|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $escaper;
+
     protected function setUp()
     {
         $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
@@ -44,11 +64,23 @@ class FileTest extends \PHPUnit_Framework_TestCase
         $this->rootDirectory = $this->getMockBuilder(ReadInterface::class)
             ->getMock();
 
-        $this->filesystemMock->expects($this->once())
+        $this->filesystemMock->expects($this->any())
             ->method('getDirectoryRead')
             ->with(DirectoryList::MEDIA, DriverPool::FILE)
             ->willReturn($this->rootDirectory);
 
+        $this->serializer = $this->getMockBuilder(\Magento\Framework\Serialize\Serializer\Json::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->urlBuilder = $this->getMockBuilder(\Magento\Catalog\Model\Product\Option\UrlBuilder::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->escaper = $this->getMockBuilder(\Magento\Framework\Escaper::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
         $this->coreFileStorageDatabase = $this->getMock(
             \Magento\MediaStorage\Helper\File\Storage\Database::class,
             ['copyFile'],
@@ -67,11 +99,40 @@ class FileTest extends \PHPUnit_Framework_TestCase
             \Magento\Catalog\Model\Product\Option\Type\File::class,
             [
                 'filesystem' => $this->filesystemMock,
-                'coreFileStorageDatabase' => $this->coreFileStorageDatabase
+                'coreFileStorageDatabase' => $this->coreFileStorageDatabase,
+                'serializer' => $this->serializer,
+                'urlBuilder' => $this->urlBuilder,
+                'escaper' => $this->escaper
             ]
         );
     }
 
+    public function testGetCustomizedView()
+    {
+        $fileObject = $this->getFileObject();
+        $optionInfo = ['option_value' => 'some serialized data'];
+
+        $dataAfterSerialize = ['some' => 'array'];
+
+        $this->serializer->expects($this->once())
+            ->method('unserialize')
+            ->with('some serialized data')
+            ->willReturn($dataAfterSerialize);
+
+        $this->urlBuilder->expects($this->once())
+            ->method('getUrl')
+            ->willReturn('someUrl');
+
+        $this->escaper->expects($this->once())
+            ->method('escapeHtml')
+            ->willReturn('string');
+
+        $this->assertEquals(
+            '<a href="someUrl" target="_blank">string</a> ',
+            $fileObject->getCustomizedView($optionInfo)
+        );
+    }
+
     public function testCopyQuoteToOrder()
     {
         $optionMock = $this->getMockBuilder(OptionInterface::class)
@@ -82,11 +143,22 @@ class FileTest extends \PHPUnit_Framework_TestCase
         $quotePath = '/quote/path/path/uploaded.file';
         $orderPath = '/order/path/path/uploaded.file';
 
+        $quoteValue = "{\"quote_path\":\"$quotePath\",\"order_path\":\"$orderPath\"}";
+
+        $this->serializer->expects($this->once())
+            ->method('unserialize')
+            ->with($quoteValue)
+            ->willReturnCallback(
+                function ($value) {
+                    return json_decode($value, true);
+                }
+            );
+
         $optionMock->expects($this->any())
             ->method('getValue')
-            ->will($this->returnValue(serialize(['quote_path' => $quotePath, 'order_path' => $orderPath])));
+            ->will($this->returnValue($quoteValue));
 
-        $this->rootDirectory->expects($this->once())
+        $this->rootDirectory->expects($this->any())
             ->method('isFile')
             ->with($this->equalTo($quotePath))
             ->will($this->returnValue(true));
@@ -112,4 +184,55 @@ class FileTest extends \PHPUnit_Framework_TestCase
             $fileObject->copyQuoteToOrder()
         );
     }
+
+    public function testGetFormattedOptionValue()
+    {
+        $resultValue = ['result'];
+        $optionValue = json_encode($resultValue);
+        $urlParameter = 'parameter';
+
+        $fileObject = $this->getFileObject();
+        $fileObject->setCustomOptionUrlParams($urlParameter);
+        $this->serializer->expects($this->once())
+            ->method('unserialize')
+            ->with($optionValue)
+            ->willReturn($resultValue);
+
+        $resultValue['url'] = [
+            'route' => 'sales/download/downloadCustomOption',
+            'params' => $fileObject->getCustomOptionUrlParams()
+        ];
+
+        $this->serializer->expects($this->once())
+            ->method('serialize')
+            ->with($resultValue)
+            ->willReturn(json_encode($resultValue));
+
+        $option = $this->getMockBuilder(\Magento\Quote\Model\Quote\Item\Option::class)
+            ->setMethods(['setValue'])
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $option->expects($this->once())
+            ->method('setValue')
+            ->with(json_encode($resultValue));
+
+        $fileObject->setConfigurationItemOption($option);
+
+        $fileObject->getFormattedOptionValue($optionValue);
+    }
+
+    public function testPrepareOptionValueForRequest()
+    {
+        $optionValue = 'string';
+        $resultValue = ['result'];
+        $fileObject = $this->getFileObject();
+
+        $this->serializer->expects($this->once())
+            ->method('unserialize')
+            ->with($optionValue)
+            ->willReturn($resultValue);
+
+        $this->assertEquals($resultValue, $fileObject->prepareOptionValueForRequest($optionValue));
+    }
 }
diff --git a/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php b/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php
index 0bd2f23418221770d4562eb67d6af9d3e8bd4646..d9ff7a92f08c6d86f17e3cfc568853e09ee5c59f 100644
--- a/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php
+++ b/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php
@@ -183,7 +183,7 @@ class Configurable extends \Magento\Catalog\Model\Product\Type\AbstractType
      * @param \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable $catalogProductTypeConfigurable
      * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
      * @param \Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface $extensionAttributesJoinProcessor
-     *
+     * @param \Magento\Framework\Serialize\Serializer\Json $serializer
      * @SuppressWarnings(PHPMD.ExcessiveParameterList)
      */
     public function __construct(
@@ -205,7 +205,8 @@ class Configurable extends \Magento\Catalog\Model\Product\Type\AbstractType
         \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
         \Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface $extensionAttributesJoinProcessor,
         \Magento\Framework\Cache\FrontendInterface $cache = null,
-        \Magento\Customer\Model\Session $customerSession = null
+        \Magento\Customer\Model\Session $customerSession = null,
+        \Magento\Framework\Serialize\Serializer\Json $serializer = null
     ) {
         $this->typeConfigurableFactory = $typeConfigurableFactory;
         $this->_eavAttributeFactory = $eavAttributeFactory;
@@ -226,7 +227,8 @@ class Configurable extends \Magento\Catalog\Model\Product\Type\AbstractType
             $filesystem,
             $coreRegistry,
             $logger,
-            $productRepository
+            $productRepository,
+            $serializer
         );
 
     }
@@ -414,47 +416,15 @@ class Configurable extends \Magento\Catalog\Model\Product\Type\AbstractType
             ['group' => 'CONFIGURABLE', 'method' => __METHOD__]
         );
         if (!$product->hasData($this->_configurableAttributes)) {
-            $metadata = $this->getMetadataPool()->getMetadata(ProductInterface::class);
-            $productId = $product->getData($metadata->getLinkField());
-            $cacheId =  __CLASS__ . $productId . '_' . $product->getStoreId();
-            $configurableAttributes = $this->getCache()->load($cacheId);
-            $configurableAttributes = $this->hasCacheData($configurableAttributes);
-            if ($configurableAttributes) {
-                $configurableAttributes->setProductFilter($product);
-            } else {
-                $configurableAttributes = $this->getConfigurableAttributeCollection($product);
-                $this->extensionAttributesJoinProcessor->process($configurableAttributes);
-                $configurableAttributes->orderByPosition()->load();
-                $this->getCache()->save(
-                    serialize($configurableAttributes),
-                    $cacheId,
-                    array_merge($product->getIdentities(), [self::TYPE_CODE . '_' . $productId])
-                );
-            }
+            $configurableAttributes = $this->getConfigurableAttributeCollection($product);
+            $this->extensionAttributesJoinProcessor->process($configurableAttributes);
+            $configurableAttributes->orderByPosition()->load();
             $product->setData($this->_configurableAttributes, $configurableAttributes);
         }
         \Magento\Framework\Profiler::stop('CONFIGURABLE:' . __METHOD__);
         return $product->getData($this->_configurableAttributes);
     }
 
-    /**
-     * @param mixed $configurableAttributes
-     * @return bool
-     */
-    protected function hasCacheData($configurableAttributes)
-    {
-        $configurableAttributes = $configurableAttributes ?: unserialize($configurableAttributes);
-        if (is_array($configurableAttributes) && count($configurableAttributes)) {
-            foreach ($configurableAttributes as $attribute) {
-                /** @var \Magento\ConfigurableProduct\Model\Product\Type\Configurable\Attribute $attribute */
-                if ($attribute->getData('options')) {
-                    return $configurableAttributes;
-                }
-            }
-        }
-        return false;
-    }
-
     /**
      * Reset the cached configurable attributes of a product
      *
@@ -463,13 +433,7 @@ class Configurable extends \Magento\Catalog\Model\Product\Type\AbstractType
      */
     public function resetConfigurableAttributes($product)
     {
-        $metadata = $this->getMetadataPool()->getMetadata(ProductInterface::class);
-        $productId = $product->getData($metadata->getLinkField());
         $product->unsetData($this->_configurableAttributes);
-        $cacheId =  __CLASS__ . $productId . '_' . $product->getStoreId();
-        $this->getCache()->remove($cacheId);
-        $this->getCache()->clean(\Zend_Cache::CLEANING_MODE_MATCHING_TAG, [self::TYPE_CODE . '_' . $productId]);
-
         return $this;
     }
 
@@ -566,7 +530,7 @@ class Configurable extends \Magento\Catalog\Model\Product\Type\AbstractType
                 )
             );
             $collection = $this->getUsedProductCollection($product);
-            $data = unserialize($this->getCache()->load($key));
+            $data = $this->serializer->unserialize($this->getCache()->load($key));
             if (!empty($data)) {
                 $usedProducts = [];
                 foreach ($data as $item) {
@@ -592,7 +556,7 @@ class Configurable extends \Magento\Catalog\Model\Product\Type\AbstractType
                 $usedProducts = $collection->getItems();
 
                 $this->getCache()->save(
-                    serialize(array_map(
+                    $this->serializer->serialize(array_map(
                         function ($item) {
                             return $item->getData();
                         },
@@ -883,7 +847,7 @@ class Configurable extends \Magento\Catalog\Model\Product\Type\AbstractType
             ['group' => 'CONFIGURABLE', 'method' => __METHOD__]
         );
         if ($attributesOption = $product->getCustomOption('attributes')) {
-            $data = unserialize($attributesOption->getValue());
+            $data = $this->serializer->unserialize($attributesOption->getValue());
             $this->getUsedProductAttributeIds($product);
 
             $usedAttributes = $product->getData($this->_usedAttributes);
@@ -906,7 +870,7 @@ class Configurable extends \Magento\Catalog\Model\Product\Type\AbstractType
                         'value' => $value,
                         'option_id' => $attributeId,
                         'option_value' => $attributeValue
-                        ];
+                    ];
                 }
             }
         }
@@ -965,7 +929,7 @@ class Configurable extends \Magento\Catalog\Model\Product\Type\AbstractType
 
                 if ($subProduct) {
                     $subProductLinkFieldId = $subProduct->getId();
-                    $product->addCustomOption('attributes', serialize($attributes));
+                    $product->addCustomOption('attributes', $this->serializer->serialize($attributes));
                     $product->addCustomOption('product_qty_' . $subProductLinkFieldId, 1, $subProduct);
                     $product->addCustomOption('simple_product', $subProductLinkFieldId, $subProduct);
 
@@ -1026,7 +990,7 @@ class Configurable extends \Magento\Catalog\Model\Product\Type\AbstractType
         parent::checkProductBuyState($product);
         $option = $product->getCustomOption('info_buyRequest');
         if ($option instanceof \Magento\Quote\Model\Quote\Item\Option) {
-            $buyRequest = new \Magento\Framework\DataObject(unserialize($option->getValue()));
+            $buyRequest = new \Magento\Framework\DataObject($this->serializer->unserialize($option->getValue()));
             $attributes = $buyRequest->getSuperAttribute();
             if (is_array($attributes)) {
                 foreach ($attributes as $key => $val) {
diff --git a/app/code/Magento/ConfigurableProduct/Model/Quote/Item/CartItemProcessor.php b/app/code/Magento/ConfigurableProduct/Model/Quote/Item/CartItemProcessor.php
index 8e661f99c5238d9ac811048e6f32829c388fc39b..a4ff02482b0190b961eaeddd31588ba7337f305e 100644
--- a/app/code/Magento/ConfigurableProduct/Model/Quote/Item/CartItemProcessor.php
+++ b/app/code/Magento/ConfigurableProduct/Model/Quote/Item/CartItemProcessor.php
@@ -7,6 +7,8 @@ namespace Magento\ConfigurableProduct\Model\Quote\Item;
 
 use Magento\Quote\Model\Quote\Item\CartItemProcessorInterface;
 use Magento\Quote\Api\Data\CartItemInterface;
+use Magento\Framework\Serialize\Serializer\Json;
+use Magento\Framework\App\ObjectManager;
 
 class CartItemProcessor implements CartItemProcessorInterface
 {
@@ -30,22 +32,30 @@ class CartItemProcessor implements CartItemProcessorInterface
      */
     protected $itemOptionValueFactory;
 
+    /**
+     * @var Json
+     */
+    private $serializer;
+
     /**
      * @param \Magento\Framework\DataObject\Factory $objectFactory
      * @param \Magento\Quote\Model\Quote\ProductOptionFactory $productOptionFactory
      * @param \Magento\Quote\Api\Data\ProductOptionExtensionFactory $extensionFactory
      * @param \Magento\ConfigurableProduct\Model\Quote\Item\ConfigurableItemOptionValueFactory $itemOptionValueFactory
+     * @param Json $serializer
      */
     public function __construct(
         \Magento\Framework\DataObject\Factory $objectFactory,
         \Magento\Quote\Model\Quote\ProductOptionFactory $productOptionFactory,
         \Magento\Quote\Api\Data\ProductOptionExtensionFactory $extensionFactory,
-        \Magento\ConfigurableProduct\Model\Quote\Item\ConfigurableItemOptionValueFactory $itemOptionValueFactory
+        \Magento\ConfigurableProduct\Model\Quote\Item\ConfigurableItemOptionValueFactory $itemOptionValueFactory,
+        Json $serializer = null
     ) {
         $this->objectFactory = $objectFactory;
         $this->productOptionFactory = $productOptionFactory;
         $this->extensionFactory = $extensionFactory;
         $this->itemOptionValueFactory = $itemOptionValueFactory;
+        $this->serializer = $serializer ?: ObjectManager::getInstance()->get(Json::class);
     }
 
     /**
@@ -73,7 +83,7 @@ class CartItemProcessor implements CartItemProcessorInterface
     public function processOptions(CartItemInterface $cartItem)
     {
         $attributesOption = $cartItem->getProduct()->getCustomOption('attributes');
-        $selectedConfigurableOptions = unserialize($attributesOption->getValue());
+        $selectedConfigurableOptions = $this->serializer->unserialize($attributesOption->getValue());
 
         if (is_array($selectedConfigurableOptions)) {
             $configurableOptions = [];
diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/Type/ConfigurableTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/Type/ConfigurableTest.php
index 4f7ae98cc11cee8543581ea02c70a252183c4aa5..a1a153731d07318b27b62a470ca5ccc43f7d44af 100644
--- a/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/Type/ConfigurableTest.php
+++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/Type/ConfigurableTest.php
@@ -15,7 +15,15 @@ use Magento\ConfigurableProduct\Model\Product\Type\Configurable;
 use Magento\Framework\EntityManager\EntityMetadata;
 use Magento\Framework\EntityManager\MetadataPool;
 use Magento\Customer\Model\Session;
-use Magento\Framework\Cache\FrontendInterface;
+use Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Attribute\CollectionFactory;
+use Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Attribute\Collection;
+use Magento\Catalog\Model\Product\Configuration\Item\Option\OptionInterface;
+use Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface;
+use Magento\ConfigurableProduct\Model\Product\Type\Configurable\AttributeFactory;
+use Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\ConfigurableFactory;
+use Magento\Eav\Model\Entity\Attribute\Frontend\AbstractFrontend;
+use Magento\Eav\Model\Entity\Attribute\Source\AbstractSource;
+use Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Product\Collection as ProductCollection;
 
 /**
  * Class \Magento\ConfigurableProduct\Test\Unit\Model\Product\Type\ConfigurableTest
@@ -94,6 +102,9 @@ class ConfigurableTest extends \PHPUnit_Framework_TestCase
     /** @var \PHPUnit_Framework_MockObject_MockObject */
     private $cache;
 
+    /** @var \PHPUnit_Framework_MockObject_MockObject */
+    private $serializer;
+
     /**
      * @var Config
      */
@@ -105,76 +116,67 @@ class ConfigurableTest extends \PHPUnit_Framework_TestCase
     protected function setUp()
     {
         $this->_objectHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
-        $eventManager = $this->getMock(\Magento\Framework\Event\ManagerInterface::class, [], [], '', false);
-        $fileStorageDbMock = $this->getMock(
-            \Magento\MediaStorage\Helper\File\Storage\Database::class,
-            [],
-            [],
-            '',
-            false
-        );
+        $eventManager = $this->getMockBuilder(\Magento\Framework\Event\ManagerInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $fileStorageDbMock = $this->getMockBuilder(\Magento\MediaStorage\Helper\File\Storage\Database::class)
+            ->disableOriginalConstructor()
+            ->getMock();
         $filesystem = $this->getMockBuilder(\Magento\Framework\Filesystem::class)
             ->disableOriginalConstructor()
             ->getMock();
-        $coreRegistry = $this->getMock(\Magento\Framework\Registry::class, [], [], '', false);
+        $coreRegistry = $this->getMockBuilder(\Magento\Framework\Registry::class)
+            ->disableOriginalConstructor()
+            ->getMock();
         $logger = $this->getMockBuilder(\Psr\Log\LoggerInterface::class)
             ->disableOriginalConstructor()
-            ->setMethods([])
-            ->getMockForAbstractClass();
-        $this->_typeConfigurableFactory = $this->getMock(
-            \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\ConfigurableFactory::class,
-            ['create', 'saveProducts'],
-            [],
-            '',
-            false
-        );
-        $this->_configurableAttributeFactoryMock = $this->getMock(
-            \Magento\ConfigurableProduct\Model\Product\Type\Configurable\AttributeFactory::class,
-            ['create'],
-            [],
-            '',
-            false
-        );
-        $this->_productCollectionFactory = $this->getMock(
-            \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Product\CollectionFactory::class,
-            ['create'],
-            [],
-            '',
-            false
-        );
-        $this->_attributeCollectionFactory = $this->getMock(
-            \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Attribute\CollectionFactory::class,
-            ['create'],
-            [],
-            '',
-            false
-        );
-        $this->productRepository = $this->getMock(\Magento\Catalog\Api\ProductRepositoryInterface::class);
-        $this->extensionAttributesJoinProcessorMock = $this->getMock(
-            \Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface::class,
-            [],
-            [],
-            '',
-            false
-        );
+            ->getMock();
+        $this->_typeConfigurableFactory = $this->getMockBuilder(ConfigurableFactory::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['create', 'saveProducts'])
+            ->getMock();
+        $this->_configurableAttributeFactoryMock = $this->getMockBuilder(AttributeFactory::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['create'])
+            ->getMock();
+        $this->_productCollectionFactory = $this->getMockBuilder(
+            \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Product\CollectionFactory::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['create'])
+            ->getMock();
+        $this->_attributeCollectionFactory = $this->getMockBuilder(CollectionFactory::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['create'])
+            ->getMock();
+        $this->productRepository = $this->getMockBuilder(\Magento\Catalog\Api\ProductRepositoryInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->extensionAttributesJoinProcessorMock = $this->getMockBuilder(JoinProcessorInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
         $this->entityMetadata = $this->getMockBuilder(EntityMetadata::class)
             ->disableOriginalConstructor()
             ->getMock();
         $this->metadataPool = $this->getMockBuilder(MetadataPool::class)
             ->disableOriginalConstructor()
             ->getMock();
-        $this->metadataPool->expects($this->any())
-            ->method('getMetadata')
-            ->with(ProductInterface::class)
-            ->willReturn($this->entityMetadata);
         $this->cache = $this->getMockBuilder(\Magento\Framework\Cache\FrontendInterface::class)
-            ->getMockForAbstractClass();
+            ->disableOriginalConstructor()
+            ->getMock();
         $this->catalogConfig = $this->getMockBuilder(Config::class)
             ->disableOriginalConstructor()
             ->getMock();
-
-        $this->eavConfig = $this->getMockBuilder(\Magento\Eav\Model\Config::class)->disableOriginalConstructor()
+        $this->eavConfig = $this->getMockBuilder(\Magento\Eav\Model\Config::class)
+            ->disableOriginalConstructor()
             ->getMock();
+        $this->serializer = $this->getMockBuilder(\Magento\Framework\Serialize\Serializer\Json::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->metadataPool->expects($this->any())
+            ->method('getMetadata')
+            ->with(ProductInterface::class)
+            ->willReturn($this->entityMetadata);
 
         $this->_model = $this->_objectHelper->getObject(
             Configurable::class,
@@ -194,6 +196,7 @@ class ConfigurableTest extends \PHPUnit_Framework_TestCase
                 'customerSession' => $this->getMockBuilder(Session::class)->disableOriginalConstructor()->getMock(),
                 'cache' => $this->cache,
                 'catalogConfig' => $this->catalogConfig,
+                'serializer' => $this->serializer,
             ]
         );
         $refClass = new \ReflectionClass(Configurable::class);
@@ -223,19 +226,20 @@ class ConfigurableTest extends \PHPUnit_Framework_TestCase
                     'getData',
                     'hasData',
                     'getAssociatedProductIds',
-                    '__wakeup',
-                    '__sleep',
                 ]
             )->disableOriginalConstructor()
             ->getMock();
-        $product->expects($this->any())->method('dataHasChangedFor')->will($this->returnValue('false'));
-        $product->expects($this->any())->method('getConfigurableAttributesData')
-            ->will($this->returnValue($this->attributeData));
-        $product->expects($this->once())->method('getIsDuplicate')->will($this->returnValue(true));
-        $product->expects($this->any())->method('getStoreId')->will($this->returnValue(1));
-        $product->expects($this->any())->method('getAssociatedProductIds')->will($this->returnValue([2]));
-        $product->expects($this->any())->method('hasData')->with('_cache_instance_used_product_attribute_ids')
-            ->will($this->returnValue(true));
+        $product->expects($this->once())->method('dataHasChangedFor')->willReturn('false');
+        $product->expects($this->once())
+            ->method('getConfigurableAttributesData')
+            ->willReturn($this->attributeData);
+        $product->expects($this->once())->method('getIsDuplicate')->willReturn(true);
+        $product->expects($this->atLeastOnce())->method('getStoreId')->willReturn(1);
+        $product->expects($this->once())->method('getAssociatedProductIds')->willReturn([2]);
+        $product->expects($this->once())
+            ->method('hasData')
+            ->with('_cache_instance_used_product_attribute_ids')
+            ->willReturn(true);
         $extensionAttributes = $this->getMockBuilder(ProductExtensionInterface::class)
             ->setMethods([
                 'getConfigurableProductOptions',
@@ -250,7 +254,7 @@ class ConfigurableTest extends \PHPUnit_Framework_TestCase
             ['_cache_instance_used_product_attribute_ids', null, 1],
             ['link', null, 1],
         ];
-        $product->expects($this->any())
+        $product->expects($this->atLeastOnce())
             ->method('getData')
             ->willReturnMap($dataMap);
         $attribute = $this->getMockBuilder(
@@ -260,24 +264,26 @@ class ConfigurableTest extends \PHPUnit_Framework_TestCase
             ->getMock();
         $expectedAttributeData = $this->attributeData[1];
         unset($expectedAttributeData['id']);
-        $attribute->expects($this->once())->method('addData')->with($expectedAttributeData)->will($this->returnSelf());
-        $attribute->expects($this->once())->method('setStoreId')->with(1)->will($this->returnSelf());
-        $attribute->expects($this->once())->method('setProductId')->with(1)->will($this->returnSelf());
-        $attribute->expects($this->once())->method('save')->will($this->returnSelf());
-
-        $this->_configurableAttributeFactoryMock->expects($this->any())->method('create')
-            ->will($this->returnValue($attribute));
-
-        $attributeCollection = $this->getMockBuilder(
-            \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Attribute\Collection::class
-        )->setMethods(['setProductFilter', 'addFieldToFilter', 'walk'])->disableOriginalConstructor()
-            ->getMock();
-        $this->_attributeCollectionFactory->expects($this->any())->method('create')
-            ->will($this->returnValue($attributeCollection));
-
-        $this->_typeConfigurableFactory->expects($this->once())->method('create')->will($this->returnSelf());
-        $this->_typeConfigurableFactory->expects($this->once())->method('saveProducts')->withAnyParameters()
-            ->will($this->returnSelf());
+        $attribute->expects($this->once())->method('addData')->with($expectedAttributeData)->willReturnSelf();
+        $attribute->expects($this->once())->method('setStoreId')->with(1)->willReturnSelf();
+        $attribute->expects($this->once())->method('setProductId')->with(1)->willReturnSelf();
+        $attribute->expects($this->once())->method('save')->willReturnSelf();
+
+        $this->_configurableAttributeFactoryMock->expects($this->once())
+            ->method('create')
+            ->willReturn($attribute);
+        $attributeCollection = $this->getMockBuilder(Collection::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->_attributeCollectionFactory->expects($this->once())
+            ->method('create')
+            ->willReturn($attributeCollection);
+        $this->_typeConfigurableFactory->expects($this->once())
+            ->method('create')
+            ->willReturnSelf();
+        $this->_typeConfigurableFactory->expects($this->once())
+            ->method('saveProducts')
+            ->willReturnSelf();
 
         $this->_model->save($product);
     }
@@ -293,174 +299,117 @@ class ConfigurableTest extends \PHPUnit_Framework_TestCase
 
     public function testCanUseAttribute()
     {
-        $attribute = $this->getMock(
-            \Magento\Catalog\Model\ResourceModel\Eav\Attribute::class,
-            [
-                'getIsGlobal',
-                'getIsVisible',
-                'usesSource',
-                'getIsUserDefined',
-                '__wakeup',
-                '__sleep'
-            ],
-            [],
-            '',
-            false
-        );
+        $attribute = $this->getMockBuilder(\Magento\Catalog\Model\ResourceModel\Eav\Attribute::class)
+            ->disableOriginalConstructor()
+            ->getMock();
         $attribute->expects($this->once())
             ->method('getIsGlobal')
-            ->will($this->returnValue(1));
+            ->willReturn(1);
         $attribute->expects($this->once())
             ->method('getIsVisible')
-            ->will($this->returnValue(1));
+            ->willReturn(1);
         $attribute->expects($this->once())
             ->method('usesSource')
-            ->will($this->returnValue(1));
+            ->willReturn(1);
         $attribute->expects($this->once())
             ->method('getIsUserDefined')
-            ->will($this->returnValue(1));
+            ->willReturn(1);
 
         $this->assertTrue($this->_model->canUseAttribute($attribute));
     }
 
     public function testGetUsedProducts()
     {
-        $attributeCollection = $this->getMockBuilder(
-            \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Attribute\Collection::class
-        )->setMethods(['setProductFilter', 'addFieldToFilter', 'walk'])->disableOriginalConstructor()
+        $productCollectionItemData = ['array'];
+
+        $productCollectionItem = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $attributeCollection = $this->getMockBuilder(Collection::class)
+            ->disableOriginalConstructor()
             ->getMock();
-        $attributeCollection->expects($this->any())->method('setProductFilter')->will($this->returnSelf());
-        $this->_attributeCollectionFactory->expects($this->any())->method('create')
-            ->will($this->returnValue($attributeCollection));
         $product = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
-            ->setMethods(
-                [
-                    'dataHasChangedFor',
-                    'getConfigurableAttributesData',
-                    'getStoreId',
-                    'getId',
-                    'getData',
-                    'hasData',
-                    'getAssociatedProductIds',
-                    'getIdentities',
-                    '__wakeup',
-                    '__sleep',
-                ]
-            )->disableOriginalConstructor()
+            ->disableOriginalConstructor()
+            ->getMock();
+        $productCollection = $this->getMockBuilder(ProductCollection::class)
+            ->disableOriginalConstructor()
             ->getMock();
-        $product->expects($this->any())->method('getConfigurableAttributesData')
-            ->will($this->returnValue($this->attributeData));
-        $product->expects($this->any())->method('getStoreId')->will($this->returnValue(5));
-        $product->expects($this->any())->method('getId')->will($this->returnValue(1));
-        $product->expects($this->any())->method('getIdentities')->willReturn(['123']);
-        $product->expects($this->any())->method('getAssociatedProductIds')->will($this->returnValue([2]));
 
-        $product->expects($this->any())->method('hasData')
-            ->will(
-                $this->returnValueMap(
-                    [
-                        ['_cache_instance_used_product_attribute_ids', 1],
-                        ['_cache_instance_products', 0],
-                        ['_cache_instance_configurable_attributes', 1],
-                        ['_cache_instance_used_product_attributes', 1],
-                    ]
-                )
+        $productCollectionItem->expects($this->once())->method('getData')->willReturn($productCollectionItemData);
+        $attributeCollection->expects($this->any())->method('setProductFilter')->willReturnSelf();
+        $product->expects($this->atLeastOnce())->method('getStoreId')->willReturn(5);
+        $product->expects($this->once())->method('getIdentities')->willReturn(['123']);
+
+        $product->expects($this->exactly(2))
+            ->method('hasData')
+            ->willReturnMap(
+                [
+                    ['_cache_instance_products', null],
+                    ['_cache_instance_used_product_attributes', 1],
+                ]
             );
-        $product->expects($this->any())->method('getData')
-            ->will($this->returnValueMap(
+        $product->expects($this->any())
+            ->method('getData')
+            ->willReturnMap(
                 [
-                    ['_cache_instance_used_product_attributes', null, []],
+                    ['_cache_instance_used_product_attributes', null, []]
                 ]
-            ));
-
-
-        $productCollection = $this->getMockBuilder(
-            \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Product\Collection::class
-        )->setMethods(
-            [
-                'setFlag',
-                'setProductFilter',
-                'addStoreFilter',
-                'addAttributeToSelect',
-                'addFilterByRequiredOptions',
-                'setStoreId',
-                'addTierPriceData',
-                'getIterator',
-                'load',
-            ]
-        )->disableOriginalConstructor()
-            ->getMock();
-        $productCollection->expects($this->any())->method('addAttributeToSelect')->will($this->returnSelf());
-        $productCollection->expects($this->any())->method('setProductFilter')->will($this->returnSelf());
-        $productCollection->expects($this->any())->method('setFlag')->will($this->returnSelf());
-        $productCollection->expects($this->any())->method('addTierPriceData')->will($this->returnSelf());
-        $productCollection->expects($this->any())->method('addFilterByRequiredOptions')->will($this->returnSelf());
-        $productCollection->expects($this->any())->method('setStoreId')->with(5)->will($this->returnValue([]));
-        $productCollection->expects($this->any())->method('getIterator')->willReturn(
-            new \ArrayIterator([])
-        );
-
+            );
 
-        $this->_productCollectionFactory->expects($this->any())->method('create')
-            ->will($this->returnValue($productCollection));
+        $productCollection->expects($this->atLeastOnce())->method('addAttributeToSelect')->willReturnSelf();
+        $productCollection->expects($this->once())->method('setProductFilter')->willReturnSelf();
+        $productCollection->expects($this->atLeastOnce())->method('setFlag')->willReturnSelf();
+        $productCollection->expects($this->once())->method('addTierPriceData')->willReturnSelf();
+        $productCollection->expects($this->once())->method('addFilterByRequiredOptions')->willReturnSelf();
+        $productCollection->expects($this->once())->method('setStoreId')->with(5)->willReturn([]);
+        $productCollection->expects($this->once())->method('getItems')->willReturn([$productCollectionItem]);
+
+        $this->serializer->expects($this->once())->method('unserialize')->willReturn([]);
+        $this->serializer->expects($this->once())
+            ->method('serialize')
+            ->with([$productCollectionItemData])
+            ->willReturn('result');
+
+        $this->_productCollectionFactory->expects($this->any())->method('create')->willReturn($productCollection);
         $this->_model->getUsedProducts($product);
     }
 
     /**
      * @param int $productStore
-     * @param int $attributeStore
      *
      * @dataProvider getConfigurableAttributesAsArrayDataProvider
      */
-    public function testGetConfigurableAttributesAsArray($productStore, $attributeStore)
+    public function testGetConfigurableAttributesAsArray($productStore)
     {
-        $attributeSource = $this->getMockForAbstractClass(
-            \Magento\Eav\Model\Entity\Attribute\Source\AbstractSource::class,
-            [],
-            '',
-            false,
-            true,
-            true,
-            ['getAllOptions']
-        );
-        $attributeSource->expects($this->any())->method('getAllOptions')->will($this->returnValue([]));
-
-        $attributeFrontend = $this->getMockForAbstractClass(
-            \Magento\Eav\Model\Entity\Attribute\Frontend\AbstractFrontend::class,
-            [],
-            '',
-            false,
-            true,
-            true,
-            ['getLabel']
-        );
-        $attributeFrontend->expects($this->any())->method('getLabel')->will($this->returnValue('Label'));
-
-        $eavAttribute = $this->getMock(
-            \Magento\Catalog\Model\ResourceModel\Eav\Attribute::class,
-            ['getFrontend', 'getSource', 'getStoreLabel', '__wakeup', 'setStoreId', '__sleep'],
-            [],
-            '',
-            false
-        );
-        $eavAttribute->expects($this->any())->method('getFrontend')->will($this->returnValue($attributeFrontend));
-        $eavAttribute->expects($this->any())->method('getSource')->will($this->returnValue($attributeSource));
-        $eavAttribute->expects($this->any())->method('getStoreLabel')->will($this->returnValue('Store Label'));
-        $eavAttribute->expects($this->any())->method('setStoreId')->with($attributeStore);
+        $attributeSource = $this->getMockBuilder(AbstractSource::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $attributeFrontend = $this->getMockBuilder(AbstractFrontend::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $eavAttribute = $this->getMockBuilder(\Magento\Catalog\Model\ResourceModel\Eav\Attribute::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $attributeSource->expects($this->once())->method('getAllOptions')->willReturn([]);
+        $attributeFrontend->expects($this->once())->method('getLabel')->willReturn('Label');
+        $eavAttribute->expects($this->once())->method('getFrontend')->willReturn($attributeFrontend);
+        $eavAttribute->expects($this->once())->method('getSource')->willReturn($attributeSource);
+        $eavAttribute->expects($this->atLeastOnce())->method('getStoreLabel')->willReturn('Store Label');
 
         $attribute = $this->getMockBuilder(
             \Magento\ConfigurableProduct\Model\Product\Type\Configurable\Attribute::class)
             ->disableOriginalConstructor()
             ->setMethods(['getProductAttribute', '__wakeup', '__sleep'])
             ->getMock();
-        $attribute->expects($this->any())->method('getProductAttribute')->will($this->returnValue($eavAttribute));
+        $attribute->expects($this->any())->method('getProductAttribute')->willReturn($eavAttribute);
 
         $product = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
             ->setMethods(['getStoreId', 'getData', 'hasData', '__wakeup', '__sleep'])
             ->disableOriginalConstructor()
             ->getMock();
-        $product->expects($this->any())->method('getStoreId')->will($this->returnValue($productStore));
-        $product->expects($this->any())->method('hasData')
+        $product->expects($this->atLeastOnce())->method('getStoreId')->willReturn($productStore);
+        $product->expects($this->atLeastOnce())->method('hasData')
             ->will(
                 $this->returnValueMap(
                     [
@@ -487,69 +436,56 @@ class ConfigurableTest extends \PHPUnit_Framework_TestCase
     public function getConfigurableAttributesAsArrayDataProvider()
     {
         return [
-            [5, 5],
-            [null, 0],
+            [5],
+            [null],
         ];
     }
 
     public function testGetConfigurableAttributes()
     {
-        $expectedData = [1];
         $configurableAttributes = '_cache_instance_configurable_attributes';
 
         /** @var \Magento\Catalog\Model\Product|\PHPUnit_Framework_MockObject_MockObject $product */
         $product = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
-            ->setMethods(['getData', 'hasData', 'setData', 'getIdentities', 'getId', 'getStoreId'])
+            ->setMethods(['getData', 'hasData', 'setData'])
             ->disableOriginalConstructor()
             ->getMock();
-        $product->expects($this->once())->method('hasData')->with($configurableAttributes)->willReturn(false);
-        $product->expects($this->once())->method('getStoreId')->willReturn(0);
-        $product->expects($this->any())->method('getId')->willReturn(0);
-        $product->expects($this->any())->method('getIdentities')->willReturn(['123']);
-        $product->expects($this->once())->method('setData')->willReturnSelf();
-        $product->expects($this->exactly(2))
-            ->method('getData')
-            ->willReturnMap(
-                [
-                    [$configurableAttributes, null, $expectedData],
-                    ['link', null, 1],
-                ]
-            );
-        $product->expects($this->once())->method('getIdentities')->willReturn([1,2,3]);
 
-        $this->entityMetadata->expects($this->once())
-            ->method('getLinkField')
-            ->willReturn('link');
+        $product->expects($this->once())->method('hasData')->with($configurableAttributes)->willReturn(false);
 
-        $attributeCollection = $this->getMockBuilder(
-            \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Attribute\Collection::class
-        )
+        $attributeCollection = $this->getMockBuilder(Collection::class)
             ->setMethods(['setProductFilter', 'orderByPosition', 'load'])
             ->disableOriginalConstructor()
             ->getMock();
-        $attributeCollection->expects($this->any())->method('setProductFilter')->will($this->returnSelf());
-        $attributeCollection->expects($this->any())->method('orderByPosition')->will($this->returnSelf());
-        $this->_attributeCollectionFactory->expects($this->any())->method('create')->willReturn($attributeCollection);
+        $attributeCollection->expects($this->once())->method('setProductFilter')->willReturnSelf();
+        $attributeCollection->expects($this->once())->method('orderByPosition')->willReturnSelf();
+        $attributeCollection->expects($this->once())->method('load')->willReturnSelf();
 
-        $this->extensionAttributesJoinProcessorMock->expects($this->once())
-            ->method('process')
-            ->with(
-                $this->isInstanceOf(\Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Attribute\Collection::class
-                )
-            );
+        $this->_attributeCollectionFactory->expects($this->once())->method('create')->willReturn($attributeCollection);
+
+        $product->expects($this->once())
+            ->method('setData')
+            ->with($configurableAttributes, $attributeCollection)
+            ->willReturnSelf();
+
+        $product->expects($this->once())
+            ->method('getData')
+            ->with($configurableAttributes)
+            ->willReturn($attributeCollection);
 
-        $this->assertEquals($expectedData, $this->_model->getConfigurableAttributes($product));
+        $this->assertEquals($attributeCollection, $this->_model->getConfigurableAttributes($product));
     }
 
     public function testResetConfigurableAttributes()
     {
         $product = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
-            ->setMethods(['unsetData', '__wakeup', '__sleep', 'getStoreId', 'getId'])
+            ->setMethods(['unsetData'])
             ->disableOriginalConstructor()
             ->getMock();
-        $product->expects($this->any())->method('unsetData')
+        $product->expects($this->once())
+            ->method('unsetData')
             ->with('_cache_instance_configurable_attributes')
-            ->will($this->returnSelf());
+            ->willReturnSelf();
 
         $this->assertEquals($this->_model, $this->_model->resetConfigurableAttributes($product));
     }
@@ -629,13 +565,26 @@ class ConfigurableTest extends \PHPUnit_Framework_TestCase
 
     public function testGetSelectedAttributesInfo()
     {
+        $this->serializer->expects($this->any())
+            ->method('serialize')
+            ->willReturnCallback(
+                function ($value) {
+                    return json_encode($value);
+                }
+            );
+
+        $this->serializer->expects($this->any())
+            ->method('unserialize')
+            ->willReturnCallback(
+                function ($value) {
+                    return json_decode($value, true);
+                }
+            );
+
         $productMock = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
-            ->setMethods(['__wakeup', 'getCustomOption', 'hasData', 'getData'])
             ->disableOriginalConstructor()
             ->getMock();
-        $optionMock = $this->getMockBuilder(
-            \Magento\Catalog\Model\Product\Configuration\Item\Option\OptionInterface::class)
-            ->setMethods(['getValue'])
+        $optionMock = $this->getMockBuilder(OptionInterface::class)
             ->disableOriginalConstructor()
             ->getMock();
         $usedAttributeMock = $this->getMockBuilder(
@@ -645,11 +594,10 @@ class ConfigurableTest extends \PHPUnit_Framework_TestCase
             ->disableOriginalConstructor()
             ->getMock();
         $attributeMock = $this->getMockBuilder(\Magento\Catalog\Model\ResourceModel\Eav\Attribute::class)
-            ->setMethods(['getStoreLabel', 'getSourceModel'])
             ->disableOriginalConstructor()
             ->getMock();
 
-        $optionMock->expects($this->once())->method('getValue')->willReturn(serialize($this->attributeData));
+        $optionMock->expects($this->once())->method('getValue')->willReturn(json_encode($this->attributeData));
         $productMock->expects($this->once())->method('getCustomOption')->with('attributes')->willReturn($optionMock);
         $productMock->expects($this->once())->method('hasData')->willReturn(true);
         $productMock->expects($this->at(2))->method('getData')->willReturn(true);
@@ -662,24 +610,25 @@ class ConfigurableTest extends \PHPUnit_Framework_TestCase
             $this->_model->getSelectedAttributesInfo($productMock),
             [
                 [
-                'label' => 'attr_store_label',
-                'value' => '',
-                'option_id' => 1,
-                'option_value' => ''
+                    'label' => 'attr_store_label',
+                    'value' => '',
+                    'option_id' => 1,
+                    'option_value' => ''
                 ]
             ]
         );
     }
 
+    /**
+     * @covers \Magento\ConfigurableProduct\Model\Product\Type\Configurable::checkProductBuyState()
+     */
     public function testCheckProductBuyState()
     {
-        $this->markTestIncomplete('checkProductBuyState() method is not complete in parent class');
         $productMock = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
-            ->setMethods(['__wakeup', 'getCustomOption', 'getSkipCheckRequiredOption'])
+            ->setMethods(['getSkipCheckRequiredOption', 'getCustomOption'])
             ->disableOriginalConstructor()
             ->getMock();
         $optionMock = $this->getMockBuilder(\Magento\Quote\Model\Quote\Item\Option::class)
-            ->setMethods(['getValue'])
             ->disableOriginalConstructor()
             ->getMock();
 
@@ -690,24 +639,30 @@ class ConfigurableTest extends \PHPUnit_Framework_TestCase
             ->willReturn($optionMock);
         $optionMock->expects($this->once())
             ->method('getValue')
-            ->willReturn(serialize(['super_attribute' => ['test_key' => 'test_value', 'empty_key' => '']]));
+            ->willReturn(json_encode(['super_attribute' => ['test_key' => 'test_value', 'empty_key' => '']]));
+        $this->serializer->expects($this->any())
+            ->method('unserialize')
+            ->willReturnCallback(
+                function ($value) {
+                    return json_decode($value, true);
+                }
+            );
 
         $this->assertEquals($this->_model, $this->_model->checkProductBuyState($productMock));
     }
 
     /**
+     * @covers \Magento\ConfigurableProduct\Model\Product\Type\Configurable::checkProductBuyState()
      * @expectedException \Magento\Framework\Exception\LocalizedException
      * @expectedExceptionMessage You need to choose options for your item.
      */
     public function testCheckProductBuyStateException()
     {
-        $this->markTestIncomplete('checkProductBuyState() method is not complete in parent class');
         $productMock = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
-            ->setMethods(['__wakeup', 'getCustomOption', 'getSkipCheckRequiredOption'])
+            ->setMethods(['getSkipCheckRequiredOption', 'getCustomOption'])
             ->disableOriginalConstructor()
             ->getMock();
         $optionMock = $this->getMockBuilder(\Magento\Quote\Model\Quote\Item\Option::class)
-            ->setMethods(['getValue'])
             ->disableOriginalConstructor()
             ->getMock();
 
@@ -716,7 +671,14 @@ class ConfigurableTest extends \PHPUnit_Framework_TestCase
             ->method('getCustomOption')
             ->with('info_buyRequest')
             ->willReturn($optionMock);
-        $optionMock->expects($this->once())->method('getValue')->willReturn(serialize([]));
+        $optionMock->expects($this->once())->method('getValue')->willReturn(json_encode([]));
+        $this->serializer->expects($this->any())
+            ->method('unserialize')
+            ->willReturnCallback(
+                function ($value) {
+                    return json_decode($value, true);
+                }
+            );
 
         $this->_model->checkProductBuyState($productMock);
     }
@@ -724,47 +686,29 @@ class ConfigurableTest extends \PHPUnit_Framework_TestCase
     public function testGetProductByAttributesReturnUsedProduct()
     {
         $productMock = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
-            ->setMethods(['__wakeup', 'hasData', 'getData', 'getResource', 'getAttributeSetId'])
             ->disableOriginalConstructor()
             ->getMock();
         $firstItemMock = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
-            ->setMethods(['__wakeup', 'getId'])
             ->disableOriginalConstructor()
             ->getMock();
         $usedProductMock = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
-            ->setMethods(['__wakeup', 'getData'])
             ->disableOriginalConstructor()
             ->getMock();
         $eavAttributeMock = $this->getMockBuilder(\Magento\Eav\Model\Entity\Attribute\AbstractAttribute::class)
-            ->setMethods(['__wakeup', 'getId', 'getAttributeCode'])
             ->disableOriginalConstructor()
             ->getMock();
-        $productCollection = $this->getMockBuilder(
-            \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Product\Collection::class
-        )
-            ->setMethods(
-                [
-                    'setFlag',
-                    'setProductFilter',
-                    'addStoreFilter',
-                    'addAttributeToSelect',
-                    'addAttributeToFilter',
-                    'getFirstItem',
-                    'getIterator'
-                ]
-            )
+        $productCollection = $this->getMockBuilder(ProductCollection::class)
             ->disableOriginalConstructor()
             ->getMock();
 
-        $this->_productCollectionFactory->expects($this->any())->method('create')
-            ->will($this->returnValue($productCollection));
-        $productCollection->expects($this->any())->method('setProductFilter')->will($this->returnSelf());
-        $productCollection->expects($this->any())->method('setFlag')->will($this->returnSelf());
-        $productCollection->expects($this->any())->method('addAttributeToSelect')->will($this->returnSelf());
-        $productCollection->expects($this->any())->method('addAttributeToFilter')->will($this->returnSelf());
+        $this->_productCollectionFactory->expects($this->once())->method('create')->willReturn($productCollection);
+        $productCollection->expects($this->once())->method('setProductFilter')->willReturnSelf();
+        $productCollection->expects($this->once())->method('setFlag')->willReturnSelf();
+        $productCollection->expects($this->once())->method('addAttributeToSelect')->willReturnSelf();
+        $productCollection->expects($this->once())->method('addAttributeToFilter')->willReturnSelf();
         $productCollection->expects($this->once())->method('getFirstItem')->willReturn($firstItemMock);
-        $productCollection->expects($this->any())->method('getIterator')->willReturn(
-          new \ArrayIterator([$usedProductMock])
+        $productCollection->expects($this->once())->method('getIterator')->willReturn(
+            new \ArrayIterator([$usedProductMock])
         );
 
         $firstItemMock->expects($this->once())->method('getId')->willReturn(false);
@@ -789,42 +733,24 @@ class ConfigurableTest extends \PHPUnit_Framework_TestCase
     public function testGetProductByAttributesReturnFirstItem()
     {
         $productMock = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
-            ->setMethods(['__wakeup', 'hasData', 'getData', 'getResource', 'getAttributeSetId'])
             ->disableOriginalConstructor()
             ->getMock();
         $firstItemMock = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
-            ->setMethods(['__wakeup', 'getId'])
             ->disableOriginalConstructor()
             ->getMock();
-        $productCollection = $this->getMockBuilder(
-            \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Product\Collection::class
-        )
-            ->setMethods(
-                [
-                    'setFlag',
-                    'setProductFilter',
-                    'addStoreFilter',
-                    'addAttributeToSelect',
-                    'addAttributeToFilter',
-                    'getFirstItem',
-                ]
-            )
+        $productCollection = $this->getMockBuilder(ProductCollection::class)
             ->disableOriginalConstructor()
             ->getMock();
 
-        $this->_productCollectionFactory->expects($this->any())->method('create')
-            ->will($this->returnValue($productCollection));
-        $productCollection->expects($this->any())->method('setProductFilter')->will($this->returnSelf());
-        $productCollection->expects($this->any())->method('setFlag')->will($this->returnSelf());
-        $productCollection->expects($this->any())->method('addAttributeToSelect')->will($this->returnSelf());
-        $productCollection->expects($this->any())->method('addAttributeToFilter')->will($this->returnSelf());
+        $this->_productCollectionFactory->expects($this->any())->method('create')->willReturn($productCollection);
+        $productCollection->expects($this->once())->method('setProductFilter')->willReturnSelf();
+        $productCollection->expects($this->once())->method('setFlag')->willReturnSelf();
+        $productCollection->expects($this->once())->method('addAttributeToSelect')->willReturnSelf();
+        $productCollection->expects($this->once())->method('addAttributeToFilter')->willReturnSelf();
         $productCollection->expects($this->once())->method('getFirstItem')->willReturn($firstItemMock);
-        $firstItemMock->expects(static::once())
-            ->method('getId')
-            ->willReturn(3);
+        $firstItemMock->expects($this->once())->method('getId')->willReturn(3);
         $this->productRepository->expects($this->once())->method('getById')->with(3)->willReturn($firstItemMock);
 
-
         $this->assertEquals(
             $firstItemMock,
             $this->_model->getProductByAttributes($this->attributeData, $productMock)
@@ -834,11 +760,10 @@ class ConfigurableTest extends \PHPUnit_Framework_TestCase
     public function testSetImageFromChildProduct()
     {
         $productMock = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
-            ->setMethods(['__wakeup', 'hasData', 'getData', 'setImage'])
+            ->setMethods(['hasData', 'getData', 'setImage'])
             ->disableOriginalConstructor()
             ->getMock();
         $childProductMock = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
-            ->setMethods(['__wakeup', 'getData'])
             ->disableOriginalConstructor()
             ->getMock();
 
diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Quote/Item/CartItemProcessorTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Quote/Item/CartItemProcessorTest.php
index ab4f5e3be7cfac0185c21086fa7c82bf85b3f8fe..227c9cc36b308424aa1ebd472e331353fa62ef32 100644
--- a/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Quote/Item/CartItemProcessorTest.php
+++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Quote/Item/CartItemProcessorTest.php
@@ -43,6 +43,9 @@ class CartItemProcessorTest extends \PHPUnit_Framework_TestCase
      */
     private $productOptionExtensionAttributes;
 
+    /** @var \PHPUnit_Framework_MockObject_MockObject */
+    private $serializer;
+
     protected function setUp()
     {
         $this->objectFactoryMock = $this->getMock(
@@ -84,11 +87,36 @@ class CartItemProcessorTest extends \PHPUnit_Framework_TestCase
             ['setConfigurableItemOptions']
         );
 
+        $this->serializer = $this->getMock(
+            \Magento\Framework\Serialize\Serializer\Json::class,
+            [],
+            [],
+            '',
+            false
+        );
+
+        $this->serializer->expects($this->any())
+            ->method('serialize')
+            ->willReturnCallback(
+                function ($value) {
+                    return json_encode($value);
+                }
+            );
+
+        $this->serializer->expects($this->any())
+            ->method('unserialize')
+            ->willReturnCallback(
+                function ($value) {
+                    return json_decode($value, true);
+                }
+            );
+
         $this->model = new \Magento\ConfigurableProduct\Model\Quote\Item\CartItemProcessor(
             $this->objectFactoryMock,
             $this->optionFactoryMock,
             $this->optionExtensionFactoryMock,
-            $this->optionValueFactoryMock
+            $this->optionValueFactoryMock,
+            $this->serializer
         );
     }
 
@@ -174,7 +202,7 @@ class CartItemProcessorTest extends \PHPUnit_Framework_TestCase
             '',
             false
         );
-        $customOption->expects($this->once())->method('getValue')->willReturn(serialize([$optionId => $optionValue]));
+        $customOption->expects($this->once())->method('getValue')->willReturn(json_encode([$optionId => $optionValue]));
         $productMock = $this->getMock(\Magento\Catalog\Model\Product::class, [], [], '', false);
         $productMock->expects($this->once())->method('getCustomOption')->with('attributes')->willReturn($customOption);
 
@@ -227,7 +255,7 @@ class CartItemProcessorTest extends \PHPUnit_Framework_TestCase
             '',
             false
         );
-        $customOption->expects($this->once())->method('getValue')->willReturn(serialize([$optionId => $optionValue]));
+        $customOption->expects($this->once())->method('getValue')->willReturn(json_encode([$optionId => $optionValue]));
         $productMock = $this->getMock(\Magento\Catalog\Model\Product::class, [], [], '', false);
         $productMock->expects($this->once())->method('getCustomOption')->with('attributes')->willReturn($customOption);
 
diff --git a/app/code/Magento/Downloadable/Model/Product/Type.php b/app/code/Magento/Downloadable/Model/Product/Type.php
index 64c00d208b86fc233fc2908dca8afca644ec667d..1ab363d5b2b583df219ee931a05f01f858fbb31a 100644
--- a/app/code/Magento/Downloadable/Model/Product/Type.php
+++ b/app/code/Magento/Downloadable/Model/Product/Type.php
@@ -85,6 +85,7 @@ class Type extends \Magento\Catalog\Model\Product\Type\Virtual
      * @param \Magento\Downloadable\Model\LinkFactory $linkFactory
      * @param TypeHandler\TypeHandlerInterface $typeHandler
      * @param JoinProcessorInterface $extensionAttributesJoinProcessor
+     * @param \Magento\Framework\Serialize\Serializer\Json|null $serializer
      * @SuppressWarnings(PHPMD.ExcessiveParameterList)
      */
     public function __construct(
@@ -104,7 +105,8 @@ class Type extends \Magento\Catalog\Model\Product\Type\Virtual
         \Magento\Downloadable\Model\SampleFactory $sampleFactory,
         \Magento\Downloadable\Model\LinkFactory $linkFactory,
         \Magento\Downloadable\Model\Product\TypeHandler\TypeHandlerInterface $typeHandler,
-        JoinProcessorInterface $extensionAttributesJoinProcessor
+        JoinProcessorInterface $extensionAttributesJoinProcessor,
+        \Magento\Framework\Serialize\Serializer\Json $serializer = null
     ) {
         $this->_sampleResFactory = $sampleResFactory;
         $this->_linkResource = $linkResource;
@@ -123,7 +125,8 @@ class Type extends \Magento\Catalog\Model\Product\Type\Virtual
             $filesystem,
             $coreRegistry,
             $logger,
-            $productRepository
+            $productRepository,
+            $serializer
         );
     }
 
@@ -249,14 +252,17 @@ class Type extends \Magento\Catalog\Model\Product\Type\Virtual
         parent::checkProductBuyState($product);
         $option = $product->getCustomOption('info_buyRequest');
         if ($option instanceof \Magento\Quote\Model\Quote\Item\Option) {
-            $buyRequest = new \Magento\Framework\DataObject(unserialize($option->getValue()));
+            $buyRequest = new \Magento\Framework\DataObject($this->serializer->unserialize($option->getValue()));
             if (!$buyRequest->hasLinks()) {
                 if (!$product->getLinksPurchasedSeparately()) {
                     $allLinksIds = $this->_linksFactory->create()->addProductToFilter(
                         $product->getEntityId()
                     )->getAllIds();
                     $buyRequest->setLinks($allLinksIds);
-                    $product->addCustomOption('info_buyRequest', serialize($buyRequest->getData()));
+                    $product->addCustomOption(
+                        'info_buyRequest',
+                        $this->serializer->serialize($buyRequest->getData())
+                    );
                 } else {
                     throw new \Magento\Framework\Exception\LocalizedException(__('Please specify product link(s).'));
                 }
diff --git a/app/code/Magento/Downloadable/Test/Unit/Model/Product/TypeTest.php b/app/code/Magento/Downloadable/Test/Unit/Model/Product/TypeTest.php
index 61d66d47bc2815bc37f33c1550dfab9f8e3bdbaf..b93a6a8386116f16ed5048226d29a784af6b74b2 100644
--- a/app/code/Magento/Downloadable/Test/Unit/Model/Product/TypeTest.php
+++ b/app/code/Magento/Downloadable/Test/Unit/Model/Product/TypeTest.php
@@ -6,6 +6,7 @@
 namespace Magento\Downloadable\Test\Unit\Model\Product;
 
 use Magento\Downloadable\Model\Product\TypeHandler\TypeHandlerInterface;
+use Magento\Framework\Serialize\Serializer\Json;
 
 /**
  * Class TypeTest
@@ -30,12 +31,27 @@ class TypeTest extends \PHPUnit_Framework_TestCase
      */
     private $product;
 
+    /**
+     * @var \Magento\Framework\Serialize\Serializer\Json|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $serializerMock;
+
+    /**
+     * @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager
+     */
+    private $objectManager;
+
+    /**
+     * @var \Magento\Downloadable\Model\ResourceModel\Link\CollectionFactory|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $linksFactory;
+
     /**
      * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
      */
     protected function setUp()
     {
-        $objectHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+        $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
         $eventManager = $this->getMock(\Magento\Framework\Event\ManagerInterface::class, [], [], '', false);
         $fileStorageDb = $this->getMockBuilder(
             \Magento\MediaStorage\Helper\File\Storage\Database::class
@@ -54,9 +70,9 @@ class TypeTest extends \PHPUnit_Framework_TestCase
             false
         );
         $linkResource = $this->getMock(\Magento\Downloadable\Model\ResourceModel\Link::class, [], [], '', false);
-        $linksFactory = $this->getMock(
+        $this->linksFactory = $this->getMock(
             \Magento\Downloadable\Model\ResourceModel\Link\CollectionFactory::class,
-            [],
+            ['create'],
             [],
             '',
             false
@@ -81,6 +97,30 @@ class TypeTest extends \PHPUnit_Framework_TestCase
         );
         $resourceProductMock->expects($this->any())->method('getEntityType')->will($this->returnValue($entityTypeMock));
 
+        $this->serializerMock = $this->getMock(
+            Json::class,
+            [],
+            ['serialize', 'unserialize'],
+            '',
+            false
+        );
+
+        $this->serializerMock->expects($this->any())
+            ->method('serialize')
+            ->willReturnCallback(
+                function ($value) {
+                    return json_encode($value);
+                }
+            );
+
+        $this->serializerMock->expects($this->any())
+            ->method('unserialize')
+            ->willReturnCallback(
+                function ($value) {
+                    return json_decode($value, true);
+                }
+            );
+
         $this->product = $this->getMock(
             \Magento\Catalog\Model\Product::class,
             [
@@ -94,6 +134,9 @@ class TypeTest extends \PHPUnit_Framework_TestCase
                 'setLinksExist',
                 'getDownloadableLinks',
                 '__wakeup',
+                'getCustomOption',
+                'addCustomOption',
+                'getEntityId'
             ],
             [],
             '',
@@ -109,8 +152,6 @@ class TypeTest extends \PHPUnit_Framework_TestCase
         $this->product->expects($this->any())->method('setTypeHasOptions')->with($this->equalTo(false));
         $this->product->expects($this->any())->method('setLinksExist')->with($this->equalTo(false));
         $this->product->expects($this->any())->method('canAffectOptions')->with($this->equalTo(true));
-        $this->product->expects($this->any())->method('getLinksPurchasedSeparately')->will($this->returnValue(true));
-        $this->product->expects($this->any())->method('getLinksPurchasedSeparately')->will($this->returnValue(true));
 
         $eavConfigMock = $this->getMock(\Magento\Eav\Model\Config::class, ['getEntityAttributeCodes'], [], '', false);
         $eavConfigMock->expects($this->any())
@@ -123,7 +164,7 @@ class TypeTest extends \PHPUnit_Framework_TestCase
             ->setMethods(['save'])
             ->getMock();
 
-        $this->target = $objectHelper->getObject(
+        $this->target = $this->objectManager->getObject(
             \Magento\Downloadable\Model\Product\Type::class,
             [
                 'eventManager' => $eventManager,
@@ -134,13 +175,13 @@ class TypeTest extends \PHPUnit_Framework_TestCase
                 'productFactory' => $productFactoryMock,
                 'sampleResFactory' => $sampleResFactory,
                 'linkResource' => $linkResource,
-                'linksFactory' => $linksFactory,
+                'linksFactory' => $this->linksFactory,
                 'samplesFactory' => $samplesFactory,
                 'sampleFactory' => $sampleFactory,
                 'linkFactory' => $linkFactory,
                 'eavConfig' => $eavConfigMock,
                 'typeHandler' => $this->typeHandler,
-
+                'serializer' => $this->serializerMock
             ]
         );
     }
@@ -157,9 +198,79 @@ class TypeTest extends \PHPUnit_Framework_TestCase
 
     public function testHasLinks()
     {
+        $this->product->expects($this->any())->method('getLinksPurchasedSeparately')->will($this->returnValue(true));
         $this->product->expects($this->exactly(2))
             ->method('getDownloadableLinks')
             ->willReturn(['link1', 'link2']);
         $this->assertTrue($this->target->hasLinks($this->product));
     }
+
+    public function testCheckProductBuyState()
+    {
+        $optionMock = $this->getMock(\Magento\Quote\Model\Quote\Item\Option::class, [], ['getValue'], '', false);
+
+        $optionMock->expects($this->any())->method('getValue')->will($this->returnValue('{}'));
+
+        $this->product->expects($this->any())
+            ->method('getCustomOption')
+            ->with('info_buyRequest')
+            ->will($this->returnValue($optionMock));
+
+        $this->product->expects($this->any())
+            ->method('getLinksPurchasedSeparately')
+            ->will($this->returnValue(false));
+
+        $this->product->expects($this->any())
+            ->method('getEntityId')
+            ->will($this->returnValue(123));
+
+        $linksCollectionMock = $this->getMock(
+            \Magento\Downloadable\Model\ResourceModel\Link\Collection::class,
+            [],
+            ['addProductToFilter', 'getAllIds'],
+            '',
+            false
+        );
+
+        $linksCollectionMock->expects($this->once())
+            ->method('addProductToFilter')
+            ->with(123)
+            ->will($this->returnSelf());
+
+        $linksCollectionMock->expects($this->once())
+            ->method('getAllIds')
+            ->will($this->returnValue([1, 2, 3]));
+
+        $this->linksFactory->expects($this->any())
+            ->method('create')
+            ->will($this->returnValue($linksCollectionMock));
+
+        $this->product->expects($this->once())
+            ->method('addCustomOption')
+            ->with('info_buyRequest', '{"links":[1,2,3]}');
+
+        $this->target->checkProductBuyState($this->product);
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\LocalizedException
+     * @expectedExceptionMessage Please specify product link(s).
+     */
+    public function testCheckProductBuyStateException()
+    {
+        $optionMock = $this->getMock(\Magento\Quote\Model\Quote\Item\Option::class, [], ['getValue'], '', false);
+
+        $optionMock->expects($this->any())->method('getValue')->will($this->returnValue('{}'));
+
+        $this->product->expects($this->any())
+            ->method('getCustomOption')
+            ->with('info_buyRequest')
+            ->will($this->returnValue($optionMock));
+
+        $this->product->expects($this->any())
+            ->method('getLinksPurchasedSeparately')
+            ->will($this->returnValue(true));
+
+        $this->target->checkProductBuyState($this->product);
+    }
 }
diff --git a/app/code/Magento/Eav/Model/ResourceModel/Entity/Attribute/Set.php b/app/code/Magento/Eav/Model/ResourceModel/Entity/Attribute/Set.php
index b3e7bf2bc3925224cace683b4aba2fe57b29e63e..9b3a4ef42fc5e3499241f00b608f8af86f22e4bf 100644
--- a/app/code/Magento/Eav/Model/ResourceModel/Entity/Attribute/Set.php
+++ b/app/code/Magento/Eav/Model/ResourceModel/Entity/Attribute/Set.php
@@ -5,12 +5,10 @@
  */
 namespace Magento\Eav\Model\ResourceModel\Entity\Attribute;
 
-use Magento\Framework\Serialize\SerializerInterface;
-
 class Set extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
 {
     /**
-     * EAV cache ids
+     * EAV cache id
      */
     const ATTRIBUTES_CACHE_ID = 'EAV_ENTITY_ATTRIBUTES_BY_SET_ID';
 
@@ -25,16 +23,12 @@ class Set extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
     protected $eavConfig;
 
     /**
-     * @var SerializerInterface
-     */
-    private $serializer;
-
-    /**
+     * Constructor
+     *
      * @param \Magento\Framework\Model\ResourceModel\Db\Context $context
      * @param GroupFactory $attrGroupFactory
      * @param \Magento\Eav\Model\Config $eavConfig
-     * @param string $connectionName
-     * @codeCoverageIgnore
+     * @param string|null $connectionName
      */
     public function __construct(
         \Magento\Framework\Model\ResourceModel\Db\Context $context,
@@ -235,19 +229,4 @@ class Set extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
         }
         return $connection->fetchAll($select, $bind);
     }
-
-    /**
-     * Get serializer
-     *
-     * @return SerializerInterface
-     * @deprecated
-     */
-    private function getSerializer()
-    {
-        if (null === $this->serializer) {
-            $this->serializer = \Magento\Framework\App\ObjectManager::getInstance()
-                ->get(SerializerInterface::class);
-        }
-        return $this->serializer;
-    }
 }
diff --git a/app/code/Magento/Eav/Test/Unit/Model/ResourceModel/Entity/Attribute/SetTest.php b/app/code/Magento/Eav/Test/Unit/Model/ResourceModel/Entity/Attribute/SetTest.php
index e00a8ee97648c0768c7dac4c10359e1378856674..8a588a6cbe76c4c8f298c1c56e8a577ac30678fa 100644
--- a/app/code/Magento/Eav/Test/Unit/Model/ResourceModel/Entity/Attribute/SetTest.php
+++ b/app/code/Magento/Eav/Test/Unit/Model/ResourceModel/Entity/Attribute/SetTest.php
@@ -7,7 +7,7 @@ namespace Magento\Eav\Test\Unit\Model\ResourceModel\Entity\Attribute;
 
 use Magento\Eav\Model\ResourceModel\Entity\Attribute\Set;
 use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
-use Magento\Framework\Serialize\SerializerInterface;
+use Magento\Framework\Serialize\Serializer\Json;
 
 /**
  * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
@@ -50,7 +50,7 @@ class SetTest extends \PHPUnit_Framework_TestCase
     protected $relationProcessor;
 
     /**
-     * @var SerializerInterface|\PHPUnit_Framework_MockObject_MockObject
+     * @var Json|\PHPUnit_Framework_MockObject_MockObject
      */
     private $serializerMock;
 
@@ -88,7 +88,7 @@ class SetTest extends \PHPUnit_Framework_TestCase
             ->disableOriginalConstructor()
             ->getMock();
 
-        $this->serializerMock = $this->getMock(SerializerInterface::class);
+        $this->serializerMock = $this->getMock(Json::class);
 
         $attributeGroupFactoryMock = $this->getMock(
             \Magento\Eav\Model\ResourceModel\Entity\Attribute\GroupFactory::class,
diff --git a/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php b/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php
index 74a7e8112aa0ddb528b46168a16df15310fd227c..08dd1553d99b1208d7cc8e10bc89b5f814b3a0e2 100644
--- a/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php
+++ b/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php
@@ -95,7 +95,7 @@ class Grouped extends \Magento\Catalog\Model\Product\Type\AbstractType
      * @param \Magento\Catalog\Model\Product\Attribute\Source\Status $catalogProductStatus
      * @param \Magento\Framework\App\State $appState
      * @param \Magento\Msrp\Helper\Data $msrpData
-     *
+     * @param \Magento\Framework\Serialize\Serializer\Json|null $serializer
      * @SuppressWarnings(PHPMD.ExcessiveParameterList)
      */
     public function __construct(
@@ -112,7 +112,8 @@ class Grouped extends \Magento\Catalog\Model\Product\Type\AbstractType
         \Magento\Store\Model\StoreManagerInterface $storeManager,
         \Magento\Catalog\Model\Product\Attribute\Source\Status $catalogProductStatus,
         \Magento\Framework\App\State $appState,
-        \Magento\Msrp\Helper\Data $msrpData
+        \Magento\Msrp\Helper\Data $msrpData,
+        \Magento\Framework\Serialize\Serializer\Json $serializer = null
     ) {
         $this->productLinks = $catalogProductLink;
         $this->_storeManager = $storeManager;
@@ -128,7 +129,8 @@ class Grouped extends \Magento\Catalog\Model\Product\Type\AbstractType
             $filesystem,
             $coreRegistry,
             $logger,
-            $productRepository
+            $productRepository,
+            $serializer
         );
     }
 
@@ -384,7 +386,7 @@ class Grouped extends \Magento\Catalog\Model\Product\Type\AbstractType
                 $_result[0]->addCustomOption('product_type', self::TYPE_CODE, $product);
                 $_result[0]->addCustomOption(
                     'info_buyRequest',
-                    serialize(
+                    $this->serializer->serialize(
                         [
                             'super_product_config' => [
                                 'product_type' => self::TYPE_CODE,
@@ -402,7 +404,7 @@ class Grouped extends \Magento\Catalog\Model\Product\Type\AbstractType
 
         if (!$isStrictProcessMode || count($associatedProductsInfo)) {
             $product->addCustomOption('product_type', self::TYPE_CODE, $product);
-            $product->addCustomOption('info_buyRequest', serialize($buyRequest->getData()));
+            $product->addCustomOption('info_buyRequest', $this->serializer->serialize($buyRequest->getData()));
 
             $products[] = $product;
         }
diff --git a/app/code/Magento/GroupedProduct/Test/Unit/Model/Product/Type/GroupedTest.php b/app/code/Magento/GroupedProduct/Test/Unit/Model/Product/Type/GroupedTest.php
index 3efc0b7058be1e8fa803d5dc6a43cd66bb03d145..42afe71e16c30deb8d9fdced21bcd57ca7da46e3 100644
--- a/app/code/Magento/GroupedProduct/Test/Unit/Model/Product/Type/GroupedTest.php
+++ b/app/code/Magento/GroupedProduct/Test/Unit/Model/Product/Type/GroupedTest.php
@@ -37,6 +37,11 @@ class GroupedTest extends \PHPUnit_Framework_TestCase
      */
     protected $objectHelper;
 
+    /**
+     * @var \Magento\Framework\Serialize\Serializer\Json
+     */
+    private $serializer;
+
     protected function setUp()
     {
         $this->objectHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
@@ -67,6 +72,10 @@ class GroupedTest extends \PHPUnit_Framework_TestCase
             '',
             false
         );
+        $this->serializer = $this->getMockBuilder(\Magento\Framework\Serialize\Serializer\Json::class)
+            ->setMethods(['serialize'])
+            ->getMockForAbstractClass();
+
         $this->_model = $this->objectHelper->getObject(
             \Magento\GroupedProduct\Model\Product\Type\Grouped::class,
             [
@@ -77,7 +86,8 @@ class GroupedTest extends \PHPUnit_Framework_TestCase
                 'logger' => $logger,
                 'productFactory' => $productFactoryMock,
                 'catalogProductLink' => $this->catalogProductLink,
-                'catalogProductStatus' => $this->productStatusMock
+                'catalogProductStatus' => $this->productStatusMock,
+                'serializer' => $this->serializer
             ]
         );
     }
@@ -429,6 +439,9 @@ class GroupedTest extends \PHPUnit_Framework_TestCase
             ->expects($this->atLeastOnce())
             ->method('getData')
             ->will($this->returnValue($associatedProducts));
+        $this->serializer->expects($this->any())
+            ->method('serialize')
+            ->willReturn(json_encode($buyRequest->getData()));
 
         $this->assertEquals(
             [0 => $this->product],
@@ -540,6 +553,10 @@ class GroupedTest extends \PHPUnit_Framework_TestCase
         $buyRequest = new \Magento\Framework\DataObject();
         $buyRequest->setSuperGroup([$associatedId => 1]);
 
+        $this->serializer->expects($this->any())
+            ->method('serialize')
+            ->willReturn(json_encode($buyRequest->getData()));
+
         $cached = true;
         $this->product
             ->expects($this->atLeastOnce())
@@ -583,6 +600,10 @@ class GroupedTest extends \PHPUnit_Framework_TestCase
         $buyRequest = new \Magento\Framework\DataObject();
         $buyRequest->setSuperGroup([$associatedId => 1]);
 
+        $this->serializer->expects($this->any())
+            ->method('serialize')
+            ->willReturn(json_encode($buyRequest->getData()));
+
         $cached = true;
         $this->product
             ->expects($this->atLeastOnce())
diff --git a/app/code/Magento/Quote/Model/Quote/Address.php b/app/code/Magento/Quote/Model/Quote/Address.php
index f1764da5e555b06d5055fe7e1ed7bf9cbad065ad..b1126549e3bcfbdb2ddcd8b3f179f1b6c9ed26e6 100644
--- a/app/code/Magento/Quote/Model/Quote/Address.php
+++ b/app/code/Magento/Quote/Model/Quote/Address.php
@@ -8,7 +8,8 @@ namespace Magento\Quote\Model\Quote;
 use Magento\Customer\Api\AddressMetadataInterface;
 use Magento\Customer\Api\Data\AddressInterfaceFactory;
 use Magento\Customer\Api\Data\RegionInterfaceFactory;
-use Magento\Quote\Api\Data\AddressInterface;
+use Magento\Framework\Serialize\Serializer\Json;
+use Magento\Framework\App\ObjectManager;
 
 /**
  * Sales Quote address model
@@ -233,6 +234,11 @@ class Address extends \Magento\Customer\Model\Address\AbstractAddress implements
      */
     protected $totalsReader;
 
+    /**
+     * @var Json
+     */
+    private $serializer;
+
     /**
      * @param \Magento\Framework\Model\Context $context
      * @param \Magento\Framework\Registry $registry
@@ -266,6 +272,7 @@ class Address extends \Magento\Customer\Model\Address\AbstractAddress implements
      * @param \Magento\Framework\Model\ResourceModel\AbstractResource|null $resource
      * @param \Magento\Framework\Data\Collection\AbstractDb|null $resourceCollection
      * @param array $data
+     * @param Json $serializer
      *
      * @SuppressWarnings(PHPMD.ExcessiveParameterList)
      */
@@ -301,7 +308,8 @@ class Address extends \Magento\Customer\Model\Address\AbstractAddress implements
         \Magento\Quote\Model\Quote\TotalsReader $totalsReader,
         \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
         \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
-        array $data = []
+        array $data = [],
+        Json $serializer = null
     ) {
         $this->_scopeConfig = $scopeConfig;
         $this->_addressItemFactory = $addressItemFactory;
@@ -320,6 +328,7 @@ class Address extends \Magento\Customer\Model\Address\AbstractAddress implements
         $this->attributeList = $attributeList;
         $this->totalsCollector = $totalsCollector;
         $this->totalsReader = $totalsReader;
+        $this->serializer = $serializer ?: ObjectManager::getInstance()->get(Json::class);
         parent::__construct(
             $context,
             $registry,
@@ -1143,7 +1152,7 @@ class Address extends \Magento\Customer\Model\Address\AbstractAddress implements
      */
     public function getAppliedTaxes()
     {
-        return unserialize($this->getData('applied_taxes'));
+        return $this->serializer->unserialize($this->getData('applied_taxes'));
     }
 
     /**
@@ -1154,7 +1163,7 @@ class Address extends \Magento\Customer\Model\Address\AbstractAddress implements
      */
     public function setAppliedTaxes($data)
     {
-        return $this->setData('applied_taxes', serialize($data));
+        return $this->setData('applied_taxes', $this->serializer->serialize($data));
     }
 
     /******************************* Start Total Collector Interface *******************************************/
diff --git a/app/code/Magento/Quote/Model/Quote/Address/Total.php b/app/code/Magento/Quote/Model/Quote/Address/Total.php
index aeaa71fb8daad7c4fa8d832e66cad83dadb45f34..cd7aa54e1497b68a512f23e61d176afbd605f797 100644
--- a/app/code/Magento/Quote/Model/Quote/Address/Total.php
+++ b/app/code/Magento/Quote/Model/Quote/Address/Total.php
@@ -17,6 +17,28 @@ class Total extends \Magento\Framework\DataObject
      */
     protected $baseTotalAmounts;
 
+    /**
+     * Serializer interface instance.
+     *
+     * @var \Magento\Framework\Serialize\Serializer\Json
+     */
+    private $serializer;
+
+    /**
+     * Constructor
+     *
+     * @param array $data
+     * @param \Magento\Framework\Serialize\Serializer\Json|null $serializer
+     */
+    public function __construct(
+        array $data = [],
+        \Magento\Framework\Serialize\Serializer\Json $serializer = null
+    ) {
+        $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance()
+            ->get(\Magento\Framework\Serialize\Serializer\Json::class);
+        parent::__construct($data);
+    }
+
     /**
      * Set total amount value
      *
@@ -159,7 +181,7 @@ class Total extends \Magento\Framework\DataObject
     {
         $fullInfo = $this->getData('full_info');
         if (is_string($fullInfo)) {
-            $fullInfo = unserialize($fullInfo);
+            $fullInfo = $this->serializer->unserialize($fullInfo);
         }
         return $fullInfo;
     }
diff --git a/app/code/Magento/Quote/Model/Quote/Item.php b/app/code/Magento/Quote/Model/Quote/Item.php
index ac3a1109d7172cee98f38a7bf5ec5f2a71527b00..a8aa2b2dc273bbb4d750eff28b8fda5436edde99 100644
--- a/app/code/Magento/Quote/Model/Quote/Item.php
+++ b/app/code/Magento/Quote/Model/Quote/Item.php
@@ -175,6 +175,13 @@ class Item extends \Magento\Quote\Model\Quote\Item\AbstractItem implements \Mage
      */
     protected $stockRegistry;
 
+    /**
+     * Serializer interface instance.
+     *
+     * @var \Magento\Framework\Serialize\Serializer\Json
+     */
+    private $serializer;
+
     /**
      * @param \Magento\Framework\Model\Context $context
      * @param \Magento\Framework\Registry $registry
@@ -191,6 +198,7 @@ class Item extends \Magento\Quote\Model\Quote\Item\AbstractItem implements \Mage
      * @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection
      * @param array $data
      *
+     * @param \Magento\Framework\Serialize\Serializer\Json $serializer
      * @SuppressWarnings(PHPMD.ExcessiveParameterList)
      */
     public function __construct(
@@ -207,13 +215,16 @@ class Item extends \Magento\Quote\Model\Quote\Item\AbstractItem implements \Mage
         \Magento\CatalogInventory\Api\StockRegistryInterface $stockRegistry,
         \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
         \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
-        array $data = []
+        array $data = [],
+        \Magento\Framework\Serialize\Serializer\Json $serializer = null
     ) {
         $this->_errorInfos = $statusListFactory->create();
         $this->_localeFormat = $localeFormat;
         $this->_itemOptionFactory = $itemOptionFactory;
         $this->quoteItemCompare = $quoteItemCompare;
         $this->stockRegistry = $stockRegistry;
+        $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance()
+            ->get(\Magento\Framework\Serialize\Serializer\Json::class);
         parent::__construct(
             $context,
             $registry,
@@ -808,7 +819,8 @@ class Item extends \Magento\Quote\Model\Quote\Item\AbstractItem implements \Mage
     public function getBuyRequest()
     {
         $option = $this->getOptionByCode('info_buyRequest');
-        $buyRequest = new \Magento\Framework\DataObject($option ? unserialize($option->getValue()) : []);
+        $data = $option ? $this->serializer->unserialize($option->getValue()) : [];
+        $buyRequest = new \Magento\Framework\DataObject($data);
 
         // Overwrite standard buy request qty, because item qty could have changed since adding to quote
         $buyRequest->setOriginalQty($buyRequest->getQty())->setQty($this->getQty() * 1);
diff --git a/app/code/Magento/Quote/Model/Quote/Item/Compare.php b/app/code/Magento/Quote/Model/Quote/Item/Compare.php
index 10bb712025462fc11f99c2f55206c6cf10f8b854..ca788f0985ca2d580457aef7c196afdc38516738 100644
--- a/app/code/Magento/Quote/Model/Quote/Item/Compare.php
+++ b/app/code/Magento/Quote/Model/Quote/Item/Compare.php
@@ -12,6 +12,22 @@ use Magento\Quote\Model\Quote\Item;
  */
 class Compare
 {
+    /**
+     * Serializer interface instance.
+     *
+     * @var \Magento\Framework\Serialize\Serializer\Json
+     */
+    private $serializer;
+
+    /**
+     * @param \Magento\Framework\Serialize\Serializer\Json|null $serializer
+     */
+    public function __construct(\Magento\Framework\Serialize\Serializer\Json $serializer = null)
+    {
+        $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance()
+            ->get(\Magento\Framework\Serialize\Serializer\Json::class);
+    }
+
     /**
      * Returns option values adopted to compare
      *
@@ -20,8 +36,8 @@ class Compare
      */
     protected function getOptionValues($value)
     {
-        if (is_string($value) && is_array(@unserialize($value))) {
-            $value = @unserialize($value);
+        if (is_string($value) && is_array($this->serializer->unserialize($value))) {
+            $value = $this->serializer->unserialize($value);
             unset($value['qty'], $value['uenc']);
             $value = array_filter($value, function ($optionValue) {
                 return !empty($optionValue);
diff --git a/app/code/Magento/Quote/Model/Quote/Item/Updater.php b/app/code/Magento/Quote/Model/Quote/Item/Updater.php
index 45f9d3d90e39e0cd517853cf218b5ac8b08f3858..1ea7676cca405a5fb1abc58cdb341b6b51d39f97 100644
--- a/app/code/Magento/Quote/Model/Quote/Item/Updater.php
+++ b/app/code/Magento/Quote/Model/Quote/Item/Updater.php
@@ -32,19 +32,30 @@ class Updater
      */
     protected $objectFactory;
 
+    /**
+     * Serializer interface instance.
+     *
+     * @var \Magento\Framework\Serialize\Serializer\Json
+     */
+    private $serializer;
+
     /**
      * @param ProductFactory $productFactory
      * @param FormatInterface $localeFormat
      * @param ObjectFactory $objectFactory
+     * @param \Magento\Framework\Serialize\Serializer\Json|null $serializer
      */
     public function __construct(
         ProductFactory $productFactory,
         FormatInterface $localeFormat,
-        ObjectFactory $objectFactory
+        ObjectFactory $objectFactory,
+        \Magento\Framework\Serialize\Serializer\Json $serializer = null
     ) {
         $this->productFactory = $productFactory;
         $this->localeFormat = $localeFormat;
         $this->objectFactory = $objectFactory;
+        $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance()
+            ->get(\Magento\Framework\Serialize\Serializer\Json::class);
     }
 
     /**
@@ -104,7 +115,7 @@ class Updater
         if ($infoBuyRequest) {
             $infoBuyRequest->setCustomPrice($itemPrice);
 
-            $infoBuyRequest->setValue(serialize($infoBuyRequest->getData()));
+            $infoBuyRequest->setValue($this->serializer->serialize($infoBuyRequest->getData()));
             $infoBuyRequest->setCode('info_buyRequest');
             $infoBuyRequest->setProduct($item->getProduct());
 
@@ -128,7 +139,7 @@ class Updater
         if ($infoBuyRequest->hasData('custom_price')) {
             $infoBuyRequest->unsetData('custom_price');
 
-            $infoBuyRequest->setValue(serialize($infoBuyRequest->getData()));
+            $infoBuyRequest->setValue($this->serializer->serialize($infoBuyRequest->getData()));
             $infoBuyRequest->setCode('info_buyRequest');
             $infoBuyRequest->setProduct($item->getProduct());
             $item->addOption($infoBuyRequest);
diff --git a/app/code/Magento/Quote/Model/Quote/Payment.php b/app/code/Magento/Quote/Model/Quote/Payment.php
index 612802ccd279d58e3aa0349a8fb1da1ea4213f60..03acf1d6500e10ce8bd27194524658ba4b73982d 100644
--- a/app/code/Magento/Quote/Model/Quote/Payment.php
+++ b/app/code/Magento/Quote/Model/Quote/Payment.php
@@ -65,6 +65,13 @@ class Payment extends \Magento\Payment\Model\Info implements PaymentInterface
      */
     private $additionalChecks;
 
+    /**
+     * Serializer interface instance.
+     *
+     * @var \Magento\Framework\Serialize\Serializer\Json
+     */
+    private $serializer;
+
     /**
      * @param \Magento\Framework\Model\Context $context
      * @param \Magento\Framework\Registry $registry
@@ -77,6 +84,7 @@ class Payment extends \Magento\Payment\Model\Info implements PaymentInterface
      * @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection
      * @param array $data
      * @param array $additionalChecks
+     * @param \Magento\Framework\Serialize\Serializer\Json|null $serializer
      * @SuppressWarnings(PHPMD.ExcessiveParameterList)
      */
     public function __construct(
@@ -90,10 +98,13 @@ class Payment extends \Magento\Payment\Model\Info implements PaymentInterface
         \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
         \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
         array $data = [],
-        array $additionalChecks = []
+        array $additionalChecks = [],
+        \Magento\Framework\Serialize\Serializer\Json $serializer = null
     ) {
         $this->methodSpecificationFactory = $methodSpecificationFactory;
         $this->additionalChecks = $additionalChecks;
+        $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance()
+            ->get(\Magento\Framework\Serialize\Serializer\Json::class);
         parent::__construct(
             $context,
             $registry,
@@ -326,7 +337,7 @@ class Payment extends \Magento\Payment\Model\Info implements PaymentInterface
     {
         $additionalDataValue = $this->getData(self::KEY_ADDITIONAL_DATA);
         if (is_string($additionalDataValue)) {
-            $additionalData = @unserialize($additionalDataValue);
+            $additionalData = $this->serializer->unserialize($additionalDataValue);
             if (is_array($additionalData)) {
                 return $additionalData;
             }
diff --git a/app/code/Magento/Quote/Setup/ConvertSerializedDataToJson.php b/app/code/Magento/Quote/Setup/ConvertSerializedDataToJson.php
new file mode 100644
index 0000000000000000000000000000000000000000..7b3da6ba95c69a77b6661cfa562837a51a4aba83
--- /dev/null
+++ b/app/code/Magento/Quote/Setup/ConvertSerializedDataToJson.php
@@ -0,0 +1,140 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Quote\Setup;
+
+use Magento\Framework\DB\FieldDataConverterFactory;
+use Magento\Framework\DB\Select\QueryModifierFactory;
+use Magento\Framework\DB\Query\Generator;
+
+/**
+ * Convert serialized data in quote tables to JSON
+ */
+class ConvertSerializedDataToJson
+{
+    /**
+     * @var QuoteSetup
+     */
+    private $quoteSetup;
+
+    /**
+     * @var FieldDataConverterFactory
+     */
+    private $fieldDataConverterFactory;
+
+    /**
+     * @var QueryModifierFactory
+     */
+    private $queryModifierFactory;
+
+    /**
+     * @var Generator
+     */
+    private $queryGenerator;
+
+    /**
+     * Constructor
+     *
+     * @param QuoteSetup $quoteSetup
+     * @param FieldDataConverterFactory $fieldDataConverterFactory
+     * @param QueryModifierFactory $queryModifierFactory
+     * @param Generator $queryGenerator
+     */
+    public function __construct(
+        QuoteSetup $quoteSetup,
+        FieldDataConverterFactory $fieldDataConverterFactory,
+        QueryModifierFactory $queryModifierFactory,
+        Generator $queryGenerator
+    ) {
+        $this->quoteSetup = $quoteSetup;
+        $this->fieldDataConverterFactory = $fieldDataConverterFactory;
+        $this->queryModifierFactory = $queryModifierFactory;
+        $this->queryGenerator = $queryGenerator;
+    }
+
+    /**
+     * Convert data for additional_information field in quote_payment table from serialized
+     * to JSON format
+     *
+     * @return void
+     * @throws \InvalidArgumentException
+     */
+    public function convert()
+    {
+        $fieldDataConverter = $this->fieldDataConverterFactory->create(
+            \Magento\Framework\DB\DataConverter\SerializedToJson::class
+        );
+        $fieldDataConverter->convert(
+            $this->quoteSetup->getConnection(),
+            $this->quoteSetup->getTable('quote_payment'),
+            'payment_id',
+            'additional_information'
+        );
+        $fieldDataConverter->convert(
+            $this->quoteSetup->getConnection(),
+            $this->quoteSetup->getTable('quote_address'),
+            'address_id',
+            'applied_taxes'
+        );
+        $queryModifier = $this->queryModifierFactory->create(
+            'in',
+            [
+                'values' => [
+                    'code' => [
+                        'parameters',
+                        'info_buyRequest',
+                        'attributes',
+                        'bundle_option_ids',
+                        'bundle_selection_ids',
+                        'bundle_selection_attributes',
+                    ]
+                ]
+            ]
+        );
+        $fieldDataConverter->convert(
+            $this->quoteSetup->getConnection(),
+            $this->quoteSetup->getTable('quote_item_option'),
+            'option_id',
+            'value',
+            $queryModifier
+        );
+        $select = $this->quoteSetup->getSetup()
+            ->getConnection()
+            ->select()
+            ->from(
+                $this->quoteSetup->getSetup()
+                    ->getTable('catalog_product_option'),
+                ['option_id']
+            )
+            ->where('type = ?', 'file');
+        $iterator = $this->queryGenerator->generate('option_id', $select);
+        foreach ($iterator as $selectByRange) {
+            $codes = $this->quoteSetup->getSetup()
+                ->getConnection()
+                ->fetchCol($selectByRange);
+            $codes = array_map(
+                function ($id) {
+                    return 'option_' . $id;
+                },
+                $codes
+            );
+            $queryModifier = $this->queryModifierFactory->create(
+                'in',
+                [
+                    'values' => [
+                        'code' => $codes
+                    ]
+                ]
+            );
+            $fieldDataConverter->convert(
+                $this->quoteSetup->getConnection(),
+                $this->quoteSetup->getTable('quote_item_option'),
+                'option_id',
+                'value',
+                $queryModifier
+            );
+        }
+    }
+}
diff --git a/app/code/Magento/Quote/Setup/QuoteSetup.php b/app/code/Magento/Quote/Setup/QuoteSetup.php
index 1ef5f4b0dae2ee91a9580ae9097f6d129ce8f24e..cbd357d537fb12e2f42037a432d138012dfe446d 100644
--- a/app/code/Magento/Quote/Setup/QuoteSetup.php
+++ b/app/code/Magento/Quote/Setup/QuoteSetup.php
@@ -13,7 +13,8 @@ use Magento\Framework\App\Config\ScopeConfigInterface;
 use Magento\Framework\Setup\ModuleDataSetupInterface;
 
 /**
- * Setup Model of Quote Module
+ * Quote module setup class
+ *
  * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  * @codeCoverageIgnore
  */
@@ -75,9 +76,9 @@ class QuoteSetup extends EavSetup
      */
     protected function _flatTableExist($table)
     {
-        $tablesList = $this->getSetup()->getConnection(self::$connectionName)->listTables();
+        $tablesList = $this->getConnection()->listTables();
         return in_array(
-            strtoupper($this->getSetup()->getTable($table, self::$connectionName)),
+            strtoupper($this->getTable($table)),
             array_map('strtoupper', $tablesList)
         );
     }
@@ -115,15 +116,14 @@ class QuoteSetup extends EavSetup
      */
     protected function _addFlatAttribute($table, $attribute, $attr)
     {
-        $tableInfo = $this->getSetup()
-            ->getConnection(self::$connectionName)
-            ->describeTable($this->getSetup()->getTable($table, self::$connectionName));
+        $tableInfo = $this->getConnection()
+            ->describeTable($this->getTable($table));
         if (isset($tableInfo[$attribute])) {
             return $this;
         }
         $columnDefinition = $this->_getAttributeColumnDefinition($attribute, $attr);
-        $this->getSetup()->getConnection(self::$connectionName)->addColumn(
-            $this->getSetup()->getTable($table, self::$connectionName),
+        $this->getConnection()->addColumn(
+            $this->getTable($table),
             $attribute,
             $columnDefinition
         );
@@ -195,4 +195,25 @@ class QuoteSetup extends EavSetup
     {
         return $this->_encryptor;
     }
+
+    /**
+     * Get quote connection
+     *
+     * @return \Magento\Framework\DB\Adapter\AdapterInterface
+     */
+    public function getConnection()
+    {
+        return $this->getSetup()->getConnection(self::$connectionName);
+    }
+
+    /**
+     * Get table name
+     *
+     * @param string $table
+     * @return string
+     */
+    public function getTable($table)
+    {
+        return $this->getSetup()->getTable($table, self::$connectionName);
+    }
 }
diff --git a/app/code/Magento/Quote/Setup/UpgradeData.php b/app/code/Magento/Quote/Setup/UpgradeData.php
new file mode 100644
index 0000000000000000000000000000000000000000..5b9e3482081cd24d358fd2fa165b87c8081c7f75
--- /dev/null
+++ b/app/code/Magento/Quote/Setup/UpgradeData.php
@@ -0,0 +1,49 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Quote\Setup;
+
+use Magento\Framework\Setup\UpgradeDataInterface;
+use Magento\Framework\Setup\ModuleContextInterface;
+use Magento\Framework\Setup\ModuleDataSetupInterface;
+
+class UpgradeData implements UpgradeDataInterface
+{
+    /**
+     * @var QuoteSetupFactory
+     */
+    private $quoteSetupFactory;
+
+    /**
+     * @var ConvertSerializedDataToJsonFactory
+     */
+    private $convertSerializedDataToJsonFactory;
+
+    /**
+     * Constructor
+     *
+     * @param QuoteSetupFactory $quoteSetupFactory
+     * @param ConvertSerializedDataToJsonFactory $convertSerializedDataToJsonFactory
+     */
+    public function __construct(
+        QuoteSetupFactory $quoteSetupFactory,
+        ConvertSerializedDataToJsonFactory $convertSerializedDataToJsonFactory
+    ) {
+        $this->quoteSetupFactory = $quoteSetupFactory;
+        $this->convertSerializedDataToJsonFactory = $convertSerializedDataToJsonFactory;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
+    {
+        if (version_compare($context->getVersion(), '2.0.4', '<')) {
+            $quoteSetup = $this->quoteSetupFactory->create(['setup' => $setup]);
+            $this->convertSerializedDataToJsonFactory->create(['quoteSetup' => $quoteSetup])
+                ->convert();
+        }
+    }
+}
diff --git a/app/code/Magento/Quote/Test/Unit/Model/Quote/Address/TotalTest.php b/app/code/Magento/Quote/Test/Unit/Model/Quote/Address/TotalTest.php
index efe6a81ce9242f510561f54cd6b484a336b37dbf..b29fbe698811c7d98bd9b2e0e5ce8103a84b0dbb 100644
--- a/app/code/Magento/Quote/Test/Unit/Model/Quote/Address/TotalTest.php
+++ b/app/code/Magento/Quote/Test/Unit/Model/Quote/Address/TotalTest.php
@@ -15,7 +15,22 @@ class TotalTest extends \PHPUnit_Framework_TestCase
 
     protected function setUp()
     {
-        $this->model = new \Magento\Quote\Model\Quote\Address\Total();
+        $serializer = $this->getMockBuilder(\Magento\Framework\Serialize\Serializer\Json::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+        $serializer->expects($this->any())
+            ->method('unserialize')
+            ->willReturnCallback(function ($value) {
+                return json_decode($value, true);
+            });
+
+        $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+        $this->model = $objectManagerHelper->getObject(
+            \Magento\Quote\Model\Quote\Address\Total::class,
+            [
+                'serializer' => $serializer
+            ]
+        );
     }
 
     /**
@@ -171,6 +186,7 @@ class TotalTest extends \PHPUnit_Framework_TestCase
     /**
      * Verify handling of serialized, non-serialized input into and out of getFullInfo()
      *
+     * @covers \Magento\Quote\Model\Quote\Address\Total::getFullInfo()
      * @param $input
      * @param $expected
      * @dataProvider getFullInfoDataProvider
@@ -187,7 +203,7 @@ class TotalTest extends \PHPUnit_Framework_TestCase
     public function getFullInfoDataProvider()
     {
         $myArray = ['team' => 'kiwis'];
-        $serializedInput = serialize($myArray);
+        $serializedInput = json_encode($myArray);
 
         return [
             'simple array' => [
diff --git a/app/code/Magento/Quote/Test/Unit/Model/Quote/AddressTest.php b/app/code/Magento/Quote/Test/Unit/Model/Quote/AddressTest.php
index 7a8ccb232ba06690780323988374b26ba644f2fc..507b2b00203d0ea95bb3bfe41f1dec39c3407778 100644
--- a/app/code/Magento/Quote/Test/Unit/Model/Quote/AddressTest.php
+++ b/app/code/Magento/Quote/Test/Unit/Model/Quote/AddressTest.php
@@ -32,16 +32,23 @@ class AddressTest extends \PHPUnit_Framework_TestCase
      */
     private $scopeConfig;
 
+    /**
+     * @var \Magento\Framework\Serialize\Serializer\Json | \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $serializer;
+
     protected function setUp()
     {
         $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
 
         $this->scopeConfig = $this->getMock(\Magento\Framework\App\Config::class, [], [], '', false);
+        $this->serializer = $this->getMock(\Magento\Framework\Serialize\Serializer\Json::class, [], [], '', false);
 
         $this->address = $objectManager->getObject(
             \Magento\Quote\Model\Quote\Address::class,
             [
-                'scopeConfig' => $this->scopeConfig
+                'scopeConfig' => $this->scopeConfig,
+                'serializer' => $this->serializer
             ]
         );
         $this->quote = $this->getMock(\Magento\Quote\Model\Quote::class, [], [], '', false);
@@ -134,4 +141,23 @@ class AddressTest extends \PHPUnit_Framework_TestCase
 
         $this->assertTrue($this->address->validateMinimumAmount());
     }
+
+    public function testSetAndGetAppliedTaxes()
+    {
+        $data = ['data'];
+        $result = json_encode($data);
+
+        $this->serializer->expects($this->once())
+            ->method('serialize')
+            ->with($data)
+            ->willReturn($result);
+
+        $this->serializer->expects($this->once())
+            ->method('unserialize')
+            ->with($result)
+            ->willReturn($data);
+
+        $this->assertInstanceOf(\Magento\Quote\Model\Quote\Address::class, $this->address->setAppliedTaxes($data));
+        $this->assertEquals($data, $this->address->getAppliedTaxes());
+    }
 }
diff --git a/app/code/Magento/Quote/Test/Unit/Model/Quote/Item/CompareTest.php b/app/code/Magento/Quote/Test/Unit/Model/Quote/Item/CompareTest.php
index f8b72e4df6b7c00dbef493def4072d07bf037eaf..1811a2e4ce6a80f7f464114eb7c92067f4a8053c 100644
--- a/app/code/Magento/Quote/Test/Unit/Model/Quote/Item/CompareTest.php
+++ b/app/code/Magento/Quote/Test/Unit/Model/Quote/Item/CompareTest.php
@@ -38,29 +38,42 @@ class CompareTest extends \PHPUnit_Framework_TestCase
      */
     protected function setUp()
     {
-        $this->itemMock = $this->getMock(
+        $this->itemMock = $this->getMock(
             \Magento\Quote\Model\Quote\Item::class,
             ['__wakeup', 'getProductId', 'getOptions'],
             [],
             '',
             false
         );
-        $this->comparedMock = $this->getMock(
+        $this->comparedMock = $this->getMock(
             \Magento\Quote\Model\Quote\Item::class,
             ['__wakeup', 'getProductId', 'getOptions'],
             [],
             '',
             false
         );
-        $this->optionMock = $this->getMock(
+        $this->optionMock = $this->getMock(
             \Magento\Quote\Model\Quote\Item\Option::class,
             ['__wakeup', 'getCode', 'getValue'],
             [],
             '',
             false
         );
-
-        $this->helper = new \Magento\Quote\Model\Quote\Item\Compare();
+        $serializer = $this->getMockBuilder(\Magento\Framework\Serialize\Serializer\Json::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+        $serializer->expects($this->any())
+            ->method('unserialize')
+            ->willReturnCallback(function ($value) {
+                return json_decode($value, true);
+            });
+
+        $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+        $this->helper = $objectManagerHelper->getObject(
+            \Magento\Quote\Model\Quote\Item\Compare::class,
+            [
+                'serializer' => $serializer
+            ]);
     }
 
     /**
@@ -112,7 +125,7 @@ class CompareTest extends \PHPUnit_Framework_TestCase
             ->will($this->returnValue([
                     $this->getOptionMock('option-1', 1),
                     $this->getOptionMock('option-2', 'option-value'),
-                    $this->getOptionMock('option-3', serialize([
+                    $this->getOptionMock('option-3', json_encode([
                             'value' => 'value-1',
                             'qty' => 2,
                         ])
@@ -123,7 +136,7 @@ class CompareTest extends \PHPUnit_Framework_TestCase
             ->will($this->returnValue([
                     $this->getOptionMock('option-4', 1),
                     $this->getOptionMock('option-2', 'option-value'),
-                    $this->getOptionMock('option-3', serialize([
+                    $this->getOptionMock('option-3', json_encode([
                         'value' => 'value-1',
                         'qty' => 2,
                     ])),
@@ -148,7 +161,7 @@ class CompareTest extends \PHPUnit_Framework_TestCase
             ->will($this->returnValue([
                     $this->getOptionMock('option-1', 1),
                     $this->getOptionMock('option-2', 'option-value'),
-                    $this->getOptionMock('option-3', serialize([
+                    $this->getOptionMock('option-3', json_encode([
                             'value' => 'value-1',
                             'qty' => 2,
                         ])
@@ -176,7 +189,7 @@ class CompareTest extends \PHPUnit_Framework_TestCase
             ->will($this->returnValue([
                     $this->getOptionMock('option-1', 1),
                     $this->getOptionMock('option-2', 'option-value'),
-                    $this->getOptionMock('option-3', serialize([
+                    $this->getOptionMock('option-3', json_encode([
                             'value' => 'value-1',
                             'qty' => 2,
                         ])
@@ -201,13 +214,13 @@ class CompareTest extends \PHPUnit_Framework_TestCase
             ->will($this->returnValue(1));
 
         $this->itemMock->expects($this->once())->method('getOptions')->willReturn([
-            $this->getOptionMock('option-1', serialize([
+            $this->getOptionMock('option-1', json_encode([
                 'non-empty-option' => 'test',
                 'empty_option' => ''
             ]))
         ]);
         $this->comparedMock->expects($this->once())->method('getOptions')->willReturn([
-            $this->getOptionMock('option-1', serialize([
+            $this->getOptionMock('option-1', json_encode([
                 'non-empty-option' => 'test'
             ]))
         ]);
diff --git a/app/code/Magento/Quote/Test/Unit/Model/Quote/Item/UpdaterTest.php b/app/code/Magento/Quote/Test/Unit/Model/Quote/Item/UpdaterTest.php
index fc86df0819e68bdf63c89202574400fa651613ca..ebf857fd0f1fa7b378fd76c7637ca91763051bdf 100644
--- a/app/code/Magento/Quote/Test/Unit/Model/Quote/Item/UpdaterTest.php
+++ b/app/code/Magento/Quote/Test/Unit/Model/Quote/Item/UpdaterTest.php
@@ -38,6 +38,11 @@ class UpdaterTest extends \PHPUnit_Framework_TestCase
      */
     protected $productMock;
 
+    /**
+     * @var \Magento\Framework\Serialize\Serializer\Json
+     */
+    private $serializer;
+
     protected function setUp()
     {
         $this->productMock = $this->getMock(
@@ -94,12 +99,16 @@ class UpdaterTest extends \PHPUnit_Framework_TestCase
             '',
             false
         );
+        $this->serializer = $this->getMockBuilder(\Magento\Framework\Serialize\Serializer\Json::class)
+            ->setMethods(['serialize'])
+            ->getMockForAbstractClass();
 
         $this->object = (new ObjectManager($this))
             ->getObject(
                 \Magento\Quote\Model\Quote\Item\Updater::class,
                 [
-                    'localeFormat' => $this->localeFormat
+                    'localeFormat' => $this->localeFormat,
+                    'serializer' => $this->serializer
                 ]
             );
     }
@@ -226,6 +235,9 @@ class UpdaterTest extends \PHPUnit_Framework_TestCase
         $this->object->update($this->itemMock, ['qty' => 3, 'use_discount' => true]);
     }
 
+    /**
+     * @covers \Magento\Quote\Model\Quote\Item\Updater::setCustomPrice()
+     */
     public function testUpdateCustomPrice()
     {
         $customPrice = 9.99;
@@ -249,10 +261,12 @@ class UpdaterTest extends \PHPUnit_Framework_TestCase
         $buyRequestMock->expects($this->any())
             ->method('getData')
             ->will($this->returnValue(['custom_price' => $customPrice]));
-
+        $this->serializer->expects($this->any())
+            ->method('serialize')
+            ->willReturn(json_encode($buyRequestMock->getData()));
         $buyRequestMock->expects($this->any())
             ->method('setValue')
-            ->with($this->equalTo(serialize(['custom_price' => $customPrice])));
+            ->with($this->equalTo('{"custom_price":' . $customPrice . '}'));
         $buyRequestMock->expects($this->any())
             ->method('setCode')
             ->with($this->equalTo('info_buyRequest'));
@@ -293,6 +307,9 @@ class UpdaterTest extends \PHPUnit_Framework_TestCase
         $this->object->update($this->itemMock, ['qty' => $qty, 'custom_price' => $customPrice]);
     }
 
+    /**
+     * @covers \Magento\Quote\Model\Quote\Item\Updater::unsetCustomPrice()
+     */
     public function testUpdateUnsetCustomPrice()
     {
         $qty = 3;
@@ -313,6 +330,14 @@ class UpdaterTest extends \PHPUnit_Framework_TestCase
         );
         $buyRequestMock->expects($this->never())->method('setCustomPrice');
         $buyRequestMock->expects($this->once())->method('getData')->will($this->returnValue([]));
+        $serializer = $this->getMockBuilder(\Magento\Framework\Serialize\Serializer\Json::class)
+            ->setMethods(['serialize'])
+            ->getMockForAbstractClass();
+        $serializer->expects($this->any())
+            ->method('serialize')
+            ->willReturn('{}');
+        $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+        $objectManagerHelper->setBackwardCompatibleProperty($this->object, 'serializer', $serializer);
         $buyRequestMock->expects($this->once())->method('unsetData')->with($this->equalTo('custom_price'));
         $buyRequestMock->expects($this->once())
             ->method('hasData')
@@ -321,7 +346,7 @@ class UpdaterTest extends \PHPUnit_Framework_TestCase
 
         $buyRequestMock->expects($this->any())
             ->method('setValue')
-            ->with($this->equalTo(serialize([])));
+            ->with($this->equalTo('{}'));
         $buyRequestMock->expects($this->any())
             ->method('setCode')
             ->with($this->equalTo('info_buyRequest'));
diff --git a/app/code/Magento/Quote/Test/Unit/Model/Quote/ItemTest.php b/app/code/Magento/Quote/Test/Unit/Model/Quote/ItemTest.php
index 7e07fcddf4abaafb572a67034f58f936500e7bdb..b012d7db61f004c16f2f5e711ea3c9267ea143a0 100644
--- a/app/code/Magento/Quote/Test/Unit/Model/Quote/ItemTest.php
+++ b/app/code/Magento/Quote/Test/Unit/Model/Quote/ItemTest.php
@@ -61,6 +61,11 @@ class ItemTest extends \PHPUnit_Framework_TestCase
      */
     protected $stockRegistry;
 
+    /**
+     * @var \Magento\Framework\Serialize\Serializer\Json
+     */
+    private $serializer;
+
     const PRODUCT_ID = 1;
     const PRODUCT_TYPE = 'simple';
     const PRODUCT_SKU = '12345';
@@ -134,6 +139,10 @@ class ItemTest extends \PHPUnit_Framework_TestCase
             ->method('getStockItem')
             ->will($this->returnValue($this->stockItemMock));
 
+        $this->serializer = $this->getMockBuilder(\Magento\Framework\Serialize\Serializer\Json::class)
+            ->setMethods(['unserialize'])
+            ->getMockForAbstractClass();
+
         $this->model = $this->objectManagerHelper->getObject(
             \Magento\Quote\Model\Quote\Item::class,
             [
@@ -142,7 +151,8 @@ class ItemTest extends \PHPUnit_Framework_TestCase
                 'statusListFactory' => $statusListFactory,
                 'itemOptionFactory' => $this->itemOptionFactory,
                 'quoteItemCompare' => $this->compareHelper,
-                'stockRegistry' => $this->stockRegistry
+                'stockRegistry' => $this->stockRegistry,
+                'serializer' => $this->serializer
             ]
         );
     }
@@ -1058,9 +1068,9 @@ class ItemTest extends \PHPUnit_Framework_TestCase
         $optionMock->expects($this->exactly(3))
             ->method('getCode')
             ->will($this->returnValue($optionCode));
-        $optionMock->expects($this->once())
+        $optionMock->expects($this->any())
             ->method('getValue')
-            ->will($this->returnValue(serialize(['qty' => $buyRequestQuantity])));
+            ->will($this->returnValue('{"qty":23}'));
 
         $this->model->addOption($optionMock);
 
@@ -1071,6 +1081,9 @@ class ItemTest extends \PHPUnit_Framework_TestCase
             ->will($this->returnValue($quantity));
         $this->model->setQty($quantity);
         $this->assertEquals($quantity, $this->model->getQty());
+        $this->serializer->expects($this->any())
+            ->method('unserialize')
+            ->willReturn(json_decode($optionMock->getValue(), true));
         $buyRequest = $this->model->getBuyRequest();
         $this->assertEquals($buyRequestQuantity, $buyRequest->getOriginalQty());
         $this->assertEquals($quantity, $buyRequest->getQty());
diff --git a/app/code/Magento/Quote/Test/Unit/Model/Quote/PaymentTest.php b/app/code/Magento/Quote/Test/Unit/Model/Quote/PaymentTest.php
index cc23683cb481bce0a8acc53a1b923c75ccf1eada..b710dba828a4c007432c5087a1cda0c9d0af06ea 100644
--- a/app/code/Magento/Quote/Test/Unit/Model/Quote/PaymentTest.php
+++ b/app/code/Magento/Quote/Test/Unit/Model/Quote/PaymentTest.php
@@ -41,12 +41,21 @@ class PaymentTest extends \PHPUnit_Framework_TestCase
         )->disableOriginalConstructor()
             ->getMock();
         $this->eventManager = $this->getMock(ManagerInterface::class);
+        $serializer = $this->getMockBuilder(\Magento\Framework\Serialize\Serializer\Json::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+        $serializer->expects($this->any())
+            ->method('unserialize')
+            ->willReturnCallback(function ($value) {
+                return json_decode($value, true);
+            });
 
         $this->model = $objectManager->getObject(
             Payment::class,
             [
                 'methodSpecificationFactory' => $this->specificationFactory,
-                'eventDispatcher' => $this->eventManager
+                'eventDispatcher' => $this->eventManager,
+                'serializer' => $serializer
             ]
         );
     }
@@ -144,6 +153,55 @@ class PaymentTest extends \PHPUnit_Framework_TestCase
         $this->model->importData($data);
     }
 
+    /**
+     * @covers \Magento\Quote\Model\Quote\Payment::getAdditionalData()
+     * @dataProvider getAdditionalDataDataProvider
+     * @param mixed $expected
+     * @param mixed $additionalData
+     */
+    public function testGetAdditionalData($expected, $additionalData)
+    {
+        $this->model->setData(Payment::KEY_ADDITIONAL_DATA, $additionalData);
+        $this->assertSame($expected, $this->model->getAdditionalData());
+    }
+
+    /**
+     * @return array
+     */
+    public function getAdditionalDataDataProvider()
+    {
+        return [
+            // Variation #1
+            [
+                //$expected
+                ['field1' => 'value1', 'field2' => 'value2'],
+                //$additionalData
+                ['field1' => 'value1', 'field2' => 'value2'],
+            ],
+            // Variation #2
+            [
+                //$expected
+                ['field1' => 'value1', 'field2' => 'value2'],
+                //$additionalData
+                '{"field1":"value1","field2":"value2"}',
+            ],
+            // Variation #3
+            [
+                //$expected
+                null,
+                //$additionalData
+                '{"field1":field2":"value2"}',
+            ],
+            // Variation #4
+            [
+                //$expected
+                null,
+                //$additionalData
+                123,
+            ],
+        ];
+    }
+
     /**
      * @return array
      */
diff --git a/app/code/Magento/Quote/etc/module.xml b/app/code/Magento/Quote/etc/module.xml
index 281cde9eeb9d18bc559cd0979e593a43c3b70ebb..52c92cf2d912a95f413634be2fa20976929462b3 100644
--- a/app/code/Magento/Quote/etc/module.xml
+++ b/app/code/Magento/Quote/etc/module.xml
@@ -6,6 +6,6 @@
  */
 -->
 <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
-    <module name="Magento_Quote" setup_version="2.0.3">
+    <module name="Magento_Quote" setup_version="2.0.4">
     </module>
 </config>
diff --git a/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Items/Grid.php b/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Items/Grid.php
index 3af13c7b1ead281347a901a9993a2010ee1e7cb3..d5d0da9c4676cb06c68d1ca0867f16f8ed9cb283 100644
--- a/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Items/Grid.php
+++ b/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Items/Grid.php
@@ -425,6 +425,8 @@ class Grid extends \Magento\Sales\Block\Adminhtml\Order\Create\AbstractCreate
      *
      * @param Item $item
      * @return string
+     *
+     * @deprecated
      */
     public function getCustomOptions(Item $item)
     {
diff --git a/app/code/Magento/Sales/Controller/Download/DownloadCustomOption.php b/app/code/Magento/Sales/Controller/Download/DownloadCustomOption.php
index a2dcebe8440b1479cf4557495b2d5abb68124f62..951fef40b8e3566cd96ac6012e877aa8257e2c00 100644
--- a/app/code/Magento/Sales/Controller/Download/DownloadCustomOption.php
+++ b/app/code/Magento/Sales/Controller/Download/DownloadCustomOption.php
@@ -1,17 +1,20 @@
 <?php
 /**
- *
  * Copyright © 2016 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
+
 namespace Magento\Sales\Controller\Download;
 
-use Magento\Sales\Model\Download;
+use Magento\Framework\App\ObjectManager;
 use Magento\Framework\App\Action\Context;
 use Magento\Catalog\Model\Product\Type\AbstractType;
 use Magento\Framework\Controller\Result\ForwardFactory;
-use \Magento\Framework\Unserialize\Unserialize;
 
+/**
+ * Class DownloadCustomOption
+ * @package Magento\Sales\Controller\Download
+ */
 class DownloadCustomOption extends \Magento\Framework\App\Action\Action
 {
     /**
@@ -20,31 +23,42 @@ class DownloadCustomOption extends \Magento\Framework\App\Action\Action
     protected $resultForwardFactory;
 
     /**
-     * @var Download
+     * @var \Magento\Sales\Model\Download
      */
     protected $download;
 
     /**
-     * @var Unserialize
+     * @var \Magento\Framework\Unserialize\Unserialize
+     * @deprecated
      */
     protected $unserialize;
 
+    /**
+     * @var \Magento\Framework\Serialize\Serializer\Json
+     */
+    private $serializer;
+
     /**
      * @param Context $context
      * @param ForwardFactory $resultForwardFactory
-     * @param Download $download
-     * @param Unserialize $unserialize
+     * @param \Magento\Sales\Model\Download $download
+     * @param \Magento\Framework\Unserialize\Unserialize $unserialize
+     * @param \Magento\Framework\Serialize\Serializer\Json $serializer
      */
     public function __construct(
         Context $context,
         ForwardFactory $resultForwardFactory,
-        Download $download,
-        Unserialize $unserialize
+        \Magento\Sales\Model\Download $download,
+        \Magento\Framework\Unserialize\Unserialize $unserialize,
+        \Magento\Framework\Serialize\Serializer\Json $serializer = null
     ) {
         parent::__construct($context);
         $this->resultForwardFactory = $resultForwardFactory;
         $this->download = $download;
         $this->unserialize = $unserialize;
+        $this->serializer = $serializer ?: ObjectManager::getInstance()->get(
+            \Magento\Framework\Serialize\Serializer\Json::class
+        );
     }
 
     /**
@@ -88,7 +102,7 @@ class DownloadCustomOption extends \Magento\Framework\App\Action\Action
         }
 
         try {
-            $info = $this->unserialize->unserialize($option->getValue());
+            $info = $this->serializer->unserialize($option->getValue());
             if ($this->getRequest()->getParam('key') != $info['secret_key']) {
                 return $resultForward->forward('noroute');
             }
diff --git a/app/code/Magento/Sales/Model/AdminOrder/Create.php b/app/code/Magento/Sales/Model/AdminOrder/Create.php
index 3715c02357a964bef3502a461db30574d6655ba1..a64d081ffd16041003bc73b78dc473610e4a55c1 100644
--- a/app/code/Magento/Sales/Model/AdminOrder/Create.php
+++ b/app/code/Magento/Sales/Model/AdminOrder/Create.php
@@ -224,6 +224,13 @@ class Create extends \Magento\Framework\DataObject implements \Magento\Checkout\
      */
     protected $quoteFactory;
 
+    /**
+     * Serializer interface instance.
+     *
+     * @var \Magento\Framework\Serialize\Serializer\Json
+     */
+    private $serializer;
+
     /**
      * @param \Magento\Framework\ObjectManagerInterface $objectManager
      * @param \Magento\Framework\Event\ManagerInterface $eventManager
@@ -253,6 +260,7 @@ class Create extends \Magento\Framework\DataObject implements \Magento\Checkout\
      * @param \Magento\Sales\Api\OrderManagementInterface $orderManagement
      * @param \Magento\Quote\Model\QuoteFactory $quoteFactory
      * @param array $data
+     * @param \Magento\Framework\Serialize\Serializer\Json|null $serializer
      * @SuppressWarnings(PHPMD.ExcessiveParameterList)
      */
     public function __construct(
@@ -283,7 +291,8 @@ class Create extends \Magento\Framework\DataObject implements \Magento\Checkout\
         \Magento\Framework\Api\DataObjectHelper $dataObjectHelper,
         \Magento\Sales\Api\OrderManagementInterface $orderManagement,
         \Magento\Quote\Model\QuoteFactory $quoteFactory,
-        array $data = []
+        array $data = [],
+        \Magento\Framework\Serialize\Serializer\Json $serializer = null
     ) {
         $this->_objectManager = $objectManager;
         $this->_eventManager = $eventManager;
@@ -312,6 +321,8 @@ class Create extends \Magento\Framework\DataObject implements \Magento\Checkout\
         $this->dataObjectHelper = $dataObjectHelper;
         $this->orderManagement = $orderManagement;
         $this->quoteFactory = $quoteFactory;
+        $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance()
+            ->get(\Magento\Framework\Serialize\Serializer\Json::class);
         parent::__construct($data);
     }
 
@@ -632,7 +643,7 @@ class Create extends \Magento\Framework\DataObject implements \Magento\Checkout\
                         [
                             'product' => $item->getProduct(),
                             'code' => 'additional_options',
-                            'value' => serialize($additionalOptions)
+                            'value' => $this->serializer->serialize($additionalOptions)
                         ]
                     )
                 );
@@ -794,7 +805,9 @@ class Create extends \Magento\Framework\DataObject implements \Magento\Checkout\
 
                         $info = $item->getOptionByCode('info_buyRequest');
                         if ($info) {
-                            $info = new \Magento\Framework\DataObject(unserialize($info->getValue()));
+                            $info = new \Magento\Framework\DataObject(
+                                $this->serializer->unserialize($info->getValue())
+                            );
                             $info->setQty($qty);
                             $info->setOptions($this->_prepareOptionsForRequest($item));
                         } else {
@@ -1102,6 +1115,8 @@ class Create extends \Magento\Framework\DataObject implements \Magento\Checkout\
      * @param string $additionalOptions
      * @return array
      * @throws \Magento\Framework\Exception\LocalizedException
+     *
+     * @deprecated
      */
     protected function _parseOptions(\Magento\Quote\Model\Quote\Item $item, $additionalOptions)
     {
@@ -1166,6 +1181,8 @@ class Create extends \Magento\Framework\DataObject implements \Magento\Checkout\
      * @param \Magento\Quote\Model\Quote\Item $item
      * @param array $options
      * @return $this
+     *
+     * @deprecated
      */
     protected function _assignOptionsToItem(\Magento\Quote\Model\Quote\Item $item, $options)
     {
@@ -1209,7 +1226,7 @@ class Create extends \Magento\Framework\DataObject implements \Magento\Checkout\
                     [
                         'product' => $item->getProduct(),
                         'code' => 'additional_options',
-                        'value' => serialize($options['additional_options'])
+                        'value' => $this->serializer->serialize($options['additional_options'])
                     ]
                 )
             );
@@ -1844,7 +1861,7 @@ class Create extends \Magento\Framework\DataObject implements \Magento\Checkout\
             }
             $addOptions = $item->getOptionByCode('additional_options');
             if ($addOptions) {
-                $options['additional_options'] = unserialize($addOptions->getValue());
+                $options['additional_options'] = $this->serializer->unserialize($addOptions->getValue());
             }
             $item->setProductOrderOptions($options);
         }
diff --git a/app/code/Magento/Sales/Model/Order/Config.php b/app/code/Magento/Sales/Model/Order/Config.php
index 535e2975ee13da8458cba83666ba49abb942a89a..48021fedc03f8f3422af2bdcba4ffa15920861d5 100644
--- a/app/code/Magento/Sales/Model/Order/Config.php
+++ b/app/code/Magento/Sales/Model/Order/Config.php
@@ -192,7 +192,7 @@ class Config
      */
     public function getStateStatuses($state, $addLabels = true)
     {
-        $key = md5(serialize([$state, $addLabels]));
+        $key = sha1(json_encode([$state, $addLabels]));
         if (isset($this->stateStatuses[$key])) {
             return $this->stateStatuses[$key];
         }
diff --git a/app/code/Magento/Sales/Model/Order/CreditmemoFactory.php b/app/code/Magento/Sales/Model/Order/CreditmemoFactory.php
index ff687074e4a66cc50c457c685fc1757d1529dcb6..75f100a93e4a315efd4a1d0baa89c9daffa85e4c 100644
--- a/app/code/Magento/Sales/Model/Order/CreditmemoFactory.php
+++ b/app/code/Magento/Sales/Model/Order/CreditmemoFactory.php
@@ -24,21 +24,32 @@ class CreditmemoFactory
 
     /**
      * @var \Magento\Framework\Unserialize\Unserialize
+     * @deprecated
      */
     protected $unserialize;
 
+    /**
+     * @var \Magento\Framework\Serialize\Serializer\Json
+     */
+    private $serializer;
+
     /**
      * Factory constructor
      *
      * @param \Magento\Sales\Model\Convert\OrderFactory $convertOrderFactory
      * @param \Magento\Tax\Model\Config $taxConfig
+     * @param \Magento\Framework\Serialize\Serializer\Json $serializer
      */
     public function __construct(
         \Magento\Sales\Model\Convert\OrderFactory $convertOrderFactory,
-        \Magento\Tax\Model\Config $taxConfig
+        \Magento\Tax\Model\Config $taxConfig,
+        \Magento\Framework\Serialize\Serializer\Json $serializer = null
     ) {
         $this->convertor = $convertOrderFactory->create();
         $this->taxConfig = $taxConfig;
+        $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance()->get(
+            \Magento\Framework\Serialize\Serializer\Json::class
+        );
     }
 
     /**
@@ -262,7 +273,7 @@ class CreditmemoFactory
 
     /**
      * @param \Magento\Sales\Api\Data\OrderItemInterface $orderItem
-     * @param array $qtys
+     * @param int $parentQty
      * @return int
      */
     private function calculateProductOptions(\Magento\Sales\Api\Data\OrderItemInterface $orderItem, $parentQty)
@@ -270,7 +281,7 @@ class CreditmemoFactory
         $qty = $parentQty;
         $productOptions = $orderItem->getProductOptions();
         if (isset($productOptions['bundle_selection_attributes'])) {
-            $bundleSelectionAttributes = $this->getUnserialize()
+            $bundleSelectionAttributes = $this->serializer
                 ->unserialize($productOptions['bundle_selection_attributes']);
             if ($bundleSelectionAttributes) {
                 $qty = $bundleSelectionAttributes['qty'] * $parentQty;
@@ -278,19 +289,4 @@ class CreditmemoFactory
         }
         return $qty;
     }
-
-    /**
-     * Get Unserialize
-     *
-     * @return \Magento\Framework\Unserialize\Unserialize
-     * @deprecated
-     */
-    private function getUnserialize()
-    {
-        if (!$this->unserialize) {
-            $this->unserialize = \Magento\Framework\App\ObjectManager::getInstance()
-                ->get(\Magento\Framework\Unserialize\Unserialize::class);
-        }
-        return $this->unserialize;
-    }
 }
diff --git a/app/code/Magento/Sales/Model/Order/Item.php b/app/code/Magento/Sales/Model/Order/Item.php
index 10ba1e16621448ddee118c16d7debbf58ca04e06..caf3352de0ee018fcc9c2dd475ce627761f15d2b 100644
--- a/app/code/Magento/Sales/Model/Order/Item.php
+++ b/app/code/Magento/Sales/Model/Order/Item.php
@@ -95,6 +95,13 @@ class Item extends AbstractModel implements OrderItemInterface
      */
     protected $_storeManager;
 
+    /**
+     * Serializer interface instance.
+     *
+     * @var \Magento\Framework\Serialize\Serializer\Json
+     */
+    private $serializer;
+
     /**
      * Initialize dependencies.
      *
@@ -108,6 +115,7 @@ class Item extends AbstractModel implements OrderItemInterface
      * @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource
      * @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection
      * @param array $data
+     * @param \Magento\Framework\Serialize\Serializer\Json|null $serializer
      * @SuppressWarnings(PHPMD.ExcessiveParameterList)
      */
     public function __construct(
@@ -120,7 +128,8 @@ class Item extends AbstractModel implements OrderItemInterface
         \Magento\Catalog\Api\ProductRepositoryInterface $productRepository,
         \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
         \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
-        array $data = []
+        array $data = [],
+        \Magento\Framework\Serialize\Serializer\Json $serializer = null
     ) {
         parent::__construct(
             $context,
@@ -131,6 +140,8 @@ class Item extends AbstractModel implements OrderItemInterface
             $resourceCollection,
             $data
         );
+        $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance()
+            ->get(\Magento\Framework\Serialize\Serializer\Json::class);
         $this->_orderFactory = $orderFactory;
         $this->_storeManager = $storeManager;
         $this->productRepository = $productRepository;
@@ -466,7 +477,7 @@ class Item extends AbstractModel implements OrderItemInterface
     public function getProductOptions()
     {
         $data = $this->_getData('product_options');
-        return is_string($data) ? unserialize($data) : $data;
+        return is_string($data) ? $this->serializer->unserialize($data) : $data;
     }
 
     /**
diff --git a/app/code/Magento/Sales/Model/Order/ShipmentFactory.php b/app/code/Magento/Sales/Model/Order/ShipmentFactory.php
index a8839c75375870ce03294ca3d585635fdff84f14..cde0efcb8e0fef361a328ed1317973332a264db3 100644
--- a/app/code/Magento/Sales/Model/Order/ShipmentFactory.php
+++ b/app/code/Magento/Sales/Model/Order/ShipmentFactory.php
@@ -8,6 +8,7 @@ namespace Magento\Sales\Model\Order;
 use Magento\Framework\App\ObjectManager;
 use Magento\Framework\Exception\LocalizedException;
 use Magento\Sales\Model\Order\Shipment\ShipmentValidatorInterface;
+use Magento\Framework\Serialize\Serializer\Json;
 
 /**
  * Factory class for @see \Magento\Sales\Api\Data\ShipmentInterface
@@ -35,19 +36,30 @@ class ShipmentFactory
      */
     protected $instanceName;
 
+    /**
+     * Serializer
+     *
+     * @var Json
+     */
+    private $serializer;
+
     /**
      * Factory constructor.
      *
      * @param \Magento\Sales\Model\Convert\OrderFactory $convertOrderFactory
      * @param \Magento\Sales\Model\Order\Shipment\TrackFactory $trackFactory
+     * @param \Magento\Framework\Serialize\Serializer\Json $serializer
      */
     public function __construct(
         \Magento\Sales\Model\Convert\OrderFactory $convertOrderFactory,
-        \Magento\Sales\Model\Order\Shipment\TrackFactory $trackFactory
+        \Magento\Sales\Model\Order\Shipment\TrackFactory $trackFactory,
+        Json $serializer = null
     ) {
         $this->converter = $convertOrderFactory->create();
         $this->trackFactory = $trackFactory;
         $this->instanceName = \Magento\Sales\Api\Data\ShipmentInterface::class;
+        $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance()
+            ->get(Json::class);
     }
 
     /**
@@ -100,7 +112,7 @@ class ShipmentFactory
                     $productOptions = $orderItem->getProductOptions();
 
                     if (isset($productOptions['bundle_selection_attributes'])) {
-                        $bundleSelectionAttributes = unserialize(
+                        $bundleSelectionAttributes = $this->serializer->unserialize(
                             $productOptions['bundle_selection_attributes']
                         );
 
diff --git a/app/code/Magento/Sales/Setup/ConvertSerializedDataToJson.php b/app/code/Magento/Sales/Setup/ConvertSerializedDataToJson.php
new file mode 100644
index 0000000000000000000000000000000000000000..7fe2e2743e132244d62f98a38ed91cc4f0ffd337
--- /dev/null
+++ b/app/code/Magento/Sales/Setup/ConvertSerializedDataToJson.php
@@ -0,0 +1,113 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Setup;
+
+use Magento\Framework\DB\FieldDataConverterFactory;
+use Magento\Framework\DB\DataConverter\SerializedToJson;
+use Magento\Framework\DB\FieldDataConverter;
+
+/**
+ *  Convert serialized data in sales tables to JSON
+ */
+class ConvertSerializedDataToJson
+{
+    /**
+     * @var SalesSetup
+     */
+    private $salesSetup;
+
+    /**
+     * @var FieldDataConverterFactory
+     */
+    private $fieldDataConverterFactory;
+
+    /**
+     * @var array
+     */
+    private $fieldDataConverters = [];
+
+    /**
+     * @var array
+     */
+    private $fieldsToUpdate = [
+        [
+            'table' => 'sales_order_item',
+            'identifier' => 'item_id',
+            'title' => 'product_options',
+            'data_converter' => SerializedDataConverter::class
+        ],
+        [
+            'table' => 'sales_shipment',
+            'identifier' => 'entity_id',
+            'title' => 'packages',
+            'data_converter' => SerializedToJson::class
+        ],
+        [
+            'table' => 'sales_order_payment',
+            'identifier' => 'entity_id',
+            'title' => 'additional_information',
+            'data_converter' => SerializedToJson::class
+        ],
+        [
+            'table' => 'sales_payment_transaction',
+            'identifier' => 'transaction_id',
+            'title' => 'additional_information',
+            'data_converter' => SerializedToJson::class
+        ]
+    ];
+
+    /**
+     * Constructor
+     *
+     * @param SalesSetup $salesSetup
+     * @param FieldDataConverterFactory $fieldDataConverterFactory
+     */
+    public function __construct(
+        SalesSetup $salesSetup,
+        FieldDataConverterFactory $fieldDataConverterFactory
+    ) {
+        $this->salesSetup = $salesSetup;
+        $this->fieldDataConverterFactory = $fieldDataConverterFactory;
+    }
+
+    /**
+     * Convert data for the following fields from serialized to JSON format:
+     * sales_order_item.product_options
+     * sales_shipment.packages
+     * sales_order_payment.additional_information
+     * sales_payment_transaction.additional_information
+     *
+     * @return void
+     */
+    public function convert()
+    {
+        foreach ($this->fieldsToUpdate as $field) {
+            $fieldDataConverter = $this->getFieldDataConverter($field['data_converter']);
+            $fieldDataConverter->convert(
+                $this->salesSetup->getConnection(),
+                $this->salesSetup->getTable($field['table']),
+                $field['identifier'],
+                $field['title']
+            );
+        }
+    }
+
+    /**
+     * Get field data converter
+     *
+     * @param string $dataConverterClassName
+     * @return FieldDataConverter
+     */
+    private function getFieldDataConverter($dataConverterClassName)
+    {
+        if (!isset($this->fieldDataConverters[$dataConverterClassName])) {
+            $this->fieldDataConverters[$dataConverterClassName] = $this->fieldDataConverterFactory->create(
+                $dataConverterClassName
+            );
+        }
+        return $this->fieldDataConverters[$dataConverterClassName];
+    }
+}
diff --git a/app/code/Magento/Sales/Setup/SalesSetup.php b/app/code/Magento/Sales/Setup/SalesSetup.php
index 3a2c999678a03e4115c867620092438cf27628b3..80b1ec4e8dc5fd2c171edc2e3ce8d5da8ebb9cff 100644
--- a/app/code/Magento/Sales/Setup/SalesSetup.php
+++ b/app/code/Magento/Sales/Setup/SalesSetup.php
@@ -11,13 +11,15 @@ use Magento\Framework\App\CacheInterface;
 use Magento\Framework\App\Config\ScopeConfigInterface;
 use Magento\Framework\Encryption\EncryptorInterface;
 use Magento\Framework\Setup\ModuleDataSetupInterface;
+use Magento\Eav\Setup\EavSetup;
 
 /**
- * Setup Model of Sales Module
- * @codeCoverageIgnore
+ * Sales module setup class
+ *
  * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ * @codeCoverageIgnore
  */
-class SalesSetup extends \Magento\Eav\Setup\EavSetup
+class SalesSetup extends EavSetup
 {
     /**
      * This should be set explicitly
@@ -55,6 +57,8 @@ class SalesSetup extends \Magento\Eav\Setup\EavSetup
     private static $connectionName = 'sales';
 
     /**
+     * Constructor
+     * 
      * @param ModuleDataSetupInterface $setup
      * @param Context $context
      * @param CacheInterface $cache
@@ -111,9 +115,10 @@ class SalesSetup extends \Magento\Eav\Setup\EavSetup
      */
     protected function _flatTableExist($table)
     {
-        $tablesList = $this->getSetup()->getConnection(self::$connectionName)->listTables();
+        $tablesList = $this->getConnection()
+            ->listTables();
         return in_array(
-            strtoupper($this->getSetup()->getTable($table, self::$connectionName)),
+            strtoupper($this->getTable($table)),
             array_map('strtoupper', $tablesList)
         );
     }
@@ -152,15 +157,14 @@ class SalesSetup extends \Magento\Eav\Setup\EavSetup
      */
     protected function _addFlatAttribute($table, $attribute, $attr)
     {
-        $tableInfo = $this->getSetup()
-            ->getConnection(self::$connectionName)
-            ->describeTable($this->getSetup()->getTable($table, self::$connectionName));
+        $tableInfo = $this->getConnection()
+            ->describeTable($this->getTable($table));
         if (isset($tableInfo[$attribute])) {
             return $this;
         }
         $columnDefinition = $this->_getAttributeColumnDefinition($attribute, $attr);
-        $this->getSetup()->getConnection(self::$connectionName)->addColumn(
-            $this->getSetup()->getTable($table, self::$connectionName),
+        $this->getConnection()->addColumn(
+            $this->getTable($table),
             $attribute,
             $columnDefinition
         );
@@ -180,8 +184,8 @@ class SalesSetup extends \Magento\Eav\Setup\EavSetup
     {
         if (in_array($entityTypeId, $this->_flatEntitiesGrid) && !empty($attr['grid'])) {
             $columnDefinition = $this->_getAttributeColumnDefinition($attribute, $attr);
-            $this->getSetup()->getConnection(self::$connectionName)->addColumn(
-                $this->getSetup()->getTable($table . '_grid', self::$connectionName),
+            $this->getConnection()->addColumn(
+                $this->getTable($table . '_grid'),
                 $attribute,
                 $columnDefinition
             );
@@ -297,4 +301,25 @@ class SalesSetup extends \Magento\Eav\Setup\EavSetup
     {
         return $this->encryptor;
     }
+
+    /**
+     * Get sales connection
+     *
+     * @return \Magento\Framework\DB\Adapter\AdapterInterface
+     */
+    public function getConnection()
+    {
+        return $this->getSetup()->getConnection(self::$connectionName);
+    }
+
+    /**
+     * Get table name
+     *
+     * @param string $table
+     * @return string
+     */
+    public function getTable($table)
+    {
+        return $this->getSetup()->getTable($table, self::$connectionName);
+    }
 }
diff --git a/app/code/Magento/Sales/Setup/SerializedDataConverter.php b/app/code/Magento/Sales/Setup/SerializedDataConverter.php
new file mode 100644
index 0000000000000000000000000000000000000000..507713b910f59c84dad6e5414d745d368bbadba1
--- /dev/null
+++ b/app/code/Magento/Sales/Setup/SerializedDataConverter.php
@@ -0,0 +1,70 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Sales\Setup;
+
+use Magento\Framework\Serialize\Serializer\Serialize;
+use Magento\Framework\Serialize\Serializer\Json;
+
+/**
+ * Serializer used to update nested serialized data in product_options field.
+ */
+class SerializedDataConverter implements \Magento\Framework\DB\DataConverter\DataConverterInterface
+{
+    /**
+     * @var Serialize
+     */
+    private $serialize;
+
+    /**
+     * @var Json
+     */
+    private $json;
+
+    /**
+     * SerializedDataConverter constructor.
+     *
+     * @param Serialize $serialize
+     * @param Json $json
+     */
+    public function __construct(
+        Serialize $serialize,
+        Json $json
+    ) {
+        $this->serialize = $serialize;
+        $this->json = $json;
+    }
+
+    /**
+     * Convert from serialized to JSON format.
+     *
+     * @param string $value
+     * @return string
+     */
+    public function convert($value)
+    {
+        $valueUnserialized = $this->serialize->unserialize($value);
+        if (isset($valueUnserialized['options'])) {
+            foreach ($valueUnserialized['options'] as $key => $option) {
+                if ($option['option_type'] === 'file') {
+                    $valueUnserialized['options'][$key]['option_value'] = $this->json->serialize(
+                        $this->serialize->unserialize(
+                            $option['option_value']
+                        )
+                    );
+                }
+            }
+        }
+        if (isset($valueUnserialized['bundle_selection_attributes'])) {
+            $valueUnserialized['bundle_selection_attributes'] = $this->json->serialize(
+                $this->serialize->unserialize(
+                    $valueUnserialized['bundle_selection_attributes']
+                )
+            );
+        }
+        return $this->json->serialize($valueUnserialized);
+    }
+}
diff --git a/app/code/Magento/Sales/Setup/UpgradeData.php b/app/code/Magento/Sales/Setup/UpgradeData.php
index 9580dd8a667a0477b3bbab6ffe2fac8698f85e57..67b43fee29d08b95d6a6ca5c2f8465cadc83f4ed 100644
--- a/app/code/Magento/Sales/Setup/UpgradeData.php
+++ b/app/code/Magento/Sales/Setup/UpgradeData.php
@@ -3,93 +3,112 @@
  * Copyright © 2016 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-
 namespace Magento\Sales\Setup;
 
-use Magento\Framework\Setup\UpgradeDataInterface;
-use Magento\Framework\Setup\ModuleContextInterface;
-use Magento\Framework\Setup\ModuleDataSetupInterface;
-
-class UpgradeData implements UpgradeDataInterface
+/**
+ * Data upgrade script
+ */
+class UpgradeData implements \Magento\Framework\Setup\UpgradeDataInterface
 {
     /**
      * Sales setup factory
      *
-     * @var SalesSetupFactory
+     * @var \Magento\Sales\Setup\SalesSetupFactory
      */
-    protected $salesSetupFactory;
+    private $salesSetupFactory;
 
     /**
      * @var \Magento\Eav\Model\Config
      */
-    protected $eavConfig;
+    private $eavConfig;
+
+    /**
+     * @var \Magento\Sales\Setup\ConvertSerializedDataToJsonFactory
+     */
+    private $convertSerializedDataToJsonFactory;
 
     /**
-     * @param SalesSetupFactory $salesSetupFactory
+     * Constructor
+     *
+     * @param \Magento\Sales\Setup\SalesSetupFactory $salesSetupFactory
+     * @param \Magento\Sales\Setup\ConvertSerializedDataToJsonFactory $convertSerializedDataToJsonFactory
      * @param \Magento\Eav\Model\Config $eavConfig
      */
     public function __construct(
-        SalesSetupFactory $salesSetupFactory,
+        \Magento\Sales\Setup\SalesSetupFactory $salesSetupFactory,
+        \Magento\Sales\Setup\ConvertSerializedDataToJsonFactory $convertSerializedDataToJsonFactory,
         \Magento\Eav\Model\Config $eavConfig
     ) {
         $this->salesSetupFactory = $salesSetupFactory;
+        $this->convertSerializedDataToJsonFactory = $convertSerializedDataToJsonFactory;
         $this->eavConfig = $eavConfig;
     }
 
     /**
      * {@inheritdoc}
-     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
      */
-    public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
-    {
-        $setup->startSetup();
-
-        /** @var SalesSetup $salesSetup */
+    public function upgrade(
+        \Magento\Framework\Setup\ModuleDataSetupInterface $setup,
+        \Magento\Framework\Setup\ModuleContextInterface $context
+    ) {
         $salesSetup = $this->salesSetupFactory->create(['setup' => $setup]);
-
         if (version_compare($context->getVersion(), '2.0.1', '<')) {
-            $salesSetup->updateEntityType(
-                \Magento\Sales\Model\Order::ENTITY,
-                'entity_model',
-                \Magento\Sales\Model\ResourceModel\Order::class
-            );
-            $salesSetup->updateEntityType(
-                \Magento\Sales\Model\Order::ENTITY,
-                'increment_model',
-                \Magento\Eav\Model\Entity\Increment\NumericValue::class
-            );
-            $salesSetup->updateEntityType(
-                'invoice',
-                'entity_model',
-                \Magento\Sales\Model\ResourceModel\Order::class
-            );
-            $salesSetup->updateEntityType(
-                'invoice',
-                'increment_model',
-                \Magento\Eav\Model\Entity\Increment\NumericValue::class
-            );
-            $salesSetup->updateEntityType(
-                'creditmemo',
-                'entity_model',
-                \Magento\Sales\Model\ResourceModel\Order\Creditmemo::class
-            );
-            $salesSetup->updateEntityType(
-                'creditmemo',
-                'increment_model',
-                \Magento\Eav\Model\Entity\Increment\NumericValue::class
-            );
-            $salesSetup->updateEntityType(
-                'shipment',
-                'entity_model',
-                \Magento\Sales\Model\ResourceModel\Order\Shipment::class
-            );
-            $salesSetup->updateEntityType(
-                'shipment',
-                'increment_model',
-                \Magento\Eav\Model\Entity\Increment\NumericValue::class
-            );
+            $this->upgradeToTwoZeroOne($salesSetup);
+        }
+        if (version_compare($context->getVersion(), '2.0.5', '<')) {
+            $this->convertSerializedDataToJsonFactory->create(['salesSetup' => $salesSetup])
+                ->convert();
         }
         $this->eavConfig->clear();
-        $setup->endSetup();
+    }
+
+    /**
+     * Upgrade to version 2.0.1
+     *
+     * @param \Magento\Sales\Setup\SalesSetup $setup
+     * @return void
+     */
+    private function upgradeToTwoZeroOne(\Magento\Sales\Setup\SalesSetup $setup)
+    {
+        $setup->updateEntityType(
+            \Magento\Sales\Model\Order::ENTITY,
+            'entity_model',
+            \Magento\Sales\Model\ResourceModel\Order::class
+        );
+        $setup->updateEntityType(
+            \Magento\Sales\Model\Order::ENTITY,
+            'increment_model',
+            \Magento\Eav\Model\Entity\Increment\NumericValue::class
+        );
+        $setup->updateEntityType(
+            'invoice',
+            'entity_model',
+            \Magento\Sales\Model\ResourceModel\Order::class
+        );
+        $setup->updateEntityType(
+            'invoice',
+            'increment_model',
+            \Magento\Eav\Model\Entity\Increment\NumericValue::class
+        );
+        $setup->updateEntityType(
+            'creditmemo',
+            'entity_model',
+            \Magento\Sales\Model\ResourceModel\Order\Creditmemo::class
+        );
+        $setup->updateEntityType(
+            'creditmemo',
+            'increment_model',
+            \Magento\Eav\Model\Entity\Increment\NumericValue::class
+        );
+        $setup->updateEntityType(
+            'shipment',
+            'entity_model',
+            \Magento\Sales\Model\ResourceModel\Order\Shipment::class
+        );
+        $setup->updateEntityType(
+            'shipment',
+            'increment_model',
+            \Magento\Eav\Model\Entity\Increment\NumericValue::class
+        );
     }
 }
diff --git a/app/code/Magento/Sales/Test/Unit/Controller/Download/DownloadCustomOptionTest.php b/app/code/Magento/Sales/Test/Unit/Controller/Download/DownloadCustomOptionTest.php
index 387fc3b782b10a17f969975a1c67197c5cd9dfac..b7ceaf727edb069e283fa2d5a2b99b3aeebe9687 100644
--- a/app/code/Magento/Sales/Test/Unit/Controller/Download/DownloadCustomOptionTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Controller/Download/DownloadCustomOptionTest.php
@@ -6,6 +6,9 @@
 
 namespace Magento\Sales\Test\Unit\Controller\Download;
 
+use Magento\Framework\Serialize\Serializer\Json;
+use Magento\Framework\Unserialize\Unserialize;
+
 /**
  * Class DownloadCustomOptionTest
  * @package Magento\Sales\Controller\Adminhtml\Order
@@ -55,7 +58,7 @@ class DownloadCustomOptionTest extends \PHPUnit_Framework_TestCase
     /**
      * @var \Magento\Framework\Unserialize\Unserialize|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $unserializeMock;
+    protected $serializerMock;
 
     /**
      * @var \Magento\Framework\Controller\Result\Forward|\PHPUnit_Framework_MockObject_MockObject
@@ -89,9 +92,9 @@ class DownloadCustomOptionTest extends \PHPUnit_Framework_TestCase
             ->setMethods(['downloadFile'])
             ->getMock();
 
-        $this->unserializeMock = $this->getMockBuilder(\Magento\Framework\Unserialize\Unserialize::class)
+        $this->serializerMock = $this->getMockBuilder(Json::class)
             ->disableOriginalConstructor()
-            ->setMethods(['unserialize'])
+            ->setMethods(['serialize', 'unserialize'])
             ->getMock();
 
         $requestMock = $this->getMockBuilder(\Magento\Framework\App\Request\Http::class)
@@ -151,7 +154,8 @@ class DownloadCustomOptionTest extends \PHPUnit_Framework_TestCase
                     'context'              => $contextMock,
                     'resultForwardFactory' => $resultForwardFactoryMock,
                     'download'             => $this->downloadMock,
-                    'unserialize'          => $this->unserializeMock
+                    'unserialize'          => $this->getMock(Unserialize::class, [], [], '', false),
+                    'serializer'           => $this->serializerMock
                 ]
             )
             ->getMock();
@@ -197,7 +201,7 @@ class DownloadCustomOptionTest extends \PHPUnit_Framework_TestCase
         } else {
             $unserializeResult = [self::SECRET_KEY => self::SECRET_KEY];
 
-            $this->unserializeMock->expects($this->once())
+            $this->serializerMock->expects($this->once())
                 ->method('unserialize')
                 ->with($itemOptionValues[self::OPTION_VALUE])
                 ->willReturn($unserializeResult);
@@ -321,7 +325,7 @@ class DownloadCustomOptionTest extends \PHPUnit_Framework_TestCase
         $this->productOptionMock->expects($this->any())->method('getProductId')->willReturn(self::OPTION_PRODUCT_ID);
         $this->productOptionMock->expects($this->any())->method('getType')->willReturn(self::OPTION_TYPE);
 
-        $this->unserializeMock->expects($this->once())
+        $this->serializerMock->expects($this->once())
             ->method('unserialize')
             ->with(self::OPTION_VALUE)
             ->willReturn([self::SECRET_KEY => 'bad_test_secret_key']);
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/ConfigTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/ConfigTest.php
index 7ee4f745cde8f75de23147c956ca0bf039ab2e3a..e0aae72555c038e603d0f2d13e1a15d7eeb76737 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/Order/ConfigTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/Order/ConfigTest.php
@@ -5,6 +5,9 @@
  */
 namespace Magento\Sales\Test\Unit\Model\Order;
 
+use Magento\Framework\DataObject;
+use Magento\Sales\Model\ResourceModel\Order\Status\Collection;
+
 /**
  * Class ConfigTest
  */
@@ -44,28 +47,28 @@ class ConfigTest extends \PHPUnit_Framework_TestCase
     public function testGetInvisibleOnFrontStatuses()
     {
         $statuses = [
-            new \Magento\Framework\DataObject(
+            new DataObject(
                 [
                     'status' => 'canceled',
                     'is_default' => 1,
                     'visible_on_front' => 1,
                 ]
             ),
-            new \Magento\Framework\DataObject(
+            new DataObject(
                 [
                     'status' => 'complete',
                     'is_default' => 1,
                     'visible_on_front' => 0,
                 ]
             ),
-            new \Magento\Framework\DataObject(
+            new DataObject(
                 [
                     'status' => 'processing',
                     'is_default' => 1,
                     'visible_on_front' => 1,
                 ]
             ),
-            new \Magento\Framework\DataObject(
+            new DataObject(
                 [
                     'status' => 'pending_payment',
                     'is_default' => 1,
@@ -76,7 +79,7 @@ class ConfigTest extends \PHPUnit_Framework_TestCase
         $expectedResult = ['complete', 'pending_payment'];
 
         $collectionMock = $this->getMock(
-            \Magento\Sales\Model\ResourceModel\Order\Status\Collection::class,
+            Collection::class,
             ['create', 'joinStates'],
             [],
             '',
@@ -97,14 +100,14 @@ class ConfigTest extends \PHPUnit_Framework_TestCase
     public function testGetStateLabelByStateAndStatus()
     {
         $statuses = [
-            new \Magento\Framework\DataObject(
+            new DataObject(
                 [
                     'status' => 'fraud',
                     'state' => 'processing',
                     'label' => 'Suspected Fraud',
                 ]
             ),
-            new \Magento\Framework\DataObject(
+            new DataObject(
                 [
                     'status' => 'processing',
                     'state' => 'processing',
@@ -113,7 +116,7 @@ class ConfigTest extends \PHPUnit_Framework_TestCase
             )
         ];
         $collectionMock = $this->getMock(
-            \Magento\Sales\Model\ResourceModel\Order\Status\Collection::class,
+            Collection::class,
             ['create', 'joinStates'],
             [],
             '',
@@ -129,4 +132,98 @@ class ConfigTest extends \PHPUnit_Framework_TestCase
         $result = $this->salesConfig->getStateLabelByStateAndStatus('processing', 'fraud');
         $this->assertSame('Suspected Fraud', $result->getText());
     }
+
+    /**
+     * Test get statuses
+     *
+     * @dataProvider getStatusesDataProvider
+     *
+     * @param string $state
+     * @param bool $joinLabels
+     * @param DataObject[] $collectionData
+     * @param array $expectedResult
+     */
+    public function testGetStatuses($state, $joinLabels, $collectionData, $expectedResult)
+    {
+        $collectionMock = $this->getMock(
+            Collection::class,
+            ['create', 'joinStates', 'addStateFilter', 'orderByLabel'],
+            [],
+            '',
+            false,
+            false
+        );
+        $this->orderStatusCollectionFactoryMock->expects($this->any())
+            ->method('create')
+            ->will($this->returnValue($collectionMock));
+
+        $collectionMock->expects($this->once())
+            ->method('addStateFilter')
+            ->will($this->returnSelf());
+
+        $collectionMock->expects($this->once())
+            ->method('orderByLabel')
+            ->will($this->returnValue($collectionData));
+
+        $collectionMock->expects($this->once())
+            ->method('joinStates')
+            ->will($this->returnValue($collectionData));
+
+        $result = $this->salesConfig->getStateStatuses($state, $joinLabels);
+        $this->assertSame($expectedResult, $result);
+
+        // checking data cached in private property
+        $this->assertSame($result, $this->salesConfig->getStateStatuses($state, $joinLabels));
+    }
+
+    /**
+     * Data provider for testGetStatuses
+     *
+     * @return array
+     */
+    public function getStatusesDataProvider()
+    {
+        return [
+            'processing state' => [
+                'state' => 'processing',
+                'joinLabels' => false,
+                'collectionData' => [
+                    new DataObject(
+                        [
+                            'status' => 'fraud',
+                            'state' => 'processing',
+                            'store_label' => 'Suspected Fraud',
+                        ]
+                    ),
+                    new DataObject(
+                        [
+                            'status' => 'processing',
+                            'state' => 'processing',
+                            'store_label' => 'Processing',
+                        ]
+                    ),
+                ],
+                'expectedResult' => [
+                    0 => 'fraud',
+                    1 => 'processing'
+                ],
+            ],
+            'pending state' => [
+                'state' => 'pending',
+                'joinLabels' => true,
+                'collectionData' => [
+                    new DataObject(
+                        [
+                            'status' => 'pending_status',
+                            'state' => 'pending',
+                            'store_label' => 'Pending label',
+                        ]
+                    ),
+                ],
+                'expectedResult' => [
+                    'pending_status' => 'Pending label'
+                ],
+            ],
+        ];
+    }
 }
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/ItemTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/ItemTest.php
index 3d6ba772618c70a710809bb986ec9f55efe3c90b..b40fc6c7f5916952c403734eb94b2564936f2aaf 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/Order/ItemTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/Order/ItemTest.php
@@ -6,6 +6,7 @@
 
 namespace Magento\Sales\Test\Unit\Model\Order;
 
+use Magento\Framework\Serialize\Serializer\Json;
 use Magento\Sales\Model\ResourceModel\OrderFactory;
 use \Magento\Sales\Model\Order;
 
@@ -31,14 +32,22 @@ class ItemTest extends \PHPUnit_Framework_TestCase
      */
     protected $orderFactory;
 
+    /**
+     * @var Json|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $serializerMock;
+
     protected function setUp()
     {
         $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
 
         $this->orderFactory = $this->getMock(\Magento\Sales\Model\OrderFactory::class, ['create'], [], '', false);
 
+        $this->serializerMock = $this->getMock(Json::class, [], ['unserialize'], '', false);
+
         $arguments = [
             'orderFactory' => $this->orderFactory,
+            'serializer' => $this->serializerMock
         ];
         $this->model = $this->objectManager->getObject(\Magento\Sales\Model\Order\Item::class, $arguments);
     }
@@ -173,4 +182,55 @@ class ItemTest extends \PHPUnit_Framework_TestCase
         $this->model->setData(\Magento\Sales\Api\Data\OrderItemInterface::ORIGINAL_PRICE, $originalPrice);
         $this->assertEquals($originalPrice, $this->model->getOriginalPrice());
     }
+
+    /**
+     * Test get product options with serialization
+     *
+     * @param array|string $options
+     * @param array $expectedResult
+     *
+     * @dataProvider getProductOptionsDataProvider
+     */
+    public function testGetProductOptions($options, $expectedResult)
+    {
+        if (is_string($options)) {
+            $this->serializerMock->expects($this->once())
+                ->method('unserialize')
+                ->will($this->returnValue($expectedResult));
+        }
+        $this->model->setData('product_options', $options);
+        $result = $this->model->getProductOptions();
+        $this->assertSame($result, $expectedResult);
+    }
+
+    /**
+     * Data provider for testGetProductOptions
+     *
+     * @return array
+     */
+    public function getProductOptionsDataProvider()
+    {
+        return [
+            'array' => [
+                'options' => [
+                    'option1' => 'option 1 value',
+                    'option2' => 'option 2 value',
+                ],
+                'expectedResult' => [
+                    'option1' => 'option 1 value',
+                    'option2' => 'option 2 value',
+                ]
+            ],
+            'serialized' => [
+                'options' => json_encode([
+                    'option1' => 'option 1 value',
+                    'option2' => 'option 2 value',
+                ]),
+                'expectedResult' => [
+                    'option1' => 'option 1 value',
+                    'option2' => 'option 2 value',
+                ]
+            ]
+        ];
+    }
 }
diff --git a/app/code/Magento/Sales/Test/Unit/Setup/SerializedDataConverterTest.php b/app/code/Magento/Sales/Test/Unit/Setup/SerializedDataConverterTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..e5f7e162a77c71941eac6898c0cfac3b4c854ab2
--- /dev/null
+++ b/app/code/Magento/Sales/Test/Unit/Setup/SerializedDataConverterTest.php
@@ -0,0 +1,91 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Test\Unit\Setup;
+
+use Magento\Framework\Serialize\Serializer\Json;
+use Magento\Framework\Serialize\Serializer\Serialize;
+
+/**
+ * Unit test for serialized data converter test.
+ */
+class SerializedDataConverterTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Sales\Setup\SerializedDataConverter
+     */
+    protected $model;
+
+    /**
+     * @var Serialize|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $serializeMock;
+
+    /**
+     * @var Json|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $jsonMock;
+
+    public function setUp()
+    {
+        $this->serializeMock = $this->getMock(Serialize::class, ['unserialize'], [], '', false);
+        $this->serializeMock->expects($this->any())
+            ->method('unserialize')
+            ->will(
+                $this->returnCallback(
+                    function ($value) {
+                        return unserialize($value);
+                    }
+                )
+            );
+        $this->jsonMock = $this->getMock(Json::class, ['serialize'], [], '', false);
+        $this->jsonMock->expects($this->any())
+            ->method('serialize')
+            ->will(
+                $this->returnCallback(
+                    function ($value) {
+                        return json_encode($value);
+                    }
+                )
+            );
+
+        $this->model = new \Magento\Sales\Setup\SerializedDataConverter($this->serializeMock, $this->jsonMock);
+
+    }
+
+    /**
+     * @param string $serialized
+     * @param string $expectedJson
+     *
+     * @dataProvider convertDataProvider
+     */
+    public function testConvert($serialized, $expectedJson)
+    {
+        $this->assertEquals($expectedJson, $this->model->convert($serialized));
+    }
+
+    /**
+     * Data provider for convert method test
+     *
+     * Slashes in PHP string are implicitly escaped so they MUST be escaped manually to correspond real expected data
+     *
+     * @return array
+     */
+    public function convertDataProvider()
+    {
+        // @codingStandardsIgnoreStart
+        return [
+            'dataset_1' => [
+                'serialized' => 'a:2:{s:15:"info_buyRequest";a:6:{s:4:"uenc";s:52:"aHR0cDovL20yLmxvYy9zaW1wbGUuaHRtbD9vcHRpb25zPWNhcnQ,";s:7:"product";s:1:"1";s:28:"selected_configurable_option";s:0:"";s:15:"related_product";s:0:"";s:7:"options";a:3:{i:1;s:4:"test";i:3;s:1:"2";i:2;a:9:{s:4:"type";s:10:"image/jpeg";s:5:"title";s:7:"476.jpg";s:10:"quote_path";s:61:"custom_options/quote/4/7/bc61f16f0cc3a8c5abd7ebbaad4cc139.jpg";s:10:"order_path";s:61:"custom_options/order/4/7/bc61f16f0cc3a8c5abd7ebbaad4cc139.jpg";s:8:"fullpath";s:89:"C:/www/magento/ce/pub/media/custom_options/quote/4/7/bc61f16f0cc3a8c5abd7ebbaad4cc139.jpg";s:4:"size";s:6:"122340";s:5:"width";i:666;s:6:"height";i:940;s:10:"secret_key";s:20:"bc61f16f0cc3a8c5abd7";}}s:3:"qty";s:1:"1";}s:7:"options";a:3:{i:0;a:7:{s:5:"label";s:11:"testoption1";s:5:"value";s:4:"test";s:11:"print_value";s:4:"test";s:9:"option_id";s:1:"1";s:11:"option_type";s:5:"field";s:12:"option_value";s:4:"test";s:11:"custom_view";b:0;}i:1;a:7:{s:5:"label";s:11:"testoption2";s:5:"value";s:132:"<a href="http://m2.loc/sales/download/downloadCustomOption/id/9/key/bc61f16f0cc3a8c5abd7/" target="_blank">476.jpg</a> 666 x 940 px.";s:11:"print_value";s:21:"476.jpg 666 x 940 px.";s:9:"option_id";s:1:"2";s:11:"option_type";s:4:"file";s:12:"option_value";s:600:"a:10:{s:4:"type";s:10:"image/jpeg";s:5:"title";s:7:"476.jpg";s:10:"quote_path";s:61:"custom_options/quote/4/7/bc61f16f0cc3a8c5abd7ebbaad4cc139.jpg";s:10:"order_path";s:61:"custom_options/order/4/7/bc61f16f0cc3a8c5abd7ebbaad4cc139.jpg";s:8:"fullpath";s:89:"C:/www/magento/ce/pub/media/custom_options/quote/4/7/bc61f16f0cc3a8c5abd7ebbaad4cc139.jpg";s:4:"size";s:6:"122340";s:5:"width";i:666;s:6:"height";i:940;s:10:"secret_key";s:20:"bc61f16f0cc3a8c5abd7";s:3:"url";a:2:{s:5:"route";s:35:"sales/download/downloadCustomOption";s:6:"params";a:2:{s:2:"id";s:1:"9";s:3:"key";s:20:"bc61f16f0cc3a8c5abd7";}}}";s:11:"custom_view";b:1;}i:2;a:7:{s:5:"label";s:8:"testopt3";s:5:"value";s:3:"222";s:11:"print_value";s:3:"222";s:9:"option_id";s:1:"3";s:11:"option_type";s:9:"drop_down";s:12:"option_value";s:1:"2";s:11:"custom_view";b:0;}}}',
+                'expectedJson' => '{"info_buyRequest":{"uenc":"aHR0cDovL20yLmxvYy9zaW1wbGUuaHRtbD9vcHRpb25zPWNhcnQ,","product":"1","selected_configurable_option":"","related_product":"","options":{"1":"test","3":"2","2":{"type":"image\/jpeg","title":"476.jpg","quote_path":"custom_options\/quote\/4\/7\/bc61f16f0cc3a8c5abd7ebbaad4cc139.jpg","order_path":"custom_options\/order\/4\/7\/bc61f16f0cc3a8c5abd7ebbaad4cc139.jpg","fullpath":"C:\/www\/magento\/ce\/pub\/media\/custom_options\/quote\/4\/7\/bc61f16f0cc3a8c5abd7ebbaad4cc139.jpg","size":"122340","width":666,"height":940,"secret_key":"bc61f16f0cc3a8c5abd7"}},"qty":"1"},"options":[{"label":"testoption1","value":"test","print_value":"test","option_id":"1","option_type":"field","option_value":"test","custom_view":false},{"label":"testoption2","value":"<a href=\"http:\/\/m2.loc\/sales\/download\/downloadCustomOption\/id\/9\/key\/bc61f16f0cc3a8c5abd7\/\" target=\"_blank\">476.jpg<\/a> 666 x 940 px.","print_value":"476.jpg 666 x 940 px.","option_id":"2","option_type":"file","option_value":"{\"type\":\"image\\\\\/jpeg\",\"title\":\"476.jpg\",\"quote_path\":\"custom_options\\\\\/quote\\\\\/4\\\\\/7\\\\\/bc61f16f0cc3a8c5abd7ebbaad4cc139.jpg\",\"order_path\":\"custom_options\\\\\/order\\\\\/4\\\\\/7\\\\\/bc61f16f0cc3a8c5abd7ebbaad4cc139.jpg\",\"fullpath\":\"C:\\\\\/www\\\\\/magento\\\\\/ce\\\\\/pub\\\\\/media\\\\\/custom_options\\\\\/quote\\\\\/4\\\\\/7\\\\\/bc61f16f0cc3a8c5abd7ebbaad4cc139.jpg\",\"size\":\"122340\",\"width\":666,\"height\":940,\"secret_key\":\"bc61f16f0cc3a8c5abd7\",\"url\":{\"route\":\"sales\\\\\/download\\\\\/downloadCustomOption\",\"params\":{\"id\":\"9\",\"key\":\"bc61f16f0cc3a8c5abd7\"}}}","custom_view":true},{"label":"testopt3","value":"222","print_value":"222","option_id":"3","option_type":"drop_down","option_value":"2","custom_view":false}]}',
+            ],
+            'dataset_2' => [
+                'serialized' => 'a:2:{s:15:"info_buyRequest";a:6:{s:4:"uenc";s:36:"aHR0cDovL20yLmxvYy9idW5kbGUuaHRtbA,,";s:7:"product";s:1:"4";s:28:"selected_configurable_option";s:0:"";s:15:"related_product";s:0:"";s:13:"bundle_option";a:2:{i:1;s:1:"1";i:2;s:1:"2";}s:3:"qty";s:1:"3";}s:27:"bundle_selection_attributes";s:97:"a:4:{s:5:"price";d:100;s:3:"qty";d:1;s:12:"option_label";s:8:"option 1";s:9:"option_id";s:1:"1";}";}',
+                'expectedJson' => '{"info_buyRequest":{"uenc":"aHR0cDovL20yLmxvYy9idW5kbGUuaHRtbA,,","product":"4","selected_configurable_option":"","related_product":"","bundle_option":{"1":"1","2":"2"},"qty":"3"},"bundle_selection_attributes":"{\"price\":100,\"qty\":1,\"option_label\":\"option 1\",\"option_id\":\"1\"}"}',
+            ],
+        ];
+        // @codingStandardsIgnoreEnd
+    }
+}
diff --git a/app/code/Magento/Sales/etc/module.xml b/app/code/Magento/Sales/etc/module.xml
index 980395e965e0899695206b7094b72f7f5b396ece..c0bef637833a1b1b52f9d628689f9aa512f64072 100644
--- a/app/code/Magento/Sales/etc/module.xml
+++ b/app/code/Magento/Sales/etc/module.xml
@@ -6,7 +6,7 @@
  */
 -->
 <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
-    <module name="Magento_Sales" setup_version="2.0.4">
+    <module name="Magento_Sales" setup_version="2.0.5">
         <sequence>
             <module name="Magento_Rule"/>
             <module name="Magento_Catalog"/>
diff --git a/app/code/Magento/Tax/Helper/Data.php b/app/code/Magento/Tax/Helper/Data.php
index 3f9d9648b4bb487a2911f608ade732c340fadb3a..0626b336b33214c46c5da0ddca47a9fd39f290ec 100644
--- a/app/code/Magento/Tax/Helper/Data.php
+++ b/app/code/Magento/Tax/Helper/Data.php
@@ -3,27 +3,27 @@
  * Copyright © 2016 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-
-// @codingStandardsIgnoreFile
-
 namespace Magento\Tax\Helper;
 
 use Magento\Framework\Pricing\PriceCurrencyInterface;
 use Magento\Store\Model\Store;
 use Magento\Customer\Model\Address;
 use Magento\Tax\Model\Config;
-use Magento\Tax\Api\TaxCalculationInterface;
 use Magento\Customer\Model\Session as CustomerSession;
 use Magento\Tax\Api\OrderTaxManagementInterface;
 use Magento\Sales\Model\Order\Invoice;
 use Magento\Sales\Model\Order\Creditmemo;
 use Magento\Tax\Api\Data\OrderTaxDetailsItemInterface;
 use Magento\Sales\Model\EntityInterface;
+use Magento\Framework\Serialize\Serializer\Json;
+use Magento\Framework\App\ObjectManager;
 
 /**
- * Catalog data helper
+ * Tax helper
+ *
  * @SuppressWarnings(PHPMD.TooManyFields)
  * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ * @codingStandardsIgnoreFile
  */
 class Data extends \Magento\Framework\App\Helper\AbstractHelper
 {
@@ -79,9 +79,7 @@ class Data extends \Magento\Framework\App\Helper\AbstractHelper
     protected $_localeResolver;
 
     /**
-     * \Magento\Catalog\Helper\Data
-     *
-     * @var CatalogHelper
+     * @var \Magento\Catalog\Helper\Data
      */
     protected $catalogHelper;
 
@@ -96,16 +94,24 @@ class Data extends \Magento\Framework\App\Helper\AbstractHelper
     protected $priceCurrency;
 
     /**
-     * @param \Magento\Framework\App\Helper\Context                         $context
-     * @param \Magento\Framework\Json\Helper\Data                           $jsonHelper
-     * @param Config                                                        $taxConfig
-     * @param \Magento\Store\Model\StoreManagerInterface                    $storeManager
-     * @param \Magento\Framework\Locale\FormatInterface                     $localeFormat
+     * @var Json
+     */
+    private $serializer;
+
+    /**
+     * Constructor
+     *
+     * @param \Magento\Framework\App\Helper\Context $context
+     * @param \Magento\Framework\Json\Helper\Data $jsonHelper
+     * @param Config $taxConfig
+     * @param \Magento\Store\Model\StoreManagerInterface $storeManager
+     * @param \Magento\Framework\Locale\FormatInterface $localeFormat
      * @param \Magento\Tax\Model\ResourceModel\Sales\Order\Tax\CollectionFactory $orderTaxCollectionFactory
-     * @param \Magento\Framework\Locale\ResolverInterface                   $localeResolver
-     * @param \Magento\Catalog\Helper\Data                                  $catalogHelper
-     * @param OrderTaxManagementInterface                                   $orderTaxManagement
-     * @param PriceCurrencyInterface                                        $priceCurrency
+     * @param \Magento\Framework\Locale\ResolverInterface $localeResolver
+     * @param \Magento\Catalog\Helper\Data $catalogHelper
+     * @param OrderTaxManagementInterface $orderTaxManagement
+     * @param PriceCurrencyInterface $priceCurrency
+     * @param Json $serializer
      * @SuppressWarnings(PHPMD.ExcessiveParameterList)
      */
     public function __construct(
@@ -118,7 +124,8 @@ class Data extends \Magento\Framework\App\Helper\AbstractHelper
         \Magento\Framework\Locale\ResolverInterface $localeResolver,
         \Magento\Catalog\Helper\Data $catalogHelper,
         OrderTaxManagementInterface $orderTaxManagement,
-        PriceCurrencyInterface $priceCurrency
+        PriceCurrencyInterface $priceCurrency,
+        Json $serializer = null
     ) {
         parent::__construct($context);
         $this->priceCurrency = $priceCurrency;
@@ -130,6 +137,7 @@ class Data extends \Magento\Framework\App\Helper\AbstractHelper
         $this->_localeResolver = $localeResolver;
         $this->catalogHelper = $catalogHelper;
         $this->orderTaxManagement = $orderTaxManagement;
+        $this->serializer = $serializer ?: ObjectManager::getInstance()->get(Json::class);
     }
 
     /**
@@ -738,7 +746,7 @@ class Data extends \Magento\Framework\App\Helper\AbstractHelper
                     $taxableItemType = $itemTaxDetail->getType();
                     $ratio = $itemRatio;
                     if ($item->getTaxRatio()) {
-                        $taxRatio = unserialize($item->getTaxRatio());
+                        $taxRatio = $this->serializer->unserialize($item->getTaxRatio());
                         if (isset($taxRatio[$taxableItemType])) {
                             $ratio = $taxRatio[$taxableItemType];
                         }
diff --git a/app/code/Magento/Tax/Model/Quote/GrandTotalDetailsPlugin.php b/app/code/Magento/Tax/Model/Quote/GrandTotalDetailsPlugin.php
index a727beef10b0648934dbb21b89945ff2d1462193..6340c697d1009ca602daeb19e5f12c897f4e1642 100644
--- a/app/code/Magento/Tax/Model/Quote/GrandTotalDetailsPlugin.php
+++ b/app/code/Magento/Tax/Model/Quote/GrandTotalDetailsPlugin.php
@@ -6,50 +6,62 @@
 namespace Magento\Tax\Model\Quote;
 
 use Magento\Quote\Api\Data\TotalSegmentExtensionFactory;
+use Magento\Framework\Serialize\Serializer\Json;
+use Magento\Framework\App\ObjectManager;
 
 class GrandTotalDetailsPlugin
 {
     /**
      * @var \Magento\Tax\Api\Data\GrandTotalDetailsInterfaceFactory
      */
-    protected $detailsFactory;
+    private $detailsFactory;
 
     /**
      * @var \Magento\Tax\Api\Data\GrandTotalRatesInterfaceFactory
      */
-    protected $ratesFactory;
+    private $ratesFactory;
 
     /**
      * @var TotalSegmentExtensionFactory
      */
-    protected $totalSegmentExtensionFactory;
+    private $totalSegmentExtensionFactory;
 
     /**
      * @var \Magento\Tax\Model\Config
      */
-    protected $taxConfig;
+    private $taxConfig;
 
     /**
      * @var string
      */
-    protected $code;
+    private $code;
 
     /**
+     * @var Json
+     */
+    private $serializer;
+
+    /**
+     * Constructor
+     *
      * @param \Magento\Tax\Api\Data\GrandTotalDetailsInterfaceFactory $detailsFactory
      * @param \Magento\Tax\Api\Data\GrandTotalRatesInterfaceFactory $ratesFactory
      * @param TotalSegmentExtensionFactory $totalSegmentExtensionFactory
      * @param \Magento\Tax\Model\Config $taxConfig
+     * @param Json $serializer
      */
     public function __construct(
         \Magento\Tax\Api\Data\GrandTotalDetailsInterfaceFactory $detailsFactory,
         \Magento\Tax\Api\Data\GrandTotalRatesInterfaceFactory $ratesFactory,
         TotalSegmentExtensionFactory $totalSegmentExtensionFactory,
-        \Magento\Tax\Model\Config $taxConfig
+        \Magento\Tax\Model\Config $taxConfig,
+        Json $serializer
     ) {
         $this->detailsFactory = $detailsFactory;
         $this->ratesFactory = $ratesFactory;
         $this->totalSegmentExtensionFactory = $totalSegmentExtensionFactory;
         $this->taxConfig = $taxConfig;
+        $this->serializer = $serializer;
         $this->code = 'tax';
     }
 
@@ -73,7 +85,6 @@ class GrandTotalDetailsPlugin
      * @param \Magento\Quote\Model\Cart\TotalsConverter $subject
      * @param \Magento\Quote\Api\Data\TotalSegmentInterface[] $totalSegments
      * @param \Magento\Quote\Model\Quote\Address\Total[] $addressTotals
-     *
      * @return \Magento\Quote\Api\Data\TotalSegmentInterface[]
      * @SuppressWarnings(PHPMD.UnusedFormalParameter)
      * @SuppressWarnings(PHPMD.CyclomaticComplexity)
@@ -97,7 +108,7 @@ class GrandTotalDetailsPlugin
         $finalData = [];
         $fullInfo = $taxes['full_info'];
         if (is_string($fullInfo)) {
-            $fullInfo = unserialize($fullInfo);
+            $fullInfo = $this->serializer->unserialize($fullInfo);
         }
         foreach ($fullInfo as $info) {
             if ((array_key_exists('hidden', $info) && $info['hidden'])
diff --git a/app/code/Magento/Tax/Model/Sales/Total/Quote/Tax.php b/app/code/Magento/Tax/Model/Sales/Total/Quote/Tax.php
index da3b86958eb4b13493c8e624eb556688899936ae..819f5a06349eab445cf86428e5fe0fc19fa74446 100755
--- a/app/code/Magento/Tax/Model/Sales/Total/Quote/Tax.php
+++ b/app/code/Magento/Tax/Model/Sales/Total/Quote/Tax.php
@@ -11,6 +11,8 @@ use Magento\Quote\Model\Quote\Address;
 use Magento\Tax\Api\Data\TaxClassKeyInterface;
 use Magento\Tax\Model\Calculation;
 use Magento\Quote\Api\Data\ShippingAssignmentInterface;
+use Magento\Framework\Serialize\Serializer\Json;
+use Magento\Framework\App\ObjectManager;
 
 /**
  * Tax totals calculation model
@@ -46,6 +48,11 @@ class Tax extends CommonTaxCollector
      */
     protected $_discountTaxCompensationes = [];
 
+    /**
+     * @var Json
+     */
+    private $serializer;
+
     /**
      * Class constructor
      *
@@ -57,6 +64,7 @@ class Tax extends CommonTaxCollector
      * @param CustomerAddressFactory $customerAddressFactory
      * @param CustomerAddressRegionFactory $customerAddressRegionFactory
      * @param \Magento\Tax\Helper\Data $taxData
+     * @param Json $serializer
      */
     public function __construct(
         \Magento\Tax\Model\Config $taxConfig,
@@ -66,10 +74,12 @@ class Tax extends CommonTaxCollector
         \Magento\Tax\Api\Data\TaxClassKeyInterfaceFactory $taxClassKeyDataObjectFactory,
         CustomerAddressFactory $customerAddressFactory,
         CustomerAddressRegionFactory $customerAddressRegionFactory,
-        \Magento\Tax\Helper\Data $taxData
+        \Magento\Tax\Helper\Data $taxData,
+        Json $serializer = null
     ) {
         $this->setCode('tax');
         $this->_taxData = $taxData;
+        $this->serializer = $serializer ?: ObjectManager::getInstance()->get(Json::class);
         parent::__construct(
             $taxConfig,
             $taxCalculationService,
@@ -300,7 +310,7 @@ class Tax extends CommonTaxCollector
         $store = $quote->getStore();
         $applied = $total->getAppliedTaxes();
         if (is_string($applied)) {
-            $applied = unserialize($applied);
+            $applied = $this->serializer->unserialize($applied);
         }
         $amount = $total->getTaxAmount();
         if ($amount === null) {
diff --git a/app/code/Magento/Tax/Test/Unit/Helper/DataTest.php b/app/code/Magento/Tax/Test/Unit/Helper/DataTest.php
index ea716a0c474b05572edab18014fa5856079b240a..7a292fdaedb549cccf0365ed968ba5e38b9dc5df 100644
--- a/app/code/Magento/Tax/Test/Unit/Helper/DataTest.php
+++ b/app/code/Magento/Tax/Test/Unit/Helper/DataTest.php
@@ -12,6 +12,8 @@ use Magento\Framework\DataObject as MagentoObject;
 
 /**
  * Class DataTest
+ *
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  */
 class DataTest extends \PHPUnit_Framework_TestCase
 {
@@ -29,6 +31,9 @@ class DataTest extends \PHPUnit_Framework_TestCase
     /** @var  \PHPUnit_Framework_MockObject_MockObject */
     protected $taxConfigMock;
 
+    /** @var  \PHPUnit_Framework_MockObject_MockObject */
+    protected $serializer;
+
     protected function setUp()
     {
         $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
@@ -42,13 +47,31 @@ class DataTest extends \PHPUnit_Framework_TestCase
         $this->taxConfigMock = $this->getMockBuilder(\Magento\Tax\Model\Config::class)
             ->disableOriginalConstructor()
             ->getMock();
+        $this->serializer = $this->getMockBuilder(\Magento\Framework\Serialize\Serializer\Json::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->serializer->expects($this->any())
+            ->method('serialize')
+            ->willReturnCallback(
+                function ($value) {
+                    return json_encode($value);
+                }
+            );
 
-        $this->helper = $objectManager->getObject(
+        $this->serializer->expects($this->any())
+            ->method('unserialize')
+            ->willReturnCallback(
+                function ($value) {
+                    return json_decode($value, true);
+                }
+            );
+        $this->helper = $objectManager->getObject(
             \Magento\Tax\Helper\Data::class,
             [
                 'orderTaxManagement' => $this->orderTaxManagementMock,
                 'priceCurrency' => $this->priceCurrencyMock,
-                'taxConfig' => $this->taxConfigMock
+                'taxConfig' => $this->taxConfigMock,
+                'serializer' => $this->serializer
             ]
         );
     }
@@ -147,7 +170,7 @@ class DataTest extends \PHPUnit_Framework_TestCase
             $appliedTaxesData = $orderTaxDetailsItemData['applied_taxes'];
             $appliedTaxesMocks = [];
             foreach ($appliedTaxesData as $appliedTaxData) {
-                $appliedTaxesMock = $this->getMockBuilder(
+                $appliedTaxesMock = $this->getMockBuilder(
                     \Magento\Tax\Api\Data\OrderTaxDetailsAppliedTaxInterface::class)
                     ->getMock();
                 $appliedTaxesMock->expects($this->any())
@@ -363,7 +386,7 @@ class DataTest extends \PHPUnit_Framework_TestCase
                                         ),
                                     'tax_amount' => 5.0,
                                     //half of weee tax is invoiced
-                                    'tax_ratio' => serialize(['weee' => 0.5]),
+                                    'tax_ratio' => json_encode(['weee' => 0.5]),
                                 ]
                             ),
                     ],
diff --git a/app/code/Magento/Tax/Test/Unit/Model/Quote/GrandTotalDetailsPluginTest.php b/app/code/Magento/Tax/Test/Unit/Model/Quote/GrandTotalDetailsPluginTest.php
index 693b0d437afc45853b5ab224d04c535f1af1ca92..1b2e269e7add46edefdeedabfcb422f86538eed1 100644
--- a/app/code/Magento/Tax/Test/Unit/Model/Quote/GrandTotalDetailsPluginTest.php
+++ b/app/code/Magento/Tax/Test/Unit/Model/Quote/GrandTotalDetailsPluginTest.php
@@ -75,6 +75,26 @@ class GrandTotalDetailsPluginTest extends \PHPUnit_Framework_TestCase
             ->disableOriginalConstructor()
             ->getMock();
 
+        $serializer = $this->getMockBuilder(\Magento\Framework\Serialize\Serializer\Json::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $serializer->expects($this->any())
+            ->method('serialize')
+            ->willReturnCallback(
+                function ($value) {
+                    return json_encode($value);
+                }
+            );
+
+        $serializer->expects($this->any())
+            ->method('unserialize')
+            ->willReturnCallback(
+                function ($value) {
+                    return json_decode($value, true);
+                }
+            );
+
         $this->objectManagerHelper = new ObjectManager($this);
         $this->model = $this->objectManagerHelper->getObject(
             \Magento\Tax\Model\Quote\GrandTotalDetailsPlugin::class,
@@ -83,6 +103,7 @@ class GrandTotalDetailsPluginTest extends \PHPUnit_Framework_TestCase
                 'ratesFactory' => $this->ratesFactoryMock,
                 'detailsFactory' => $this->detailsFactoryMock,
                 'taxConfig' => $this->taxConfigMock,
+                'serializer' => $serializer
             ]
         );
     }
@@ -166,12 +187,12 @@ class GrandTotalDetailsPluginTest extends \PHPUnit_Framework_TestCase
         );
 
         $taxTotalData = [
-            'full_info' => [
+            'full_info' => json_encode([
                 [
                     'amount' => $taxAmount,
                     'rates' => [$taxRate],
                 ],
-            ],
+            ]),
         ];
         $taxTotalMock = $this->setupTaxTotal($taxTotalData);
         $addressTotals = [
diff --git a/app/code/Magento/Tax/Test/Unit/Model/Sales/Total/Quote/TaxTest.php b/app/code/Magento/Tax/Test/Unit/Model/Sales/Total/Quote/TaxTest.php
index a74b5fe13ec784a1dbb1d5f41a837a74c034df08..749ee1424d5031e905b1b7a7b270e1b61f7672fb 100644
--- a/app/code/Magento/Tax/Test/Unit/Model/Sales/Total/Quote/TaxTest.php
+++ b/app/code/Magento/Tax/Test/Unit/Model/Sales/Total/Quote/TaxTest.php
@@ -38,7 +38,7 @@ class TaxTest extends \PHPUnit_Framework_TestCase
      * @SuppressWarnings(PHPMD.UnusedFormalParameter)
      */
     public function testCollect($itemData, $appliedRatesData, $taxDetailsData, $quoteDetailsData,
-        $addressData, $verifyData
+                                $addressData, $verifyData
     ) {
         $this->markTestIncomplete('Source code is not testable. Need to be refactored before unit testing');
         $shippingAssignmentMock = $this->getMock(\Magento\Quote\Api\Data\ShippingAssignmentInterface::class);
@@ -247,8 +247,8 @@ class TaxTest extends \PHPUnit_Framework_TestCase
         $address = $this->getMockBuilder(\Magento\Quote\Model\Quote\Address::class)
             ->disableOriginalConstructor()
             ->setMethods(['getAssociatedTaxables',
-                          'getQuote', 'getBillingAddress', 'getRegionId',
-                          '__wakeup', 'getCustomAttributesCodes'])
+                'getQuote', 'getBillingAddress', 'getRegionId',
+                '__wakeup', 'getCustomAttributesCodes'])
             ->getMock();
         $item
             ->expects($this->any())
@@ -613,13 +613,36 @@ class TaxTest extends \PHPUnit_Framework_TestCase
             ->will($this->returnValue(true));
 
         $objectManager = new ObjectManager($this);
+
+        $serializer = $this->getMockBuilder(\Magento\Framework\Serialize\Serializer\Json::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $serializer->expects($this->any())
+            ->method('serialize')
+            ->willReturnCallback(
+                function ($value) {
+                    return json_encode($value);
+                }
+            );
+
+        $serializer->expects($this->any())
+            ->method('unserialize')
+            ->willReturnCallback(
+                function ($value) {
+                    return json_decode($value, true);
+                }
+            );
+
         /** @var \Magento\Tax\Model\Sales\Total\Quote\Tax $taxTotalsCalcModel */
         $taxTotalsCalcModel = $objectManager->getObject(
             \Magento\Tax\Model\Sales\Total\Quote\Tax::class,
-            ['taxConfig' => $taxConfig]
+            [
+                'taxConfig' => $taxConfig,
+                'serializer' => $serializer
+            ]
         );
 
-        $appliedTaxes = unserialize($appliedTaxesData);
         $store = $this->getMockBuilder(\Magento\Store\Model\Store::class)
             ->disableOriginalConstructor()
             ->setMethods(['convertPrice', '__wakeup'])
@@ -641,7 +664,7 @@ class TaxTest extends \PHPUnit_Framework_TestCase
         $totalsMock
             ->expects($this->once())
             ->method('getAppliedTaxes')
-            ->will($this->returnValue($appliedTaxes));
+            ->will($this->returnValue($appliedTaxesData));
         $totalsMock
             ->expects($this->any())
             ->method('getGrandTotal')
@@ -675,6 +698,7 @@ class TaxTest extends \PHPUnit_Framework_TestCase
         $totalsArray = $taxTotalsCalcModel->fetch($quote, $totalsMock);
         $this->assertArrayHasKey('value', $totalsArray[0]);
         $this->assertEquals($taxAmount, $totalsArray[0]['value']);
+        $this->assertEquals(json_decode($appliedTaxesData, true), $totalsArray[0]['full_info']);
     }
 
     /**
@@ -685,10 +709,26 @@ class TaxTest extends \PHPUnit_Framework_TestCase
      */
     public function dataProviderFetchArray()
     {
-        $appliedDataString = 'a:1:{s:7:"TX Rate";a:9:{s:6:"amount";d:80;s:11:"base_amount";d:80;s:7:"percent";';
-        $appliedDataString .= 'd:10;s:2:"id";s:7:"TX Rate";s:5:"rates";a:1:{i:0;a:3:{s:7:"percent";d:10;s:4:"code";';
-        $appliedDataString .= 's:7:"TX Rate";s:5:"title";s:7:"TX Rate";}}s:7:"item_id";s:1:"1";s:9:"item_type";';
-        $appliedDataString .= 's:7:"product";s:18:"associated_item_id";N;s:7:"process";i:0;}}';
+        $appliedDataString = [
+            'amount' => 80.0,
+            'base_amount' => 80.0,
+            'percent' => 10.0,
+            'id' => 'TX Rate',
+            'rates' => [
+                0 => [
+                    'percent' => 10.0,
+                    'code' => 'TX Rate',
+                    'title' => 'TX Rate',
+                ],
+            ],
+            'item_id' => '1',
+            'item_type' => 'product',
+            'associated_item_id' => NULL,
+            'process' => 0,
+        ];
+
+        $appliedDataString = json_encode($appliedDataString);
+
         $data = [
             'default' => [
                 'appliedTaxesData' => $appliedDataString,
diff --git a/app/code/Magento/Wishlist/Model/Item.php b/app/code/Magento/Wishlist/Model/Item.php
index c68eb5572cf59a9a1451a2a966479ed96ce37f0f..2db7ff7ac20322d3cef0983a9db6d7076b98ddf0 100644
--- a/app/code/Magento/Wishlist/Model/Item.php
+++ b/app/code/Magento/Wishlist/Model/Item.php
@@ -120,6 +120,13 @@ class Item extends AbstractModel implements ItemInterface
      */
     protected $productRepository;
 
+    /**
+     * Serializer interface instance.
+     *
+     * @var \Magento\Framework\Serialize\Serializer\Json
+     */
+    private $serializer;
+
     /**
      * @param \Magento\Framework\Model\Context $context
      * @param \Magento\Framework\Registry $registry
@@ -133,6 +140,7 @@ class Item extends AbstractModel implements ItemInterface
      * @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource
      * @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection
      * @param array $data
+     * @param \Magento\Framework\Serialize\Serializer\Json|null $serializer
      * @SuppressWarnings(PHPMD.ExcessiveParameterList)
      */
     public function __construct(
@@ -147,7 +155,8 @@ class Item extends AbstractModel implements ItemInterface
         ProductRepositoryInterface $productRepository,
         \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
         \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
-        array $data = []
+        array $data = [],
+        \Magento\Framework\Serialize\Serializer\Json $serializer = null
     ) {
         $this->productTypeConfig = $productTypeConfig;
         $this->_storeManager = $storeManager;
@@ -155,6 +164,8 @@ class Item extends AbstractModel implements ItemInterface
         $this->_catalogUrl = $catalogUrl;
         $this->_wishlistOptFactory = $wishlistOptFactory;
         $this->_wishlOptionCollectionFactory = $wishlOptionCollectionFactory;
+        $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance()
+            ->get(\Magento\Framework\Serialize\Serializer\Json::class);
         parent::__construct($context, $registry, $resource, $resourceCollection, $data);
         $this->productRepository = $productRepository;
     }
@@ -472,7 +483,7 @@ class Item extends AbstractModel implements ItemInterface
     public function getBuyRequest()
     {
         $option = $this->getOptionByCode('info_buyRequest');
-        $initialData = $option ? unserialize($option->getValue()) : null;
+        $initialData = $option ? $this->serializer->unserialize($option->getValue()) : null;
 
         if ($initialData instanceof \Magento\Framework\DataObject) {
             $initialData = $initialData->getData();
@@ -500,7 +511,7 @@ class Item extends AbstractModel implements ItemInterface
         }
 
         $oldBuyRequest = $this->getBuyRequest()->getData();
-        $sBuyRequest = serialize($buyRequest + $oldBuyRequest);
+        $sBuyRequest = $this->serializer->serialize($buyRequest + $oldBuyRequest);
 
         $option = $this->getOptionByCode('info_buyRequest');
         if ($option) {
@@ -523,7 +534,7 @@ class Item extends AbstractModel implements ItemInterface
     {
         $buyRequest->setId($this->getId());
 
-        $_buyRequest = serialize($buyRequest->getData());
+        $_buyRequest = $this->serializer->serialize($buyRequest->getData());
         $this->setData('buy_request', $_buyRequest);
         return $this;
     }
diff --git a/app/code/Magento/Wishlist/Setup/UpgradeData.php b/app/code/Magento/Wishlist/Setup/UpgradeData.php
new file mode 100644
index 0000000000000000000000000000000000000000..f18ca29acf333d7ebfc873b973427c6dfa54f0cc
--- /dev/null
+++ b/app/code/Magento/Wishlist/Setup/UpgradeData.php
@@ -0,0 +1,126 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Wishlist\Setup;
+
+use Magento\Framework\Setup\UpgradeDataInterface;
+use Magento\Framework\Setup\ModuleContextInterface;
+use Magento\Framework\Setup\ModuleDataSetupInterface;
+use Magento\Framework\DB\FieldDataConverterFactory;
+use Magento\Framework\DB\DataConverter\SerializedToJson;
+use Magento\Framework\DB\Select\QueryModifierFactory;
+use Magento\Framework\DB\Select\InQueryModifier;
+use Magento\Framework\DB\Query\Generator;
+
+class UpgradeData implements UpgradeDataInterface
+{
+    /**
+     * @var FieldDataConverterFactory
+     */
+    private $fieldDataConverterFactory;
+
+    /**
+     * @var QueryModifierFactory
+     */
+    private $queryModifierFactory;
+
+    /**
+     * @var Generator
+     */
+    private $queryGenerator;
+
+    /**
+     * Constructor
+     *
+     * @param FieldDataConverterFactory $fieldDataConverterFactory
+     * @param QueryModifierFactory $queryModifierFactory
+     * @param Generator $queryGenerator
+     */
+    public function __construct(
+        FieldDataConverterFactory $fieldDataConverterFactory,
+        QueryModifierFactory $queryModifierFactory,
+        Generator $queryGenerator
+    ) {
+        $this->fieldDataConverterFactory = $fieldDataConverterFactory;
+        $this->queryModifierFactory = $queryModifierFactory;
+        $this->queryGenerator = $queryGenerator;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
+    {
+        if (version_compare($context->getVersion(), '2.0.1', '<')) {
+            $this->upgradeToVersionTwoZeroOne($setup);
+        }
+    }
+
+    /**
+     * Upgrade to version 2.0.1, convert data for `value` field in `wishlist_item_option table`
+     * from php-serialized to JSON format
+     *
+     * @param ModuleDataSetupInterface $setup
+     * @return void
+     */
+    private function upgradeToVersionTwoZeroOne(ModuleDataSetupInterface $setup)
+    {
+        $fieldDataConverter = $this->fieldDataConverterFactory->create(SerializedToJson::class);
+        $queryModifier = $this->queryModifierFactory->create(
+            'in',
+            [
+                'values' => [
+                    'code' => [
+                        'parameters',
+                        'info_buyRequest',
+                        'bundle_option_ids',
+                        'bundle_selection_ids',
+                        'attributes',
+                        'bundle_selection_attributes',
+                    ]
+                ]
+            ]
+        );
+        $fieldDataConverter->convert(
+            $setup->getConnection(),
+            $setup->getTable('wishlist_item_option'),
+            'option_id',
+            'value',
+            $queryModifier
+        );
+        $select = $setup->getConnection()
+            ->select()
+            ->from(
+                $setup->getTable('catalog_product_option'),
+                ['option_id']
+            )
+            ->where('type = ?', 'file');
+        $iterator = $this->queryGenerator->generate('option_id', $select);
+        foreach ($iterator as $selectByRange) {
+            $codes = $setup->getConnection()->fetchCol($selectByRange);
+            $codes = array_map(
+                function ($id) {
+                    return 'option_' . $id;
+                },
+                $codes
+            );
+            $queryModifier = $this->queryModifierFactory->create(
+                'in',
+                [
+                    'values' => [
+                        'code' => $codes
+                    ]
+                ]
+            );
+            $fieldDataConverter->convert(
+                $setup->getConnection(),
+                $setup->getTable('wishlist_item_option'),
+                'option_id',
+                'value',
+                $queryModifier
+            );
+        }
+    }
+}
diff --git a/app/code/Magento/Wishlist/etc/module.xml b/app/code/Magento/Wishlist/etc/module.xml
index a8b0fa21edee3e7e5222d290f686ed04c3c2e286..5643b2dc285a9e8158e41bafadc843e4de23005d 100644
--- a/app/code/Magento/Wishlist/etc/module.xml
+++ b/app/code/Magento/Wishlist/etc/module.xml
@@ -6,7 +6,7 @@
  */
 -->
 <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
-    <module name="Magento_Wishlist" setup_version="2.0.0">
+    <module name="Magento_Wishlist" setup_version="2.0.1">
         <sequence>
             <module name="Magento_Customer"/>
             <module name="Magento_Catalog"/>
diff --git a/app/etc/di.xml b/app/etc/di.xml
index 1b347574f4b2a2d3f010cb9a712da6cd6c7dbec2..5e58d5887678d91fdcfcccc1f28f751fa3502177 100755
--- a/app/etc/di.xml
+++ b/app/etc/di.xml
@@ -1214,4 +1214,11 @@
             </argument>
         </arguments>
     </type>
+    <type name="Magento\Framework\DB\Select\QueryModifierFactory">
+        <arguments>
+            <argument name="queryModifiers" xsi:type="array">
+                <item name="in" xsi:type="string">Magento\Framework\DB\Select\InQueryModifier</item>
+            </argument>
+        </arguments>
+    </type>
 </config>
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Option/Type/DateTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Option/Type/DateTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..280996a81d7f609e9ee7cd5351de50ea6ccab0f1
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Option/Type/DateTest.php
@@ -0,0 +1,112 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Catalog\Model\Product\Option\Type;
+
+/**
+ * Test for \Magento\Catalog\Model\Product\Option\Type\Date
+ */
+class DateTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Catalog\Model\Product\Option\Type\Date
+     */
+    protected $model;
+
+    /**
+     * @var \Magento\Framework\ObjectManagerInterface
+     */
+    private $objectManager;
+
+    /**
+     * {@inheritDoc}
+     */
+    protected function setUp()
+    {
+        $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
+        $this->model = $this->objectManager->create(
+            \Magento\Catalog\Model\Product\Option\Type\Date::class
+        );
+    }
+
+    /**
+     * @covers       \Magento\Catalog\Model\Product\Option\Type\Date::prepareOptionValueForRequest()
+     * @dataProvider prepareOptionValueForRequestDataProvider
+     * @param array $optionValue
+     * @param array $infoBuyRequest
+     * @param array $expectedOptionValueForRequest
+     * @param array $productOptionData
+     */
+    public function testPrepareOptionValueForRequest(
+        array $optionValue,
+        array $infoBuyRequest,
+        array $productOptionData,
+        array $expectedOptionValueForRequest
+    ) {
+        /** @var \Magento\Quote\Model\Quote\Item\Option $option */
+        $option = $this->objectManager->create(
+            \Magento\Quote\Model\Quote\Item\Option::class,
+            ['data' => $infoBuyRequest]
+        );
+        /** @var \Magento\Quote\Model\Quote\Item $item */
+        $item = $this->objectManager->create(\Magento\Quote\Model\Quote\Item::class);
+        $item->addOption($option);
+        /** @var \Magento\Catalog\Model\Product\Option|null $productOption */
+        $productOption = $productOptionData
+            ? $this->objectManager->create(
+                \Magento\Catalog\Model\Product\Option::class,
+                ['data' => $productOptionData]
+            )
+            : null;
+        $this->model->setData('quote_item', $item);
+        $this->model->setOption($productOption);
+
+        $actualOptionValueForRequest = $this->model->prepareOptionValueForRequest($optionValue);
+        $this->assertSame($expectedOptionValueForRequest, $actualOptionValueForRequest);
+    }
+
+    /**
+     * @return array
+     */
+    public function prepareOptionValueForRequestDataProvider()
+    {
+        return [
+            // Variation 1
+            [
+                // $optionValue
+                ['field1' => 'value1', 'field2' => 'value2'],
+                // $infoBuyRequest
+                ['code' => 'info_buyRequest', 'value' => '{"qty":23}'],
+                // $productOptionData
+                ['id' => '11', 'value' => '{"qty":12}'],
+                // $expectedOptionValueForRequest
+                ['date_internal' => ['field1' => 'value1', 'field2' => 'value2']]
+            ],
+            // Variation 2
+            [
+                // $optionValue
+                ['field1' => 'value1', 'field2' => 'value2'],
+                // $infoBuyRequest
+                ['code' => 'info_buyRequest', 'value' => '{"options":{"11":{"qty":23}}}'],
+                // $productOptionData
+                ['id' => '11', 'value' => '{"qty":12}'],
+                // $expectedOptionValueForRequest
+                ['qty' => 23]
+            ],
+            // Variation 3
+            [
+                // $optionValue
+                ['field1' => 'value1', 'field2' => 'value2'],
+                // $infoBuyRequest
+                ['code' => 'info_buyRequest', 'value' => '{"options":{"11":{"qty":23}}}'],
+                // $productOptionData
+                [],
+                // $expectedOptionValueForRequest
+                ['date_internal' => ['field1' => 'value1', 'field2' => 'value2']]
+            ],
+        ];
+    }
+}
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Type/AbstractTypeTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Type/AbstractTypeTest.php
index 6f98f0f413bf2e3bcd336ca1c392b39462a48f82..17c29a4e82ad345871c49cc0ee12f9ae5005d74a 100644
--- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Type/AbstractTypeTest.php
+++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Type/AbstractTypeTest.php
@@ -35,6 +35,9 @@ class AbstractTypeTest extends \PHPUnit_Framework_TestCase
         $filesystem = $this->getMock(\Magento\Framework\Filesystem::class, [], [], '', false);
         $registry = $this->getMock(\Magento\Framework\Registry::class, [], [], '', false);
         $logger = $this->getMock(\Psr\Log\LoggerInterface::class, [], [], '', false);
+        $serializer = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(
+            \Magento\Framework\Serialize\Serializer\Json::class
+        );
         $this->_model = $this->getMockForAbstractClass(
             \Magento\Catalog\Model\Product\Type\AbstractType::class,
             [
@@ -46,7 +49,8 @@ class AbstractTypeTest extends \PHPUnit_Framework_TestCase
                 $filesystem,
                 $registry,
                 $logger,
-                $productRepository
+                $productRepository,
+                $serializer
             ]
         );
     }
@@ -186,7 +190,7 @@ class AbstractTypeTest extends \PHPUnit_Framework_TestCase
         $this->assertInstanceOf(\Magento\Framework\DataObject::class, $buyRequest);
         $this->assertEquals($product->getId(), $buyRequest->getProductId());
         $this->assertSame($product, $buyRequest->getProduct());
-        $this->assertEquals(serialize($requestData), $buyRequest->getValue());
+        $this->assertEquals(json_encode($requestData), $buyRequest->getValue());
     }
 
     /**
diff --git a/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_payment_saved.php b/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_payment_saved.php
index c3dbc4baaf3f77b38c9e18948798e814cc545cc7..f1759a9eb0c4ba12edaaceb569d788c4129496e1 100644
--- a/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_payment_saved.php
+++ b/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_payment_saved.php
@@ -6,6 +6,9 @@
 
 require 'quote_with_address.php';
 
+/** @var \Magento\Framework\Serialize\Serializer\Json $serializer */
+$serializer = $objectManager->create(\Magento\Framework\Serialize\Serializer\Json::class);
+
 $quote->setReservedOrderId(
     'test_order_1_with_payment'
 );
@@ -22,7 +25,7 @@ $quote->getPayment()
     ->setCcType('visa')
     ->setCcExpYear(2014)
     ->setCcExpMonth(1)
-    ->setAdditionalData(serialize($paymentDetails));
+    ->setAdditionalData($serializer->serialize($paymentDetails));
 
 $quote->collectTotals()->save();
 
diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Product/Type/ConfigurableTest.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Product/Type/ConfigurableTest.php
index 59d828baa2d5ce381e3e2076d51bad0c1408a1bf..69179686d3ee47e0e0600d264fb4e21aef2a102b 100644
--- a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Product/Type/ConfigurableTest.php
+++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Product/Type/ConfigurableTest.php
@@ -11,7 +11,6 @@ namespace Magento\ConfigurableProduct\Model\Product\Type;
 use Magento\Catalog\Api\Data\ProductInterface;
 use Magento\Catalog\Api\ProductRepositoryInterface;
 use Magento\Catalog\Model\Product;
-use Magento\ConfigurableProduct\Model\Product\Type\Configurable;
 use Magento\TestFramework\Helper\Bootstrap;
 
 /**
@@ -294,29 +293,42 @@ class ConfigurableTest extends \PHPUnit_Framework_TestCase
      */
     public function testGetSelectedAttributesInfo()
     {
+        /** @var $serializer \Magento\Framework\Serialize\Serializer\Json */
+        $serializer = Bootstrap::getObjectManager()->create(\Magento\Framework\Serialize\Serializer\Json::class);
+
         $product = $this->productRepository->getById(1, true);
         $attributes = $this->model->getConfigurableAttributesAsArray($product);
         $attribute = reset($attributes);
         $optionValueId = $attribute['values'][0]['value_index'];
 
-        $product->addCustomOption('attributes', serialize([$attribute['attribute_id'] => $optionValueId]));
+        $product->addCustomOption('attributes',
+            $serializer->serialize([$attribute['attribute_id'] => $optionValueId])
+        );
+
         $info = $this->model->getSelectedAttributesInfo($product);
         $this->assertEquals('Test Configurable', $info[0]['label']);
         $this->assertEquals('Option 1', $info[0]['value']);
     }
 
     /**
+     * @covers \Magento\ConfigurableProduct\Model\Product\Type\Configurable::getConfigurableAttributes()
      * @magentoDataFixture Magento/ConfigurableProduct/_files/product_configurable.php
      * @magentoAppIsolation enabled
      */
     public function testGetSelectedAttributesInfoForStore()
     {
+        /** @var $serializer \Magento\Framework\Serialize\Serializer\Json */
+        $serializer = Bootstrap::getObjectManager()->create(\Magento\Framework\Serialize\Serializer\Json::class);
+
         $attributes = $this->model->getConfigurableAttributesAsArray($this->product);
 
         $attribute = reset($attributes);
         $optionValueId = $attribute['values'][0]['value_index'];
 
-        $this->product->addCustomOption('attributes', serialize([$attribute['attribute_id'] => $optionValueId]));
+        $this->product->addCustomOption(
+            'attributes',
+            $serializer->serialize([$attribute['attribute_id'] => $optionValueId])
+        );
 
         $configurableAttr = $this->model->getConfigurableAttributes($this->product);
         $attribute = $configurableAttr->getFirstItem();
diff --git a/dev/tests/integration/testsuite/Magento/Downloadable/Model/Product/TypeTest.php b/dev/tests/integration/testsuite/Magento/Downloadable/Model/Product/TypeTest.php
index c9c9109ac95dfdef8d40ec1c69ff12547d201dd7..c3b6d668fdad11f7a154099ce404222b41aca303 100644
--- a/dev/tests/integration/testsuite/Magento/Downloadable/Model/Product/TypeTest.php
+++ b/dev/tests/integration/testsuite/Magento/Downloadable/Model/Product/TypeTest.php
@@ -19,9 +19,15 @@ class TypeTest extends \PHPUnit_Framework_TestCase
      */
     protected $_model;
 
+    /**
+     * @var \Magento\Framework\ObjectManagerInterface
+     */
+    private $objectManager;
+
     protected function setUp()
     {
-        $this->_model = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
+        $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
+        $this->_model = $this->objectManager->create(
             \Magento\Downloadable\Model\Product\Type::class
         );
     }
@@ -216,4 +222,37 @@ class TypeTest extends \PHPUnit_Framework_TestCase
             $this->assertEquals($value, $sample[$key]);
         }
     }
+
+    /**
+     * @magentoAppIsolation enabled
+     * @magentoDbIsolation enabled
+     * @magentoDataFixture Magento/Downloadable/_files/product_downloadable.php
+     * @covers \Magento\Downloadable\Model\Product\Type::checkProductBuyState()
+     */
+    public function testCheckProductBuyState()
+    {
+        /** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */
+        $productRepository =$this->objectManager->create(
+            \Magento\Catalog\Api\ProductRepositoryInterface::class
+        );
+        $product = $productRepository->get('downloadable-product');
+        $product->setLinksPurchasedSeparately(false);
+        $productRepository->save($product);
+        /** @var \Magento\Quote\Model\Quote\Item\Option $option */
+        $option = $this->objectManager->create(
+            \Magento\Quote\Model\Quote\Item\Option::class,
+            ['data' => ['code' => 'info_buyRequest', 'value' => '{"qty":23}']]
+        );
+        $option->setProduct($product);
+        $product->setCustomOptions(['info_buyRequest' => $option]);
+
+        $this->_model->checkProductBuyState($product);
+        $linksFactory = $this->objectManager
+            ->get(\Magento\Downloadable\Model\ResourceModel\Link\CollectionFactory::class);
+        $allLinksIds = $linksFactory->create()->addProductToFilter($product->getEntityId())->getAllIds();
+        $this->assertEquals(
+            '{"qty":23,"links":["' . implode('","', $allLinksIds). '"]}',
+            $product->getCustomOption('info_buyRequest')->getValue()
+        );
+    }
 }
diff --git a/dev/tests/integration/testsuite/Magento/Downloadable/_files/order_with_downloadable_product_with_additional_options.php b/dev/tests/integration/testsuite/Magento/Downloadable/_files/order_with_downloadable_product_with_additional_options.php
new file mode 100644
index 0000000000000000000000000000000000000000..46caf347a098b8eddec390c6ec706696c3381ef8
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Downloadable/_files/order_with_downloadable_product_with_additional_options.php
@@ -0,0 +1,61 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+// @codingStandardsIgnoreFile
+
+$billingAddress = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
+    \Magento\Sales\Model\Order\Address::class,
+    [
+        'data' => [
+            'firstname' => 'guest',
+            'lastname' => 'guest',
+            'email' => 'customer@example.com',
+            'street' => 'street',
+            'city' => 'Los Angeles',
+            'region' => 'CA',
+            'postcode' => '1',
+            'country_id' => 'US',
+            'telephone' => '1',
+        ]
+    ]
+);
+$billingAddress->setAddressType('billing');
+
+$payment = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
+    \Magento\Sales\Model\Order\Payment::class);
+$payment->setMethod('checkmo');
+
+$orderItem = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
+    \Magento\Sales\Model\Order\Item::class);
+$orderItem->setProductId(
+    1
+)->setProductType(
+    \Magento\Downloadable\Model\Product\Type::TYPE_DOWNLOADABLE
+)->setBasePrice(
+    100
+)->setQtyOrdered(
+    1
+);
+$orderItem->setProductOptions(['additional_options' => ['additional_option_key' => 'additional_option_value']]);
+
+$order = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Sales\Model\Order::class);
+$order->setCustomerEmail('mail@to.co')
+    ->addItem(
+    $orderItem
+)->setIncrementId(
+    '100000001'
+)->setCustomerIsGuest(
+    true
+)->setStoreId(
+    1
+)->setEmailSent(
+    1
+)->setBillingAddress(
+    $billingAddress
+)->setPayment(
+    $payment
+);
+$order->save();
diff --git a/dev/tests/integration/testsuite/Magento/GroupedProduct/Model/Product/Type/GroupedTest.php b/dev/tests/integration/testsuite/Magento/GroupedProduct/Model/Product/Type/GroupedTest.php
index dfff15995ecf4e9ccd4dc15b12630f55348c4999..97762b6c39c3c9ee305053100fd3f82cbb16f1c5 100644
--- a/dev/tests/integration/testsuite/Magento/GroupedProduct/Model/Product/Type/GroupedTest.php
+++ b/dev/tests/integration/testsuite/Magento/GroupedProduct/Model/Product/Type/GroupedTest.php
@@ -80,4 +80,51 @@ class GroupedTest extends \PHPUnit_Framework_TestCase
         $this->assertEquals($data[$productId]['qty'], $product->getQty());
         $this->assertEquals($data[$productId]['position'], $product->getPosition());
     }
+
+    /**
+     * @magentoDataFixture Magento/GroupedProduct/_files/product_grouped.php
+     * @magentoAppIsolation enabled
+     * @magentoDbIsolation disabled
+     */
+    public function testPrepareProduct()
+    {
+        $buyRequest = $this->objectManager->create(
+            \Magento\Framework\DataObject::class,
+            ['data' => ['value' => ['qty' => 2]]]
+        );
+        /** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */
+        $productRepository = $this->objectManager->get(\Magento\Catalog\Api\ProductRepositoryInterface::class);
+        $product = $productRepository->get('grouped-product');
+
+        /** @var \Magento\GroupedProduct\Model\Product\Type\Grouped $type */
+        $type = $this->objectManager->get(\Magento\GroupedProduct\Model\Product\Type\Grouped::class);
+
+        $processModes = [
+            \Magento\GroupedProduct\Model\Product\Type\Grouped::PROCESS_MODE_FULL,
+            \Magento\GroupedProduct\Model\Product\Type\Grouped::PROCESS_MODE_LITE
+        ];
+        $expectedData = [
+            \Magento\GroupedProduct\Model\Product\Type\Grouped::PROCESS_MODE_FULL => [
+                1  => '{"super_product_config":{"product_type":"grouped","product_id":"'
+                    . $product->getId() . '"}}',
+                21 => '{"super_product_config":{"product_type":"grouped","product_id":"'
+                    . $product->getId() . '"}}',
+            ],
+            \Magento\GroupedProduct\Model\Product\Type\Grouped::PROCESS_MODE_LITE => [
+                $product->getId() => '{"value":{"qty":2}}',
+            ]
+        ];
+
+        foreach ($processModes as $processMode) {
+            $products = $type->processConfiguration($buyRequest, $product, $processMode);
+            foreach ($products as $item) {
+                $productId = $item->getId();
+                $this->assertEquals(
+                    $expectedData[$processMode][$productId],
+                    $item->getCustomOptions()['info_buyRequest']->getValue(),
+                    "Wrong info_buyRequest data for product with id: $productId"
+                );
+            }
+        }
+    }
 }
diff --git a/dev/tests/integration/testsuite/Magento/Quote/Model/Quote/AddressTest.php b/dev/tests/integration/testsuite/Magento/Quote/Model/Quote/AddressTest.php
index d71f5c2df7e10d433042d807a4710e8ff7320498..ad7b87407608cc06db83ab6b801e7089dc3bfa7c 100644
--- a/dev/tests/integration/testsuite/Magento/Quote/Model/Quote/AddressTest.php
+++ b/dev/tests/integration/testsuite/Magento/Quote/Model/Quote/AddressTest.php
@@ -285,4 +285,28 @@ class AddressTest extends \PHPUnit_Framework_TestCase
         $this->assertEquals($this->_quote->getId(), $this->_address->getQuoteId());
         $this->assertEquals($customerAddressId, $this->_address->getCustomerAddressId());
     }
+
+    /**
+     * Tests
+     *
+     * @covers \Magento\Quote\Model\Quote\Address::setAppliedTaxes()
+     * @covers \Magento\Quote\Model\Quote\Address::getAppliedTaxes()
+     * @dataProvider dataProvider
+     * @param $taxes
+     * @param $expected
+     */
+    public function testAppliedTaxes($taxes, $expected)
+    {
+        $this->_address->setAppliedTaxes($taxes);
+
+        $this->assertSame($expected, $this->_address->getAppliedTaxes());
+    }
+
+    public function dataProvider()
+    {
+        return [
+            ['test', 'test'],
+            [[123, true], [123, true]]
+        ];
+    }
 }
diff --git a/dev/tests/integration/testsuite/Magento/Sales/Model/AdminOrder/CreateTest.php b/dev/tests/integration/testsuite/Magento/Sales/Model/AdminOrder/CreateTest.php
index f8ca1929df91e1452ef6f66bd594ebd0e3a3d5fd..acbbbef1b1ed67f25d9f3bd5aa51cf4e120dac78 100644
--- a/dev/tests/integration/testsuite/Magento/Sales/Model/AdminOrder/CreateTest.php
+++ b/dev/tests/integration/testsuite/Magento/Sales/Model/AdminOrder/CreateTest.php
@@ -52,6 +52,63 @@ class CreateTest extends \PHPUnit_Framework_TestCase
         $this->assertNull($order->getShippingAddress());
     }
 
+    /**
+     * @magentoDataFixture Magento/Customer/_files/customer.php
+     * @magentoDataFixture Magento/Downloadable/_files/product_downloadable.php
+     * @magentoDataFixture Magento/Downloadable/_files/order_with_downloadable_product_with_additional_options.php
+     * @magentoDbIsolation enabled
+     * @magentoAppIsolation enabled
+     */
+    public function testInitFromOrderAndCreateOrderFromQuoteWithAdditionalOptions()
+    {
+        /** @var $serializer \Magento\Framework\Serialize\Serializer\Json */
+        $serializer = Bootstrap::getObjectManager()->create(\Magento\Framework\Serialize\Serializer\Json::class);
+
+        /** @var $order \Magento\Sales\Model\Order */
+        $order = Bootstrap::getObjectManager()->create(\Magento\Sales\Model\Order::class);
+        $order->loadByIncrementId('100000001');
+
+        /** @var $orderCreate \Magento\Sales\Model\AdminOrder\Create */
+        $orderCreate = $this->_model->initFromOrder($order);
+
+        $quoteItems = $orderCreate->getQuote()->getItemsCollection();
+
+        $this->assertEquals(1, $quoteItems->count());
+
+        $quoteItem = $quoteItems->getFirstItem();
+        $quoteItemOptions = $quoteItem->getOptionsByCode();
+
+        $this->assertEquals(
+            $serializer->serialize(['additional_option_key' => 'additional_option_value']),
+            $quoteItemOptions['additional_options']->getValue()
+        );
+
+        $session = Bootstrap::getObjectManager()->get(\Magento\Backend\Model\Session\Quote::class);
+        $session->setCustomerId(1);
+
+        $customer = Bootstrap::getObjectManager()->create(\Magento\Customer\Model\Customer::class);
+        $customer->load(1)->setDefaultBilling(null)->setDefaultShipping(null)->save();
+
+        $rate = Bootstrap::getObjectManager()->create(\Magento\Quote\Model\Quote\Address\Rate::class);
+        $rate->setCode('freeshipping_freeshipping');
+
+        $this->_model->getQuote()->getShippingAddress()->addShippingRate($rate);
+        $this->_model->setShippingAsBilling(0);
+        $this->_model->setPaymentData(['method' => 'checkmo']);
+
+        $newOrder = $this->_model->createOrder();
+        $newOrderItems = $newOrder->getItemsCollection();
+
+        $this->assertEquals(1, $newOrderItems->count());
+
+        $newOrderItem = $newOrderItems->getFirstItem();
+
+        $this->assertEquals(
+            ['additional_option_key' => 'additional_option_value'],
+            $newOrderItem->getProductOptionByCode('additional_options')
+        );
+    }
+
     /**
      * @magentoDataFixture Magento/Downloadable/_files/product_downloadable.php
      * @magentoDataFixture Magento/Downloadable/_files/order_with_downloadable_product.php
@@ -451,9 +508,9 @@ class CreateTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * @magentoAppIsolation enabled
      * @magentoDataFixture Magento/Sales/_files/quote.php
      * @magentoDataFixture Magento/Customer/_files/customer.php
+     * @magentoAppIsolation enabled
      */
     public function testGetCustomerCartExistingCart()
     {
@@ -477,6 +534,32 @@ class CreateTest extends \PHPUnit_Framework_TestCase
         $this->assertSame($customerQuote, $customerQuoteFromCache, 'Customer quote caching does not work correctly.');
     }
 
+    /**
+     * @magentoDataFixture Magento/Sales/_files/quote.php
+     * @magentoDataFixture Magento/Customer/_files/customer.php
+     * @magentoAppIsolation enabled
+     */
+    public function testMoveQuoteItemToCart()
+    {
+        $fixtureCustomerId = 1;
+
+        /** Preconditions */
+        /** @var \Magento\Backend\Model\Session\Quote $session */
+        $session = Bootstrap::getObjectManager()->create(\Magento\Backend\Model\Session\Quote::class);
+        $session->setCustomerId($fixtureCustomerId);
+        /** @var $quoteFixture \Magento\Quote\Model\Quote */
+        $quoteFixture = Bootstrap::getObjectManager()->create(\Magento\Quote\Model\Quote::class);
+        $quoteFixture->load('test01', 'reserved_order_id');
+        $quoteFixture->setCustomerIsGuest(false)->setCustomerId($fixtureCustomerId)->save();
+
+        $customerQuote = $this->_model->getCustomerCart();
+        $item = $customerQuote->getAllVisibleItems()[0];
+
+        $this->_model->moveQuoteItem($item, 'cart', 3);
+        $this->assertEquals(4, $item->getQty(), 'Number of Qty isn\'t correct for Quote item.');
+        $this->assertEquals(3, $item->getQtyToAdd(), 'Number of added qty isn\'t correct for Quote item.');
+    }
+
     /**
      * @magentoAppIsolation enabled
      * @magentoDbIsolation enabled
diff --git a/dev/tests/integration/testsuite/Magento/Sales/Model/Order/CreditmemoFactoryTest.php b/dev/tests/integration/testsuite/Magento/Sales/Model/Order/CreditmemoFactoryTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..64de21811dddf880fe79eab56feacbbda9f86891
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Sales/Model/Order/CreditmemoFactoryTest.php
@@ -0,0 +1,100 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model\Order;
+
+/**
+ * Test for CreditmemoFactory class.
+ * @magentoDbIsolation enabled
+ */
+class CreditmemoFactoryTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * Placeholder for order item id field.
+     */
+    const ORDER_ITEM_ID_PLACEHOLDER = 'id_item_';
+
+    /**
+     * @var \Magento\Framework\ObjectManagerInterface
+     */
+    private $objectManager;
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function setUp()
+    {
+        $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
+    }
+
+    /**
+     * @magentoDataFixture Magento/Sales/_files/order_with_dummy_item_and_invoiced.php
+     * @dataProvider createByOrderDataProvider
+     * @param array $creditmemoData
+     * @param int $expectedQty
+     */
+    public function testCreateByOrder(array $creditmemoData, $expectedQty)
+    {
+        /** @var \Magento\Sales\Model\Order $order */
+        $order = $this->objectManager->create(\Magento\Sales\Model\Order::class);
+        $order->loadByIncrementId('100000001');
+        /** @var \Magento\Sales\Model\Order\CreditmemoFactory $creditmemoFactory */
+        $creditmemoFactory = $this->objectManager->create(\Magento\Sales\Model\Order\CreditmemoFactory::class);
+        $creditmemoData = $this->prepareCreditMemoData($order, $creditmemoData);
+        $creditmemo = $creditmemoFactory->createByOrder($order, $creditmemoData);
+        $this->assertEquals($expectedQty, $creditmemo->getTotalQty(), 'Creditmemo has wrong total qty.');
+    }
+
+    /**
+     * Prepare Creditmemo data.
+     *
+     * @param \Magento\Sales\Model\Order $order
+     * @param array $creditmemoData
+     * @return array
+     */
+    private function prepareCreditMemoData(\Magento\Sales\Model\Order $order, array $creditmemoData)
+    {
+        $result = [];
+        $orderItems = $order->getAllItems();
+        foreach ($creditmemoData['qtys'] as $key => $item) {
+            $result[$orderItems[$this->prepareOrderItemKey($key)]->getId()] = $item;
+        }
+        $creditmemoData['qtys'] = $result;
+
+        return $creditmemoData;
+    }
+
+    /**
+     * Prepare order item key.
+     *
+     * @param string $key
+     * @return int
+     */
+    private function prepareOrderItemKey($key)
+    {
+        return str_replace(self::ORDER_ITEM_ID_PLACEHOLDER, '', $key) - 1;
+    }
+
+    /**
+     * @return array
+     */
+    public function createByOrderDataProvider()
+    {
+        return [
+            // Variation #1
+            [
+                //$creditmemoData
+                [
+                    'qtys' => [
+                        self::ORDER_ITEM_ID_PLACEHOLDER . '1' => 1,
+                        self::ORDER_ITEM_ID_PLACEHOLDER . '2' => 1,
+                    ]
+                ],
+                //$expectedQty
+                4
+            ]
+        ];
+    }
+}
diff --git a/dev/tests/integration/testsuite/Magento/Sales/Model/Order/ItemTest.php b/dev/tests/integration/testsuite/Magento/Sales/Model/Order/ItemTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..2b0ec3bc7cac9f5cbceace9cdabefec30d98d980
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Sales/Model/Order/ItemTest.php
@@ -0,0 +1,55 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Sales\Model\Order;
+
+/**
+ * Item test class.
+ */
+class ItemTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @param string $options
+     * @param array $expectedData
+     * @dataProvider getProductOptionsDataProvider
+     */
+    public function testGetProductOptions($options, $expectedData)
+    {
+        $model = \Magento\Framework\App\ObjectManager::getInstance()->get(\Magento\Sales\Model\Order\Item::class);
+        $model->setData('product_options', $options);
+        $this->assertEquals($expectedData, $model->getProductOptions());
+    }
+
+    /**
+     * @return array
+     */
+    public function getProductOptionsDataProvider()
+    {
+        return [
+            // Variation #1
+            [
+                // $options
+                '{"option1":1,"option2":2}',
+                //$expectedData
+                ["option1" => 1, "option2" => 2]
+            ],
+            // Variation #2
+            [
+                // $options
+                'a:2:{s:7:"option1";i:1;s:7:"option2";i:2;}',
+                //$expectedData
+                null
+            ],
+            // Variation #3
+            [
+                // $options
+                ["option1" => 1, "option2" => 2],
+                //$expectedData
+                ["option1" => 1, "option2" => 2]
+            ],
+        ];
+    }
+}
diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_dummy_item_and_invoiced.php b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_dummy_item_and_invoiced.php
new file mode 100644
index 0000000000000000000000000000000000000000..49671242a6793299af729629affa5ccadb187923
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_dummy_item_and_invoiced.php
@@ -0,0 +1,73 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+require 'order.php';
+/** @var \Magento\Sales\Model\Order $order */
+
+$orderItems = [
+    [
+        \Magento\Sales\Api\Data\OrderItemInterface::PRODUCT_ID   => 2,
+        \Magento\Sales\Api\Data\OrderItemInterface::BASE_PRICE   => 100,
+        \Magento\Sales\Api\Data\OrderItemInterface::ORDER_ID     => $order->getId(),
+        \Magento\Sales\Api\Data\OrderItemInterface::QTY_ORDERED  => 2,
+        \Magento\Sales\Api\Data\OrderItemInterface::QTY_INVOICED => 2,
+        \Magento\Sales\Api\Data\OrderItemInterface::PRICE        => 100,
+        \Magento\Sales\Api\Data\OrderItemInterface::ROW_TOTAL    => 102,
+        \Magento\Sales\Api\Data\OrderItemInterface::PRODUCT_TYPE => 'bundle',
+        'children'                                               => [
+            [
+                \Magento\Sales\Api\Data\OrderItemInterface::PRODUCT_ID   => 13,
+                \Magento\Sales\Api\Data\OrderItemInterface::ORDER_ID     => $order->getId(),
+                \Magento\Sales\Api\Data\OrderItemInterface::QTY_ORDERED  => 2,
+                \Magento\Sales\Api\Data\OrderItemInterface::QTY_INVOICED => 2,
+                \Magento\Sales\Api\Data\OrderItemInterface::BASE_PRICE   => 90,
+                \Magento\Sales\Api\Data\OrderItemInterface::PRICE        => 90,
+                \Magento\Sales\Api\Data\OrderItemInterface::ROW_TOTAL    => 92,
+                \Magento\Sales\Api\Data\OrderItemInterface::PRODUCT_TYPE => 'simple',
+                'product_options'                                        => [
+                    'bundle_selection_attributes' => '{"qty":2}',
+                ],
+            ]
+        ],
+    ]
+];
+
+// Invoiced all existing order items.
+foreach ($order->getAllItems() as $item) {
+    $item->setQtyInvoiced(1);
+    $item->save();
+}
+
+saveOrderItems($orderItems);
+
+
+/**
+ * Save Order Items.
+ *
+ * @param array $orderItems
+ * @param \Magento\Sales\Model\Order\Item|null $parentOrderItem [optional]
+ * @return void
+ */
+function saveOrderItems(array $orderItems, $parentOrderItem = null)
+{
+    /** @var array $orderItemData */
+    foreach ($orderItems as $orderItemData) {
+        /** @var $orderItem \Magento\Sales\Model\Order\Item */
+        $orderItem = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
+            \Magento\Sales\Model\Order\Item::class
+        );
+        if (null !== $parentOrderItem) {
+            $orderItemData['parent_item'] = $parentOrderItem;
+        }
+        $orderItem
+            ->setData($orderItemData)
+            ->save();
+
+        if (isset($orderItemData['children'])) {
+            saveOrderItems($orderItemData['children'], $orderItem);
+        }
+    }
+}
diff --git a/dev/tests/integration/testsuite/Magento/Wishlist/Model/ItemTest.php b/dev/tests/integration/testsuite/Magento/Wishlist/Model/ItemTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..004b605a7f1d7e6c355c4a6981961b347523b18c
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Wishlist/Model/ItemTest.php
@@ -0,0 +1,79 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Wishlist\Model;
+
+/**
+ * Item test class.
+ */
+class ItemTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Framework\App\ObjectManager
+     */
+    private $objectManager;
+
+    /**
+     * @var \Magento\Wishlist\Model\Item
+     */
+    private $model;
+
+    /**
+     * {@inheritDoc}
+     */
+    public function setUp()
+    {
+        $this->objectManager = \Magento\Framework\App\ObjectManager::getInstance();
+        $this->model = $this->objectManager->get(\Magento\Wishlist\Model\Item::class);
+    }
+
+    /**
+     * @magentoDataFixture Magento/Catalog/_files/product_simple.php
+     * @magentoAppIsolation enabled
+     * @magentoDbIsolation enabled
+     */
+    public function testBuyRequest()
+    {
+        /** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */
+        $productRepository = $this->objectManager->get(\Magento\Catalog\Api\ProductRepositoryInterface::class);
+        $product = $productRepository->getById(1);
+
+        /** @var \Magento\Wishlist\Model\Item\Option $option */
+        $option = $this->objectManager->create(
+            \Magento\Wishlist\Model\Item\Option::class,
+            ['data' => ['code' => 'info_buyRequest', 'value' => '{"qty":23}']]
+        );
+        $option->setProduct($product);
+        $this->model->addOption($option);
+
+        // Assert getBuyRequest method
+        $buyRequest = $this->model->getBuyRequest();
+        $this->assertEquals($buyRequest->getOriginalQty(), 23);
+
+        // Assert mergeBuyRequest method
+        $this->model->mergeBuyRequest(['qty' => 11, 'additional_data' => 'some value']);
+        $buyRequest = $this->model->getBuyRequest();
+        $this->assertEquals(
+            ['additional_data' => 'some value', 'qty' => 0, 'original_qty' => 11],
+            $buyRequest->getData()
+        );
+    }
+
+    public function testSetBuyRequest()
+    {
+        $buyRequest = $this->objectManager->create(
+            \Magento\Framework\DataObject::class,
+            ['data' => ['field_1' => 'some data', 'field_2' => 234]]
+        );
+
+        $this->model->setBuyRequest($buyRequest);
+
+        $this->assertEquals(
+            '{"field_1":"some data","field_2":234,"id":null}',
+            $this->model->getData('buy_request')
+        );
+    }
+}
diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/ObsoleteCodeTest.php b/dev/tests/static/testsuite/Magento/Test/Legacy/ObsoleteCodeTest.php
index ec670e2f2ea249c19c3ef2bd4001ce6a9d177fcc..2c3ee9649dc3ae37c82d41ad707fa0b25bf0853e 100644
--- a/dev/tests/static/testsuite/Magento/Test/Legacy/ObsoleteCodeTest.php
+++ b/dev/tests/static/testsuite/Magento/Test/Legacy/ObsoleteCodeTest.php
@@ -196,10 +196,11 @@ class ObsoleteCodeTest extends \PHPUnit_Framework_TestCase
      */
     protected function _testObsoleteClasses($content)
     {
+        /* avoid collision between obsolete class name and valid namespace and package tag */
+        $content = preg_replace('/namespace[^;]+;/', '', $content);
+        $content = preg_replace('/\@package\s[a-zA-Z0-9\\\_]+/', '', $content);
         foreach (self::$_classes as $row) {
             list($class, , $replacement) = $row;
-            /* avoid collision between obsolete class name and valid namespace */
-            $content = preg_replace('/namespace[^;]+;/', '', $content);
             $this->_assertNotRegExp(
                 '/[^a-z\d_]' . preg_quote($class, '/') . '[^a-z\d_\\\\]/iS',
                 $content,
diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/restricted_classes.php b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/restricted_classes.php
index 683449d4e5e34b919ef476d93c26fe01d122b0a8..1c593657742f9f5605f94ce116ae89c05fb54962 100644
--- a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/restricted_classes.php
+++ b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/restricted_classes.php
@@ -45,11 +45,6 @@ return [
     'Magento\Framework\Serialize\Serializer\Serialize' => [
         'replacement' => 'Magento\Framework\Serialize\SerializerInterface',
         'exclude' => [
-            [
-                'type' => 'library',
-                'name' => 'magento/framework',
-                'path' => 'DB/Adapter/Pdo/Mysql.php'
-            ],
             [
                 'type' => 'library',
                 'name' => 'magento/framework',
@@ -69,6 +64,21 @@ return [
                 'name' => 'magento/framework',
                 'path' => 'App/ObjectManager/ConfigLoader.php'
             ],
+            [
+                'type' => 'library',
+                'name' => 'magento/framework',
+                'path' => 'DB/Adapter/Pdo/Mysql.php'
+            ],
+            [
+                'type' => 'library',
+                'name' => 'magento/framework',
+                'path' => 'DB/DataConverter/SerializedToJson.php'
+            ],
+            [
+                'type' => 'library',
+                'name' => 'magento/framework',
+                'path' => 'DB/Test/Unit/DataConverter/SerializedToJsonTest.php'
+            ],
             [
                 'type' => 'library',
                 'name' => 'magento/framework',
@@ -98,6 +108,16 @@ return [
                 'type' => 'setup',
                 'path' => 'src/Magento/Setup/Module/Di/Compiler/Config/Writer/Filesystem.php'
             ],
+            [
+                'type' => 'module',
+                'name' => 'Magento_Sales',
+                'path' => 'Setup/SerializedDataConverter.php'
+            ],
+            [
+                'type' => 'module',
+                'name' => 'Magento_Sales',
+                'path' => 'Test/Unit/Setup/SerializedDataConverterTest.php'
+            ],
         ]
     ]
 ];
diff --git a/lib/internal/Magento/Framework/DB/DataConverter/DataConverterInterface.php b/lib/internal/Magento/Framework/DB/DataConverter/DataConverterInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..a2ca45ea638ded298e75b5115364abb77dad86b9
--- /dev/null
+++ b/lib/internal/Magento/Framework/DB/DataConverter/DataConverterInterface.php
@@ -0,0 +1,20 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Framework\DB\DataConverter;
+
+/**
+ * Convert from one format to another
+ */
+interface DataConverterInterface
+{
+    /**
+     * Convert from one format to another
+     *
+     * @param string $value
+     * @return string
+     */
+    public function convert($value);
+}
diff --git a/lib/internal/Magento/Framework/DB/DataConverter/SerializedToJson.php b/lib/internal/Magento/Framework/DB/DataConverter/SerializedToJson.php
new file mode 100644
index 0000000000000000000000000000000000000000..ae675784021d4d5f3e0d89d54088dfd4f92d64ab
--- /dev/null
+++ b/lib/internal/Magento/Framework/DB/DataConverter/SerializedToJson.php
@@ -0,0 +1,50 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Framework\DB\DataConverter;
+
+use Magento\Framework\Serialize\Serializer\Serialize;
+use Magento\Framework\Serialize\Serializer\Json;
+
+/**
+ * Convert from serialized to JSON format
+ */
+class SerializedToJson implements DataConverterInterface
+{
+    /**
+     * @var Serialize
+     */
+    private $serialize;
+
+    /**
+     * @var Json
+     */
+    private $json;
+
+    /**
+     * Constructor
+     *
+     * @param Serialize $serialize
+     * @param Json $json
+     */
+    public function __construct(
+        Serialize $serialize,
+        Json $json
+    ) {
+        $this->serialize = $serialize;
+        $this->json = $json;
+    }
+
+    /**
+     * Convert from serialized to JSON format
+     *
+     * @param string $value
+     * @return string
+     */
+    public function convert($value)
+    {
+        return $this->json->serialize($this->serialize->unserialize($value));
+    }
+}
diff --git a/lib/internal/Magento/Framework/DB/FieldDataConverter.php b/lib/internal/Magento/Framework/DB/FieldDataConverter.php
new file mode 100644
index 0000000000000000000000000000000000000000..39dcd3238c9b8a08cb6192f3ce2a4785528942a0
--- /dev/null
+++ b/lib/internal/Magento/Framework/DB/FieldDataConverter.php
@@ -0,0 +1,75 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Framework\DB;
+
+use Magento\Framework\DB\Adapter\AdapterInterface;
+use Magento\Framework\DB\Query\Generator;
+use Magento\Framework\DB\DataConverter\DataConverterInterface;
+use Magento\Framework\DB\Select\QueryModifierInterface;
+
+/**
+ * Convert field data from one representation to another
+ */
+class FieldDataConverter
+{
+    /**
+     * @var Generator
+     */
+    private $queryGenerator;
+
+    /**
+     * @var DataConverterInterface
+     */
+    private $dataConverter;
+
+    /**
+     * Constructor
+     *
+     * @param Generator $queryGenerator
+     * @param DataConverterInterface $dataConverter
+     */
+    public function __construct(
+        Generator $queryGenerator,
+        DataConverterInterface $dataConverter
+    ) {
+        $this->queryGenerator = $queryGenerator;
+        $this->dataConverter = $dataConverter;
+    }
+
+    /**
+     * Convert field data from one representation to another
+     *
+     * @param AdapterInterface $connection
+     * @param string $table
+     * @param string $identifier
+     * @param string $field
+     * @param QueryModifierInterface|null $queryModifier
+     * @return void
+     */
+    public function convert(
+        AdapterInterface $connection,
+        $table,
+        $identifier,
+        $field,
+        QueryModifierInterface $queryModifier = null
+    ) {
+        $select = $connection->select()
+            ->from($table, [$identifier, $field])
+            ->where($field . ' IS NOT NULL');
+        if ($queryModifier) {
+            $queryModifier->modify($select);
+        }
+        $iterator = $this->queryGenerator->generate($identifier, $select);
+        foreach ($iterator as $selectByRange) {
+            $rows = $connection->fetchAll($selectByRange);
+            foreach ($rows as $row) {
+                $bind = [$field => $this->dataConverter->convert($row[$field])];
+                $where = [$identifier . ' = ?' => (int) $row[$identifier]];
+                $connection->update($table, $bind, $where);
+            }
+        }
+    }
+}
diff --git a/lib/internal/Magento/Framework/DB/FieldDataConverterFactory.php b/lib/internal/Magento/Framework/DB/FieldDataConverterFactory.php
new file mode 100644
index 0000000000000000000000000000000000000000..c5caca06b283a6f769351dba3dc68a225bb66fcb
--- /dev/null
+++ b/lib/internal/Magento/Framework/DB/FieldDataConverterFactory.php
@@ -0,0 +1,46 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Framework\DB;
+
+use Magento\Framework\ObjectManagerInterface;
+
+/**
+ * Create instance of FieldDataConverter with concrete implementation of DataConverterInterface
+ */
+class FieldDataConverterFactory
+{
+    /**
+     * @var ObjectManagerInterface
+     */
+    private $objectManager;
+
+    /**
+     * Constructor
+     *
+     * @param ObjectManagerInterface $objectManager
+     */
+    public function __construct(
+        ObjectManagerInterface $objectManager
+    ) {
+        $this->objectManager = $objectManager;
+    }
+
+    /**
+     * Create instance of FieldDataConverter
+     *
+     * @param string $dataConverterClassName
+     * @return FieldDataConverter
+     */
+    public function create($dataConverterClassName)
+    {
+        return $this->objectManager->create(
+            FieldDataConverter::class,
+            [
+                'dataConverter' => $this->objectManager->get($dataConverterClassName)
+            ]
+        );
+    }
+}
diff --git a/lib/internal/Magento/Framework/DB/Select/InQueryModifier.php b/lib/internal/Magento/Framework/DB/Select/InQueryModifier.php
new file mode 100644
index 0000000000000000000000000000000000000000..e8a03f709568a67c2e34ca07b923c3ffbf16dafb
--- /dev/null
+++ b/lib/internal/Magento/Framework/DB/Select/InQueryModifier.php
@@ -0,0 +1,40 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Framework\DB\Select;
+
+use Magento\Framework\DB\Select;
+
+/**
+ * Add IN condition to select
+ */
+class InQueryModifier implements QueryModifierInterface
+{
+    /**
+     * @var array
+     */
+    private $values;
+
+    /**
+     * Constructor
+     *
+     * @param array $values
+     */
+    public function __construct(
+        $values = []
+    ) {
+        $this->values = $values;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function modify(Select $select)
+    {
+        foreach ($this->values as $field => $values) {
+            $select->where($field . ' IN (?)', $values);
+        }
+    }
+}
diff --git a/lib/internal/Magento/Framework/DB/Select/QueryModifierFactory.php b/lib/internal/Magento/Framework/DB/Select/QueryModifierFactory.php
new file mode 100644
index 0000000000000000000000000000000000000000..21eb484b43268b11373b1dcc9fbf726bdc0cf600
--- /dev/null
+++ b/lib/internal/Magento/Framework/DB/Select/QueryModifierFactory.php
@@ -0,0 +1,60 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Framework\DB\Select;
+
+use Magento\Framework\ObjectManagerInterface;
+
+/**
+ * Create instance of QueryModifierInterface
+ */
+class QueryModifierFactory
+{
+    /**
+     * @var ObjectManagerInterface
+     */
+    private $objectManager;
+
+    /**
+     * @var array
+     */
+    private $queryModifiers;
+
+    /**
+     * Constructor
+     *
+     * @param ObjectManagerInterface $objectManager
+     * @param array $queryModifiers
+     */
+    public function __construct(
+        ObjectManagerInterface $objectManager,
+        array $queryModifiers = []
+    ) {
+        $this->objectManager = $objectManager;
+        $this->queryModifiers = $queryModifiers;
+    }
+
+    /**
+     * Create instance of QueryModifierInterface
+     *
+     * @param string $type
+     * @param array $data
+     * @return QueryModifierInterface
+     * @throws \InvalidArgumentException
+     */
+    public function create($type, array $data = [])
+    {
+        if (!isset($this->queryModifiers[$type])) {
+            throw new \InvalidArgumentException('Unknown query modifier type ' . $type);
+        }
+        $queryModifier = $this->objectManager->create($this->queryModifiers[$type], $data);
+        if (!($queryModifier instanceof QueryModifierInterface)) {
+            throw new \InvalidArgumentException(
+                $this->queryModifiers[$type] . ' must implement ' . QueryModifierInterface::class
+            );
+        }
+        return $queryModifier;
+    }
+}
diff --git a/lib/internal/Magento/Framework/DB/Select/QueryModifierInterface.php b/lib/internal/Magento/Framework/DB/Select/QueryModifierInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..5cf676e088c440b626e352163ec350728c581fe1
--- /dev/null
+++ b/lib/internal/Magento/Framework/DB/Select/QueryModifierInterface.php
@@ -0,0 +1,22 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Framework\DB\Select;
+
+use Magento\Framework\DB\Select;
+
+/**
+ * Modify query, add custom conditions
+ */
+interface QueryModifierInterface
+{
+    /**
+     * Modify query
+     *
+     * @param Select $select
+     * @return void
+     */
+    public function modify(Select $select);
+}
diff --git a/lib/internal/Magento/Framework/DB/Test/Unit/DataConverter/SerializedToJsonTest.php b/lib/internal/Magento/Framework/DB/Test/Unit/DataConverter/SerializedToJsonTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..c84929f90c25c926c961906b2c1e5ab57afa77e9
--- /dev/null
+++ b/lib/internal/Magento/Framework/DB/Test/Unit/DataConverter/SerializedToJsonTest.php
@@ -0,0 +1,59 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Framework\DB\Test\Unit\DataConverter;
+
+use Magento\Framework\Serialize\Serializer\Serialize;
+use Magento\Framework\Serialize\Serializer\Json;
+use Magento\Framework\DB\DataConverter\SerializedToJson;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+
+class SerializedToJsonTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var Serialize|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $serializeMock;
+
+    /**
+     * @var Json|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $jsonMock;
+
+    /**
+     * @var SerializedToJson
+     */
+    private $serializedToJson;
+
+    protected function setUp()
+    {
+        $objectManager = new ObjectManager($this);
+        $this->serializeMock = $this->getMock(Serialize::class, [], [], '', false);
+        $this->jsonMock = $this->getMock(Json::class, [], [], '', false);
+        $this->serializedToJson = $objectManager->getObject(
+            SerializedToJson::class,
+            [
+                'serialize' => $this->serializeMock,
+                'json' => $this->jsonMock
+            ]
+        );
+    }
+
+    public function testConvert()
+    {
+        $serializedData = 'serialized data';
+        $jsonData = 'json data';
+        $unserializedData = 'unserialized data';
+        $this->serializeMock->expects($this->once())
+            ->method('unserialize')
+            ->with($serializedData)
+            ->willReturn($unserializedData);
+        $this->jsonMock->expects($this->once())
+            ->method('serialize')
+            ->with($unserializedData)
+            ->willReturn($jsonData);
+        $this->assertEquals($jsonData, $this->serializedToJson->convert($serializedData));
+    }
+}
diff --git a/lib/internal/Magento/Framework/DB/Test/Unit/FieldDataConverterFactoryTest.php b/lib/internal/Magento/Framework/DB/Test/Unit/FieldDataConverterFactoryTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..266f9e9ceceae2c89f0dc65fd27de66dfb27d166
--- /dev/null
+++ b/lib/internal/Magento/Framework/DB/Test/Unit/FieldDataConverterFactoryTest.php
@@ -0,0 +1,66 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Framework\DB\Test\Unit;
+
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+use Magento\Framework\DB\FieldDataConverterFactory;
+use Magento\Framework\ObjectManagerInterface;
+use Magento\Framework\DB\FieldDataConverter;
+use Magento\Framework\DB\DataConverter\DataConverterInterface;
+
+class FieldDataConverterFactoryTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var ObjectManagerInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $objectManagerMock;
+
+    /**
+     * @var DataConverterInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $dataConverterMock;
+
+    /**
+     * @var FieldDataConverterFactory
+     */
+    private $fieldDataConverterFactory;
+
+    protected function setUp()
+    {
+        $objectManager = new ObjectManager($this);
+        $this->objectManagerMock = $this->getMock(ObjectManagerInterface::class);
+        $this->dataConverterMock = $this->getMock(DataConverterInterface::class);
+        $this->fieldDataConverterFactory = $objectManager->getObject(
+            FieldDataConverterFactory::class,
+            [
+                'objectManager' => $this->objectManagerMock
+            ]
+        );
+    }
+
+    public function testCreate()
+    {
+        $dataConverterClassName = 'ClassName';
+        $fieldDataConverterInstance = 'field data converter instance';
+        $this->objectManagerMock->expects($this->once())
+            ->method('get')
+            ->with($dataConverterClassName)
+            ->willReturn($this->dataConverterMock);
+        $this->objectManagerMock->expects($this->once())
+            ->method('create')
+            ->with(
+                FieldDataConverter::class,
+                [
+                    'dataConverter' => $this->dataConverterMock
+                ]
+            )
+            ->willReturn($fieldDataConverterInstance);
+        $this->assertEquals(
+            $fieldDataConverterInstance,
+            $this->fieldDataConverterFactory->create($dataConverterClassName)
+        );
+    }
+}
diff --git a/lib/internal/Magento/Framework/DB/Test/Unit/FieldDataConverterTest.php b/lib/internal/Magento/Framework/DB/Test/Unit/FieldDataConverterTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..f0005de98dcda2b66aaab355fc0a07cd9d0531d7
--- /dev/null
+++ b/lib/internal/Magento/Framework/DB/Test/Unit/FieldDataConverterTest.php
@@ -0,0 +1,139 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Framework\DB\Test\Unit;
+
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+use Magento\Framework\DB\Query\Generator;
+use Magento\Framework\DB\Adapter\AdapterInterface;
+use Magento\Framework\DB\FieldDataConverter;
+use Magento\Framework\DB\DataConverter\DataConverterInterface;
+use Magento\Framework\DB\Select;
+use Magento\Framework\DB\Select\QueryModifierInterface;
+
+class FieldDataConverterTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var AdapterInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $connectionMock;
+
+    /**
+     * @var Generator|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $queryGeneratorMock;
+
+    /**
+     * @var DataConverterInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $dataConverterMock;
+
+    /**
+     * @var Select|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $selectMock;
+
+    /**
+     * @var QueryModifierInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $queryModifierMock;
+
+    /**
+     * @var FieldDataConverter
+     */
+    private $fieldDataConverter;
+
+    protected function setUp()
+    {
+        $objectManager = new ObjectManager($this);
+        $this->connectionMock = $this->getMock(AdapterInterface::class);
+        $this->queryGeneratorMock = $this->getMock(Generator::class, [], [], '', false);
+        $this->dataConverterMock = $this->getMock(DataConverterInterface::class);
+        $this->selectMock = $this->getMock(Select::class, [], [], '', false);
+        $this->queryModifierMock = $this->getMock(QueryModifierInterface::class);
+        $this->fieldDataConverter = $objectManager->getObject(
+            FieldDataConverter::class,
+            [
+                'queryGenerator' => $this->queryGeneratorMock,
+                'dataConverter' => $this->dataConverterMock
+            ]
+        );
+    }
+
+    /**
+     * @param boolean $useQueryModifier
+     * @param int $numQueryModifierCalls
+     * @dataProvider convertDataProvider
+     */
+    public function testConvert($useQueryModifier, $numQueryModifierCalls)
+    {
+        $table = 'table';
+        $identifier = 'id';
+        $field = 'field';
+        $where = $field . ' IS NOT NULL';
+        $iterator = ['query 1'];
+        $rows = [
+            [
+                $identifier => 1,
+                $field => 'value'
+            ]
+        ];
+        $convertedValue = 'converted value';
+        $this->connectionMock->expects($this->once())
+            ->method('select')
+            ->willReturn($this->selectMock);
+        $this->selectMock->expects($this->once())
+            ->method('from')
+            ->with(
+                $table,
+                [$identifier, $field]
+            )
+            ->willReturnSelf();
+        $this->selectMock->expects($this->once())
+            ->method('where')
+            ->with($where)
+            ->willReturnSelf();
+        $this->queryModifierMock->expects($this->exactly($numQueryModifierCalls))
+            ->method('modify')
+            ->with($this->selectMock);
+        $this->queryGeneratorMock->expects($this->once())
+            ->method('generate')
+            ->with($identifier, $this->selectMock)
+            ->willReturn($iterator);
+        $this->connectionMock->expects($this->once())
+            ->method('fetchAll')
+            ->with($iterator[0])
+            ->willReturn($rows);
+        $this->dataConverterMock->expects($this->once())
+            ->method('convert')
+            ->with($rows[0][$field])
+            ->willReturn($convertedValue);
+        $this->connectionMock->expects($this->once())
+            ->method('update')
+            ->with(
+                $table,
+                [$field => $convertedValue],
+                [$identifier . ' = ?' => $rows[0][$identifier]]
+            );
+        $this->fieldDataConverter->convert(
+            $this->connectionMock,
+            $table,
+            $identifier,
+            $field,
+            $useQueryModifier ? $this->queryModifierMock : null
+        );
+    }
+
+    /**
+     * @return array
+     */
+    public function convertDataProvider()
+    {
+        return [
+            [false, 0],
+            [true, 1]
+        ];
+    }
+}
diff --git a/lib/internal/Magento/Framework/DB/Test/Unit/Select/QueryModifierFactoryTest.php b/lib/internal/Magento/Framework/DB/Test/Unit/Select/QueryModifierFactoryTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..b083b730bbdbaea4d36bb094eb47ca2361ae265b
--- /dev/null
+++ b/lib/internal/Magento/Framework/DB/Test/Unit/Select/QueryModifierFactoryTest.php
@@ -0,0 +1,106 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Framework\DB\Test\Unit\Select;
+
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+use Magento\Framework\DB\Select\QueryModifierFactory;
+use Magento\Framework\DB\Select\InQueryModifier;
+use Magento\Framework\ObjectManagerInterface;
+
+class QueryModifierFactoryTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var ObjectManager
+     */
+    private $objectManager;
+
+    /**
+     * @var QueryModifierFactory
+     */
+    private $queryModifierFactory;
+
+    /**
+     * @var ObjectManagerInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $objectManagerMock;
+
+    /**
+     * @var InQueryModifier|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $inQueryModifierMock;
+
+    protected function setUp()
+    {
+        $this->objectManager = new ObjectManager($this);
+        $this->objectManagerMock = $this->getMock(ObjectManagerInterface::class);
+        $this->inQueryModifierMock = $this->getMock(InQueryModifier::class, [], [], '', false);
+    }
+
+    public function testCreate()
+    {
+        $params = ['foo' => 'bar'];
+        $this->queryModifierFactory = $this->objectManager->getObject(
+            QueryModifierFactory::class,
+            [
+                'objectManager' => $this->objectManagerMock,
+                'queryModifiers' => [
+                    'in' => InQueryModifier::class
+                ]
+            ]
+        );
+        $this->objectManagerMock->expects($this->once())
+            ->method('create')
+            ->with(
+                InQueryModifier::class,
+                $params
+            )
+            ->willReturn($this->inQueryModifierMock);
+        $this->queryModifierFactory->create('in', $params);
+    }
+
+    /**
+     * @expectedException \InvalidArgumentException
+     */
+    public function testCreateUnknownQueryModifierType()
+    {
+        $params = ['foo' => 'bar'];
+        $this->queryModifierFactory = $this->objectManager->getObject(
+            QueryModifierFactory::class,
+            [
+                'objectManager' => $this->objectManagerMock,
+                'queryModifiers' => []
+            ]
+        );
+        $this->objectManagerMock->expects($this->never())
+            ->method('create');
+        $this->queryModifierFactory->create('in', $params);
+    }
+
+    /**
+     * @expectedException \InvalidArgumentException
+     */
+    public function testCreateDoesNotImplementInterface()
+    {
+        $params = ['foo' => 'bar'];
+        $this->queryModifierFactory = $this->objectManager->getObject(
+            QueryModifierFactory::class,
+            [
+                'objectManager' => $this->objectManagerMock,
+                'queryModifiers' => [
+                    'in' => \stdClass::class
+                ]
+            ]
+        );
+        $this->objectManagerMock->expects($this->once())
+            ->method('create')
+            ->with(
+                \stdClass::class,
+                $params
+            )
+            ->willReturn(new \stdClass());
+        $this->queryModifierFactory->create('in', $params);
+    }
+}
diff --git a/lib/internal/Magento/Framework/Model/ResourceModel/AbstractResource.php b/lib/internal/Magento/Framework/Model/ResourceModel/AbstractResource.php
index 3d90fc781bf3a976d6ffb6dafb4306190ecbebfd..c87a07eaab37ed5b4c58a1c7d8162c901abc7742 100644
--- a/lib/internal/Magento/Framework/Model/ResourceModel/AbstractResource.php
+++ b/lib/internal/Magento/Framework/Model/ResourceModel/AbstractResource.php
@@ -7,6 +7,8 @@ namespace Magento\Framework\Model\ResourceModel;
 
 use Magento\Framework\DataObject;
 use Magento\Framework\Model\CallbackPool;
+use Magento\Framework\Serialize\Serializer\Json;
+use Magento\Framework\App\ObjectManager;
 
 /**
  * Abstract resource model
@@ -14,7 +16,12 @@ use Magento\Framework\Model\CallbackPool;
 abstract class AbstractResource
 {
     /**
-     * Main constructor
+     * @var Json
+     */
+    protected $serializer;
+
+    /**
+     * Constructor
      */
     public function __construct()
     {
@@ -116,7 +123,7 @@ abstract class AbstractResource
         if (empty($value) && $unsetEmpty) {
             $object->unsetData($field);
         } else {
-            $object->setData($field, serialize($value ?: $defaultValue));
+            $object->setData($field, $this->getSerializer()->serialize($value ?: $defaultValue));
         }
 
         return $this;
@@ -132,13 +139,7 @@ abstract class AbstractResource
      */
     protected function _unserializeField(DataObject $object, $field, $defaultValue = null)
     {
-        $value = $object->getData($field);
-
-        if ($value) {
-            $unserializedValue = @unserialize($value);
-            $value = $unserializedValue !== false || $value === 'b:0;' ? $unserializedValue : $value;
-        }
-
+        $value = $this->getSerializer()->unserialize($object->getData($field));
         if (empty($value)) {
             $object->setData($field, $defaultValue);
         } else {
@@ -228,4 +229,18 @@ abstract class AbstractResource
         }
         return $columns;
     }
+
+    /**
+     * Get serializer
+     *
+     * @return Json
+     * @deprecated
+     */
+    protected function getSerializer()
+    {
+        if (null === $this->serializer) {
+            $this->serializer = ObjectManager::getInstance()->get(Json::class);
+        }
+        return $this->serializer;
+    }
 }
diff --git a/lib/internal/Magento/Framework/Model/ResourceModel/Db/AbstractDb.php b/lib/internal/Magento/Framework/Model/ResourceModel/Db/AbstractDb.php
index 4cd88e356e9cad79a6f0209bb2bab685ffe5f73c..12e2da6d4ebd4b7a5c6edf123ac15865e28b4f7c 100644
--- a/lib/internal/Magento/Framework/Model/ResourceModel/Db/AbstractDb.php
+++ b/lib/internal/Magento/Framework/Model/ResourceModel/Db/AbstractDb.php
@@ -3,7 +3,6 @@
  * Copyright © 2016 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-
 namespace Magento\Framework\Model\ResourceModel\Db;
 
 use Magento\Framework\App\ResourceConnection;
@@ -14,7 +13,8 @@ use Magento\Framework\DB\Adapter\DuplicateException;
 use Magento\Framework\Phrase;
 
 /**
- * Abstract resource model class
+ * Abstract resource model
+ *
  * @SuppressWarnings(PHPMD.NumberOfChildren)
  * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
@@ -133,13 +133,15 @@ abstract class AbstractDb extends AbstractResource
     protected $objectRelationProcessor;
 
     /**
-     * Class constructor
+     * Constructor
      *
      * @param \Magento\Framework\Model\ResourceModel\Db\Context $context
      * @param string $connectionName
      */
-    public function __construct(\Magento\Framework\Model\ResourceModel\Db\Context $context, $connectionName = null)
-    {
+    public function __construct(
+        \Magento\Framework\Model\ResourceModel\Db\Context $context,
+        $connectionName = null
+    ) {
         $this->transactionManager = $context->getTransactionManager();
         $this->_resources = $context->getResources();
         $this->objectRelationProcessor = $context->getObjectRelationProcessor();
diff --git a/lib/internal/Magento/Framework/Model/Test/Unit/ResourceModel/AbstractResourceTest.php b/lib/internal/Magento/Framework/Model/Test/Unit/ResourceModel/AbstractResourceTest.php
index 217f5c8252378206881dacd8085bd4025e072821..85696221beeaf46ffe33b763ba505d26d44ad675 100644
--- a/lib/internal/Magento/Framework/Model/Test/Unit/ResourceModel/AbstractResourceTest.php
+++ b/lib/internal/Magento/Framework/Model/Test/Unit/ResourceModel/AbstractResourceTest.php
@@ -7,103 +7,161 @@ namespace Magento\Framework\Model\Test\Unit\ResourceModel;
 
 use Magento\Framework\DataObject;
 use Magento\Framework\DB\Adapter\AdapterInterface;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+use Magento\Framework\Serialize\Serializer\Json;
 
 class AbstractResourceTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @param array $arguments
-     * @param string $expectation
-     * @dataProvider serializableFieldsDataProvider
+     * @var AbstractResourceStub
      */
-    public function testSerializeFields(array $arguments, $expectation)
-    {
-        /** @var DataObject $dataObject */
-        list($dataObject, $field, $defaultValue, $unsetEmpty) = $arguments;
+    private $abstractResource;
 
-        $abstractResource = new AbstractResourceStub();
+    /**
+     * @var Json|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $serializerMock;
 
-        $abstractResource->_serializeField($dataObject, $field, $defaultValue, $unsetEmpty);
+    protected function setUp()
+    {
+        $objectManager = new ObjectManager($this);
+        $this->serializerMock = $this->getMock(Json::class);
+        $this->abstractResource = $objectManager->getObject(AbstractResourceStub::class);
+        $objectManager->setBackwardCompatibleProperty(
+            $this->abstractResource,
+            'serializer',
+            $this->serializerMock
+        );
+    }
 
-        static::assertEquals($expectation, $dataObject->getDataByKey($field));
+    /**
+     * @param array $arguments
+     * @param string $expected
+     * @param array|string|int $serializeCalledWith
+     * @param int $numSerializeCalled
+     * @dataProvider serializeFieldsDataProvider
+     */
+    public function testSerializeFields(
+        array $arguments,
+        $expected,
+        $serializeCalledWith,
+        $numSerializeCalled = 1
+    ) {
+        /** @var DataObject $dataObject */
+        list($dataObject, $field, $defaultValue, $unsetEmpty) = $arguments;
+        $this->serializerMock->expects($this->exactly($numSerializeCalled))
+            ->method('serialize')
+            ->with($serializeCalledWith)
+            ->willReturn($expected);
+        $this->abstractResource->_serializeField($dataObject, $field, $defaultValue, $unsetEmpty);
+        $this->assertEquals($expected, $dataObject->getData($field));
     }
 
     /**
      * @return array
      */
-    public function serializableFieldsDataProvider()
+    public function serializeFieldsDataProvider()
     {
+        $array = ['a', 'b', 'c'];
+        $string = 'i am string';
+        $integer = 969;
+        $empty = '';
         $dataObject = new DataObject(
             [
-                'object' => new \stdClass(),
-                'array' => ['a', 'b', 'c'],
-                'string' => 'i am string',
-                'int' => 969,
-                'serialized_object' => 'O:8:"stdClass":0:{}',
-                'empty_value' => '',
-                'empty_value_with_default' => ''
+                'array' => $array,
+                'string' => $string,
+                'integer' => $integer,
+                'empty' => $empty,
+                'empty_with_default' => ''
             ]
         );
-
         return [
-            [[$dataObject, 'object', null, false], serialize($dataObject->getDataByKey('object'))],
-            [[$dataObject, 'array', null, false], serialize($dataObject->getDataByKey('array'))],
-            [[$dataObject, 'string', null, false], serialize($dataObject->getDataByKey('string'))],
-            [[$dataObject, 'int', null, false], serialize($dataObject->getDataByKey('int'))],
             [
-                [$dataObject, 'serialized_object', null, false],
-                serialize($dataObject->getDataByKey('serialized_object'))
+                [$dataObject, 'array', null, false],
+                '["a","b","c"]',
+                $array
+            ],
+            [
+                [$dataObject, 'string', null, false],
+                '"i am string"',
+                $string
+            ],
+            [
+                [$dataObject, 'integer', null, false],
+                '969',
+                $integer
+            ],
+            [
+                [$dataObject, 'empty', null, true],
+                null,
+                $empty,
+                0
             ],
-            [[$dataObject, 'empty_value', null, true], null],
-            [[$dataObject, 'empty_value_with_default', new \stdClass(), false], 'O:8:"stdClass":0:{}'],
+            [
+                [$dataObject, 'empty_with_default', 'default', false],
+                '"default"',
+                'default'
+            ]
         ];
     }
 
     /**
      * @param array $arguments
-     * @param mixed $expectation
-     * @dataProvider unserializableFieldsDataProvider
+     * @param array|string|int|boolean $expected
+     * @dataProvider unserializeFieldsDataProvider
      */
-    public function testUnserializeFields(array $arguments, $expectation)
+    public function testUnserializeFields(array $arguments, $expected)
     {
         /** @var DataObject $dataObject */
         list($dataObject, $field, $defaultValue) = $arguments;
-
-        $abstractResource = new AbstractResourceStub();
-
-        $abstractResource->_unserializeField($dataObject, $field, $defaultValue);
-
-        static::assertEquals($expectation, $dataObject->getDataByKey($field));
+        $this->serializerMock->expects($this->once())
+            ->method('unserialize')
+            ->with($dataObject->getData($field))
+            ->willReturn($expected);
+        $this->abstractResource->_unserializeField($dataObject, $field, $defaultValue);
+        $this->assertEquals($expected, $dataObject->getData($field));
     }
 
     /**
      * @return array
      */
-    public function unserializableFieldsDataProvider()
+    public function unserializeFieldsDataProvider()
     {
         $dataObject = new DataObject(
             [
-                'object' => serialize(new \stdClass()),
-                'array' => serialize(['a', 'b', 'c']),
-                'string' => serialize('i am string'),
-                'int' => serialize(969),
-                'serialized_object' => serialize('O:8:"stdClass":0:{}'),
-                'empty_value_with_default' => serialize(''),
+                'array' => '["a","b","c"]',
+                'string' => '"i am string"',
+                'integer' => '969',
+                'empty_with_default' => '""',
                 'not_serialized_string' => 'i am string',
-                'serialized_boolean_false' => serialize(false)
+                'serialized_boolean_false' => 'false'
             ]
         );
-
-        $defaultValue = new \stdClass();
-
         return [
-            [[$dataObject, 'object', null], unserialize($dataObject->getDataByKey('object'))],
-            [[$dataObject, 'array', null], unserialize($dataObject->getDataByKey('array'))],
-            [[$dataObject, 'string', null], unserialize($dataObject->getDataByKey('string'))],
-            [[$dataObject, 'int', null], unserialize($dataObject->getDataByKey('int'))],
-            [[$dataObject, 'serialized_object', null], unserialize($dataObject->getDataByKey('serialized_object'))],
-            [[$dataObject, 'empty_value_with_default', $defaultValue], $defaultValue],
-            [[$dataObject, 'not_serialized_string', null], 'i am string'],
-            [[$dataObject, 'serialized_boolean_false', null], false]
+            [
+                [$dataObject, 'array', null],
+                ['a', 'b', 'c']
+            ],
+            [
+                [$dataObject, 'string', null],
+                'i am string'
+            ],
+            [
+                [$dataObject, 'integer', null],
+                969
+            ],
+            [
+                [$dataObject, 'empty_with_default', 'default', false],
+                'default'
+            ],
+            [
+                [$dataObject, 'not_serialized_string', null],
+                'i am string'
+            ],
+            [
+                [$dataObject, 'serialized_boolean_false', null],
+                false,
+            ]
         ];
     }
     
@@ -116,32 +174,31 @@ class AbstractResourceTest extends \PHPUnit_Framework_TestCase
             ->disableOriginalConstructor()
             ->getMock();
 
-        $abstractResource = new AbstractResourceStub();
-        $abstractResource->setConnection($connection);
-        $abstractResource->addCommitCallback(
+        $this->abstractResource->setConnection($connection);
+        $this->abstractResource->addCommitCallback(
             function () use ($closureExpectation) {
                 $closureExpectation->setData(1);
             }
         );
 
-        $abstractResource->addCommitCallback(
+        $this->abstractResource->addCommitCallback(
             function () use ($closureExpectation) {
                 $closureExpectation->getData();
             }
         );
 
-        $connection->expects(static::once())
+        $connection->expects($this->once())
             ->method('commit');
-        $connection->expects(static::once())
+        $connection->expects($this->once())
             ->method('getTransactionLevel')
             ->willReturn(0);
-        $closureExpectation->expects(static::once())
+        $closureExpectation->expects($this->once())
             ->method('setData')
             ->with(1);
-        $closureExpectation->expects(static::once())
+        $closureExpectation->expects($this->once())
             ->method('getData');
 
-        $abstractResource->commit();
+        $this->abstractResource->commit();
     }
 
     /**
@@ -152,23 +209,22 @@ class AbstractResourceTest extends \PHPUnit_Framework_TestCase
         /** @var AdapterInterface|\PHPUnit_Framework_MockObject_MockObject $connection */
         $connection = $this->getMock(AdapterInterface::class);
 
-        $abstractResource = new AbstractResourceStub();
-        $abstractResource->setConnection($connection);
-        $abstractResource->addCommitCallback(
+        $this->abstractResource->setConnection($connection);
+        $this->abstractResource->addCommitCallback(
             function () {
                 throw new \Exception();
             }
         );
 
-        $connection->expects(static::once())
+        $connection->expects($this->once())
             ->method('commit');
-        $connection->expects(static::once())
+        $connection->expects($this->once())
             ->method('getTransactionLevel')
             ->willReturn(0);
 
-        $abstractResource->commit();
+        $this->abstractResource->commit();
     }
-    
+
     public function testCommitNotCompletedTransaction()
     {
         /** @var AdapterInterface|\PHPUnit_Framework_MockObject_MockObject $connection */
@@ -178,24 +234,23 @@ class AbstractResourceTest extends \PHPUnit_Framework_TestCase
             ->disableOriginalConstructor()
             ->getMock();
 
-        $abstractResource = new AbstractResourceStub();
-        $abstractResource->setConnection($connection);
-        $abstractResource->addCommitCallback(
+        $this->abstractResource->setConnection($connection);
+        $this->abstractResource->addCommitCallback(
             function () use ($closureExpectation) {
                 $closureExpectation->setData(1);
             }
         );
 
-        $connection->expects(static::once())
+        $connection->expects($this->once())
             ->method('commit');
-        $connection->expects(static::once())
+        $connection->expects($this->once())
             ->method('getTransactionLevel')
             ->willReturn(1);
 
-        $closureExpectation->expects(static::never())
+        $closureExpectation->expects($this->never())
             ->method('setData')
             ->with(1);
 
-        $abstractResource->commit();
+        $this->abstractResource->commit();
     }
 }