diff --git a/app/code/Magento/Backend/Model/Menu.php b/app/code/Magento/Backend/Model/Menu.php
index 516319ad983f9a35804e9933d27bbb42575e7b30..ccae5ebce16a01926aa0166344976185ad6769bf 100644
--- a/app/code/Magento/Backend/Model/Menu.php
+++ b/app/code/Magento/Backend/Model/Menu.php
@@ -5,6 +5,12 @@
  */
 namespace Magento\Backend\Model;
 
+use Magento\Backend\Model\Menu\Item;
+use Magento\Backend\Model\Menu\Item\Factory;
+use Magento\Framework\App\ObjectManager;
+use Magento\Framework\Serialize\SerializerInterface;
+use Psr\Log\LoggerInterface;
+
 /**
  * Backend menu model
  */
@@ -18,33 +24,54 @@ class Menu extends \ArrayObject
     protected $_path = '';
 
     /**
-     * @var \Psr\Log\LoggerInterface
+     * @var LoggerInterface
      */
     protected $_logger;
 
     /**
-     * @param \Psr\Log\LoggerInterface $logger
+     * @var Factory
+     */
+    private $menuItemFactory;
+
+    /**
+     * @var SerializerInterface
+     */
+    private $serializer;
+
+    /**
+     * Menu constructor
+     *
+     * @param LoggerInterface $logger
      * @param string $pathInMenuStructure
+     * @param Factory|null $menuItemFactory
+     * @param SerializerInterface|null $serializer
      */
-    public function __construct(\Psr\Log\LoggerInterface $logger, $pathInMenuStructure = '')
-    {
+    public function __construct(
+        LoggerInterface $logger,
+        $pathInMenuStructure = '',
+        Factory $menuItemFactory = null,
+        SerializerInterface $serializer = null
+    ) {
         if ($pathInMenuStructure) {
             $this->_path = $pathInMenuStructure . '/';
         }
         $this->_logger = $logger;
         $this->setIteratorClass(\Magento\Backend\Model\Menu\Iterator::class);
+        $this->menuItemFactory = $menuItemFactory ?: ObjectManager::getInstance()
+            ->create(Factory::class);
+        $this->serializer = $serializer ?: ObjectManager::getInstance()->create(SerializerInterface::class);
     }
 
     /**
      * Add child to menu item
      *
-     * @param \Magento\Backend\Model\Menu\Item $item
+     * @param Item $item
      * @param string $parentId
      * @param int $index
      * @return void
      * @throws \InvalidArgumentException
      */
-    public function add(\Magento\Backend\Model\Menu\Item $item, $parentId = null, $index = null)
+    public function add(Item $item, $parentId = null, $index = null)
     {
         if ($parentId !== null) {
             $parentItem = $this->get($parentId);
@@ -69,13 +96,13 @@ class Menu extends \ArrayObject
      * Retrieve menu item by id
      *
      * @param string $itemId
-     * @return \Magento\Backend\Model\Menu\Item|null
+     * @return Item|null
      */
     public function get($itemId)
     {
         $result = null;
+        /** @var Item $item */
         foreach ($this as $item) {
-            /** @var $item \Magento\Backend\Model\Menu\Item */
             if ($item->getId() == $itemId) {
                 $result = $item;
                 break;
@@ -116,8 +143,8 @@ class Menu extends \ArrayObject
     public function remove($itemId)
     {
         $result = false;
+        /** @var Item $item */
         foreach ($this as $key => $item) {
-            /** @var $item \Magento\Backend\Model\Menu\Item */
             if ($item->getId() == $itemId) {
                 unset($this[$key]);
                 $result = true;
@@ -144,8 +171,8 @@ class Menu extends \ArrayObject
     public function reorder($itemId, $position)
     {
         $result = false;
+        /** @var Item $item */
         foreach ($this as $key => $item) {
-            /** @var $item \Magento\Backend\Model\Menu\Item */
             if ($item->getId() == $itemId) {
                 unset($this[$key]);
                 $this->add($item, null, $position);
@@ -161,10 +188,10 @@ class Menu extends \ArrayObject
     /**
      * Check whether provided item is last in list
      *
-     * @param \Magento\Backend\Model\Menu\Item $item
+     * @param Item $item
      * @return bool
      */
-    public function isLast(\Magento\Backend\Model\Menu\Item $item)
+    public function isLast(Item $item)
     {
         return $this->offsetGet(max(array_keys($this->getArrayCopy())))->getId() == $item->getId();
     }
@@ -172,12 +199,12 @@ class Menu extends \ArrayObject
     /**
      * Find first menu item that user is able to access
      *
-     * @return \Magento\Backend\Model\Menu\Item|null
+     * @return Item|null
      */
     public function getFirstAvailable()
     {
         $result = null;
-        /** @var $item \Magento\Backend\Model\Menu\Item */
+        /** @var Item $item */
         foreach ($this as $item) {
             if ($item->isAllowed() && !$item->isDisabled()) {
                 if ($item->hasChildren()) {
@@ -198,7 +225,7 @@ class Menu extends \ArrayObject
      * Get parent items by item id
      *
      * @param string $itemId
-     * @return \Magento\Backend\Model\Menu\Item[]
+     * @return Item[]
      */
     public function getParentItems($itemId)
     {
@@ -217,8 +244,8 @@ class Menu extends \ArrayObject
      */
     protected function _findParentItems($menu, $itemId, &$parents)
     {
+        /** @var Item $item */
         foreach ($menu as $item) {
-            /** @var $item \Magento\Backend\Model\Menu\Item */
             if ($item->getId() == $itemId) {
                 return true;
             }
@@ -233,16 +260,54 @@ class Menu extends \ArrayObject
     }
 
     /**
-     * Hack to unset logger instance which cannot be serialized
+     * Serialize menu
      *
      * @return string
      */
     public function serialize()
     {
-        $logger = $this->_logger;
-        unset($this->_logger);
-        $result = parent::serialize();
-        $this->_logger = $logger;
-        return $result;
+        return $this->serializer->serialize($this->toArray());
+    }
+
+    /**
+     * Get menu data represented as an array
+     *
+     * @return array
+     */
+    public function toArray()
+    {
+        $data = [];
+        foreach ($this as $item) {
+            $data[] = $item->toArray();
+        }
+        return $data;
+    }
+
+    /**
+     * Unserialize menu
+     *
+     * @param string $serialized
+     * @return void
+     */
+    public function unserialize($serialized)
+    {
+        $data = $this->serializer->unserialize($serialized);
+        $this->populateFromArray($data);
+    }
+
+    /**
+     * Populate the menu with data from array
+     *
+     * @param array $data
+     * @return void
+     */
+    public function populateFromArray(array $data)
+    {
+        $items = [];
+        foreach ($data as $itemData) {
+            $item = $this->menuItemFactory->create($itemData);
+            $items[] = $item;
+        }
+        $this->exchangeArray($items);
     }
 }
diff --git a/app/code/Magento/Backend/Model/Menu/Item.php b/app/code/Magento/Backend/Model/Menu/Item.php
index a49920a67663c7115fde12d799846c1b1da353b1..ef1aa864588f412126bf74e32ca462a41a3182d5 100644
--- a/app/code/Magento/Backend/Model/Menu/Item.php
+++ b/app/code/Magento/Backend/Model/Menu/Item.php
@@ -4,10 +4,11 @@
  * See COPYING.txt for license details.
  */
 
-// @codingStandardsIgnoreFile
-
 namespace Magento\Backend\Model\Menu;
 
+use Magento\Backend\Model\Menu;
+use Magento\Store\Model\ScopeInterface;
+
 /**
  * Menu item. Should be used to create nested menu structures with \Magento\Backend\Model\Menu
  *
@@ -102,7 +103,7 @@ class Item
     /**
      * Submenu item list
      *
-     * @var \Magento\Backend\Model\Menu
+     * @var Menu
      */
     protected $_submenu;
 
@@ -130,6 +131,7 @@ class Item
      * Serialized submenu string
      *
      * @var string
+     * @deprecated
      */
     protected $_serializedSubmenu;
 
@@ -167,22 +169,13 @@ class Item
     ) {
         $this->_validator = $validator;
         $this->_validator->validate($data);
-
         $this->_moduleManager = $moduleManager;
         $this->_acl = $authorization;
         $this->_scopeConfig = $scopeConfig;
         $this->_menuFactory = $menuFactory;
         $this->_urlModel = $urlModel;
-        $this->_moduleName = isset($data['module']) ? $data['module'] : 'Magento_Backend';
         $this->_moduleList = $moduleList;
-
-        $this->_id = $data['id'];
-        $this->_title = $data['title'];
-        $this->_action = $this->_getArgument($data, 'action');
-        $this->_resource = $this->_getArgument($data, 'resource');
-        $this->_dependsOnModule = $this->_getArgument($data, 'dependsOnModule');
-        $this->_dependsOnConfig = $this->_getArgument($data, 'dependsOnConfig');
-        $this->_tooltip = $this->_getArgument($data, 'toolTip', '');
+        $this->populateFromArray($data);
     }
 
     /**
@@ -215,13 +208,13 @@ class Item
      */
     public function hasChildren()
     {
-        return !is_null($this->_submenu) && (bool)$this->_submenu->count();
+        return (null !== $this->_submenu) && (bool)$this->_submenu->count();
     }
 
     /**
      * Retrieve submenu
      *
-     * @return \Magento\Backend\Model\Menu
+     * @return Menu
      */
     public function getChildren()
     {
@@ -425,7 +418,7 @@ class Item
     protected function _isConfigDependenciesAvailable()
     {
         if ($this->_dependsOnConfig) {
-            return $this->_scopeConfig->isSetFlag((string)$this->_dependsOnConfig, \Magento\Store\Model\ScopeInterface::SCOPE_STORE);
+            return $this->_scopeConfig->isSetFlag((string)$this->_dependsOnConfig, ScopeInterface::SCOPE_STORE);
         }
         return true;
     }
@@ -445,45 +438,53 @@ class Item
     }
 
     /**
-     * @return string[]
+     * Get menu item data represented as an array
+     *
+     * @return array
      */
-    public function __sleep()
+    public function toArray()
     {
-        if ($this->_submenu) {
-            $this->_serializedSubmenu = $this->_submenu->serialize();
-        }
         return [
-            '_parentId',
-            '_moduleName',
-            '_sortIndex',
-            '_dependsOnConfig',
-            '_id',
-            '_resource',
-            '_path',
-            '_action',
-            '_dependsOnModule',
-            '_tooltip',
-            '_title',
-            '_serializedSubmenu'
+            'parent_id' => $this->_parentId,
+            'module_name' => $this->_moduleName,
+            'sort_index' => $this->_sortIndex,
+            'depends_on_config' => $this->_dependsOnConfig,
+            'id' => $this->_id,
+            'resource' => $this->_resource,
+            'path' => $this->_path,
+            'action' => $this->_action,
+            'depends_on_module' => $this->_dependsOnModule,
+            'tooltip' => $this->_tooltip,
+            'title' => $this->_title,
+            'sub_menu' => isset($this->_submenu) ? $this->_submenu->toArray() : null
         ];
     }
 
     /**
+     * Populate the menu item with data from array
+     *
+     * @param array $data
      * @return void
      */
-    public function __wakeup()
+    public function populateFromArray(array $data)
     {
-        $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
-        $this->_moduleManager = $objectManager->get(\Magento\Framework\Module\Manager::class);
-        $this->_validator = $objectManager->get(\Magento\Backend\Model\Menu\Item\Validator::class);
-        $this->_acl = $objectManager->get(\Magento\Framework\AuthorizationInterface::class);
-        $this->_scopeConfig = $objectManager->get(\Magento\Framework\App\Config\ScopeConfigInterface::class);
-        $this->_menuFactory = $objectManager->get(\Magento\Backend\Model\MenuFactory::class);
-        $this->_urlModel = $objectManager->get(\Magento\Backend\Model\UrlInterface::class);
-        $this->_moduleList = $objectManager->get(\Magento\Framework\Module\ModuleListInterface::class);
-        if ($this->_serializedSubmenu) {
-            $this->_submenu = $this->_menuFactory->create();
-            $this->_submenu->unserialize($this->_serializedSubmenu);
+        $this->_parentId = $this->_getArgument($data, 'parent_id');
+        $this->_moduleName = $this->_getArgument($data, 'module_name', 'Magento_Backend');
+        $this->_sortIndex = $this->_getArgument($data, 'sort_index');
+        $this->_dependsOnConfig = $this->_getArgument($data, 'depends_on_config');
+        $this->_id = $this->_getArgument($data, 'id');
+        $this->_resource = $this->_getArgument($data, 'resource');
+        $this->_path = $this->_getArgument($data, 'path', '');
+        $this->_action = $this->_getArgument($data, 'action');
+        $this->_dependsOnModule = $this->_getArgument($data, 'depends_on_module');
+        $this->_tooltip = $this->_getArgument($data, 'tooltip', '');
+        $this->_title = $this->_getArgument($data, 'title');
+        if (isset($data['sub_menu'])) {
+            $menu = $this->_menuFactory->create();
+            $menu->populateFromArray($data['sub_menu']);
+            $this->_submenu = $menu;
+        } else {
+            $this->_submenu = null;
         }
     }
 }
diff --git a/app/code/Magento/Backend/Test/Unit/Model/Menu/BuilderTest.php b/app/code/Magento/Backend/Test/Unit/Model/Menu/BuilderTest.php
index 7bda9b38a2b95a3a338f5e8e8e07c2463ab734d1..ec015029675eae4591b14bfb9cc02ea0417cdad6 100644
--- a/app/code/Magento/Backend/Test/Unit/Model/Menu/BuilderTest.php
+++ b/app/code/Magento/Backend/Test/Unit/Model/Menu/BuilderTest.php
@@ -5,33 +5,36 @@
  */
 namespace Magento\Backend\Test\Unit\Model\Menu;
 
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+
 class BuilderTest extends \PHPUnit_Framework_TestCase
 {
     /**
      * @var \Magento\Backend\Model\Menu\Builder
      */
-    protected $_model;
+    private $model;
 
     /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Backend\Model\Menu|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $_menuMock;
+    private $menuMock;
 
     /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Backend\Model\Menu\Item\Factory|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $_factoryMock;
+    private $factoryMock;
 
     protected function setUp()
     {
-        $this->_factoryMock = $this->getMock(\Magento\Backend\Model\Menu\Item\Factory::class, [], [], '', false);
-        $this->_menuMock = $this->getMock(
-            \Magento\Backend\Model\Menu::class,
-            [],
-            [$this->getMock(\Psr\Log\LoggerInterface::class)]
+        $this->factoryMock = $this->getMock(\Magento\Backend\Model\Menu\Item\Factory::class, [], [], '', false);
+        $this->menuMock = $this->getMock(\Magento\Backend\Model\Menu::class, [], [], '', false);
+
+        $this->model = (new ObjectManager($this))->getObject(
+            \Magento\Backend\Model\Menu\Builder::class,
+            [
+                'menuItemFactory' => $this->factoryMock
+            ]
         );
-
-        $this->_model = new \Magento\Backend\Model\Menu\Builder($this->_factoryMock, $this->_menuMock);
     }
 
     public function testProcessCommand()
@@ -41,20 +44,20 @@ class BuilderTest extends \PHPUnit_Framework_TestCase
         $command2 = $this->getMock(\Magento\Backend\Model\Menu\Builder\Command\Update::class, [], [], '', false);
         $command2->expects($this->any())->method('getId')->will($this->returnValue(1));
         $command->expects($this->once())->method('chain')->with($this->equalTo($command2));
-        $this->_model->processCommand($command);
-        $this->_model->processCommand($command2);
+        $this->model->processCommand($command);
+        $this->model->processCommand($command2);
     }
 
     public function testGetResultBuildsTreeStructure()
     {
         $item1 = $this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false);
-        $item1->expects($this->once())->method('getChildren')->will($this->returnValue($this->_menuMock));
-        $this->_factoryMock->expects($this->any())->method('create')->will($this->returnValue($item1));
+        $item1->expects($this->once())->method('getChildren')->will($this->returnValue($this->menuMock));
+        $this->factoryMock->expects($this->any())->method('create')->will($this->returnValue($item1));
 
         $item2 = $this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false);
-        $this->_factoryMock->expects($this->at(1))->method('create')->will($this->returnValue($item2));
+        $this->factoryMock->expects($this->at(1))->method('create')->will($this->returnValue($item2));
 
-        $this->_menuMock->expects(
+        $this->menuMock->expects(
             $this->at(0)
         )->method(
             'add'
@@ -64,7 +67,7 @@ class BuilderTest extends \PHPUnit_Framework_TestCase
             $this->equalTo(2)
         );
 
-        $this->_menuMock->expects(
+        $this->menuMock->expects(
             $this->at(1)
         )->method(
             'add'
@@ -74,7 +77,7 @@ class BuilderTest extends \PHPUnit_Framework_TestCase
             $this->equalTo(4)
         );
 
-        $this->_model->processCommand(
+        $this->model->processCommand(
             new \Magento\Backend\Model\Menu\Builder\Command\Add(
                 [
                     'id' => 'item1',
@@ -85,7 +88,7 @@ class BuilderTest extends \PHPUnit_Framework_TestCase
                 ]
             )
         );
-        $this->_model->processCommand(
+        $this->model->processCommand(
             new \Magento\Backend\Model\Menu\Builder\Command\Add(
                 [
                     'id' => 'item2',
@@ -98,12 +101,12 @@ class BuilderTest extends \PHPUnit_Framework_TestCase
             )
         );
 
-        $this->_model->getResult($this->_menuMock);
+        $this->model->getResult($this->menuMock);
     }
 
     public function testGetResultSkipsRemovedItems()
     {
-        $this->_model->processCommand(
+        $this->model->processCommand(
             new \Magento\Backend\Model\Menu\Builder\Command\Add(
                 [
                     'id' => 1,
@@ -113,11 +116,11 @@ class BuilderTest extends \PHPUnit_Framework_TestCase
                 ]
             )
         );
-        $this->_model->processCommand(new \Magento\Backend\Model\Menu\Builder\Command\Remove(['id' => 1]));
+        $this->model->processCommand(new \Magento\Backend\Model\Menu\Builder\Command\Remove(['id' => 1]));
 
-        $this->_menuMock->expects($this->never())->method('addChild');
+        $this->menuMock->expects($this->never())->method('addChild');
 
-        $this->_model->getResult($this->_menuMock);
+        $this->model->getResult($this->menuMock);
     }
 
     /**
@@ -126,9 +129,9 @@ class BuilderTest extends \PHPUnit_Framework_TestCase
     public function testGetResultSkipItemsWithInvalidParent()
     {
         $item1 = $this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false);
-        $this->_factoryMock->expects($this->any())->method('create')->will($this->returnValue($item1));
+        $this->factoryMock->expects($this->any())->method('create')->will($this->returnValue($item1));
 
-        $this->_model->processCommand(
+        $this->model->processCommand(
             new \Magento\Backend\Model\Menu\Builder\Command\Add(
                 [
                     'id' => 'item1',
@@ -140,6 +143,6 @@ class BuilderTest extends \PHPUnit_Framework_TestCase
             )
         );
 
-        $this->_model->getResult($this->_menuMock);
+        $this->model->getResult($this->menuMock);
     }
 }
diff --git a/app/code/Magento/Backend/Test/Unit/Model/Menu/ConfigTest.php b/app/code/Magento/Backend/Test/Unit/Model/Menu/ConfigTest.php
index dee7518be3ac911b8e64b2d9cda0b84f9496b611..5f50c17db8d326466e9eeb90cc8e3d9e50295610 100644
--- a/app/code/Magento/Backend/Test/Unit/Model/Menu/ConfigTest.php
+++ b/app/code/Magento/Backend/Test/Unit/Model/Menu/ConfigTest.php
@@ -5,59 +5,43 @@
  */
 namespace Magento\Backend\Test\Unit\Model\Menu;
 
-/**
- * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
- */
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+
 class ConfigTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $_cacheInstanceMock;
-
-    /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $_directorMock;
-
-    /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Framework\App\Cache\Type\Config|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $_configReaderMock;
+    private $cacheInstanceMock;
 
     /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Backend\Model\Menu\Config\Reader|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $_menuFactoryMock;
+    private $configReaderMock;
 
     /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Backend\Model\Menu|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $_eventManagerMock;
+    private $menuMock;
 
     /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Backend\Model\Menu\Builder|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $_menuMock;
+    private $menuBuilderMock;
 
     /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
+     * @var \Psr\Log\LoggerInterface|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $_menuBuilderMock;
-
-    /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $_logger;
+    private $logger;
 
     /**
      * @var \Magento\Backend\Model\Menu\Config
      */
-    protected $_model;
+    private $model;
 
     protected function setUp()
     {
-        $this->_cacheInstanceMock = $this->getMock(
+        $this->cacheInstanceMock = $this->getMock(
             \Magento\Framework\App\Cache\Type\Config::class,
             [],
             [],
@@ -65,15 +49,7 @@ class ConfigTest extends \PHPUnit_Framework_TestCase
             false
         );
 
-        $this->_directorMock = $this->getMock(
-            \Magento\Backend\Model\Menu\AbstractDirector::class,
-            [],
-            [],
-            '',
-            false
-        );
-
-        $this->_menuFactoryMock = $this->getMock(
+        $menuFactoryMock = $this->getMock(
             \Magento\Backend\Model\MenuFactory::class,
             ['create'],
             [],
@@ -81,7 +57,7 @@ class ConfigTest extends \PHPUnit_Framework_TestCase
             false
         );
 
-        $this->_configReaderMock = $this->getMock(
+        $this->configReaderMock = $this->getMock(
             \Magento\Backend\Model\Menu\Config\Reader::class,
             [],
             [],
@@ -89,30 +65,15 @@ class ConfigTest extends \PHPUnit_Framework_TestCase
             false
         );
 
-        $this->_eventManagerMock = $this->getMock(
-            \Magento\Framework\Event\ManagerInterface::class,
-            [],
-            [],
-            '',
-            false,
-            false
-        );
-
-        $this->_logger = $this->getMock(\Psr\Log\LoggerInterface::class);
-
-        $this->_menuMock = $this->getMock(
-            \Magento\Backend\Model\Menu::class,
-            [],
-            [$this->getMock(\Psr\Log\LoggerInterface::class)]
-        );
+        $this->logger = $this->getMock(\Psr\Log\LoggerInterface::class);
 
-        $this->_menuBuilderMock = $this->getMock(\Magento\Backend\Model\Menu\Builder::class, [], [], '', false);
+        $this->menuMock = $this->getMock(\Magento\Backend\Model\Menu::class, [], [], '', false);
 
-        $this->_menuFactoryMock->expects($this->any())->method('create')->will($this->returnValue($this->_menuMock));
+        $this->menuBuilderMock = $this->getMock(\Magento\Backend\Model\Menu\Builder::class, [], [], '', false);
 
-        $scopeConfig = $this->getMock(\Magento\Framework\App\Config\ScopeConfigInterface::class);
+        $menuFactoryMock->expects($this->any())->method('create')->will($this->returnValue($this->menuMock));
 
-        $this->_configReaderMock->expects($this->any())->method('read')->will($this->returnValue([]));
+        $this->configReaderMock->expects($this->any())->method('read')->will($this->returnValue([]));
 
         $appState = $this->getMock(\Magento\Framework\App\State::class, ['getAreaCode'], [], '', false);
         $appState->expects(
@@ -123,22 +84,22 @@ class ConfigTest extends \PHPUnit_Framework_TestCase
             $this->returnValue(\Magento\Backend\App\Area\FrontNameResolver::AREA_CODE)
         );
 
-        $this->_model = new \Magento\Backend\Model\Menu\Config(
-            $this->_menuBuilderMock,
-            $this->_directorMock,
-            $this->_menuFactoryMock,
-            $this->_configReaderMock,
-            $this->_cacheInstanceMock,
-            $this->_eventManagerMock,
-            $this->_logger,
-            $scopeConfig,
-            $appState
+        $this->model = (new ObjectManager($this))->getObject(
+            \Magento\Backend\Model\Menu\Config::class,
+            [
+                'menuBuilder' => $this->menuBuilderMock,
+                'menuFactory' => $menuFactoryMock,
+                'configReader' => $this->configReaderMock,
+                'configCacheType' => $this->cacheInstanceMock,
+                'logger' => $this->logger,
+                'appState' => $appState,
+            ]
         );
     }
 
     public function testGetMenuWithCachedObjectReturnsUnserializedObject()
     {
-        $this->_cacheInstanceMock->expects(
+        $this->cacheInstanceMock->expects(
             $this->once()
         )->method(
             'load'
@@ -148,14 +109,14 @@ class ConfigTest extends \PHPUnit_Framework_TestCase
             $this->returnValue('menu_cache')
         );
 
-        $this->_menuMock->expects($this->once())->method('unserialize')->with('menu_cache');
+        $this->menuMock->expects($this->once())->method('unserialize')->with('menu_cache');
 
-        $this->assertEquals($this->_menuMock, $this->_model->getMenu());
+        $this->assertEquals($this->menuMock, $this->model->getMenu());
     }
 
     public function testGetMenuWithNotCachedObjectBuidlsObject()
     {
-        $this->_cacheInstanceMock->expects(
+        $this->cacheInstanceMock->expects(
             $this->at(0)
         )->method(
             'load'
@@ -165,17 +126,17 @@ class ConfigTest extends \PHPUnit_Framework_TestCase
             $this->returnValue(false)
         );
 
-        $this->_configReaderMock->expects($this->once())->method('read')->will($this->returnValue([]));
+        $this->configReaderMock->expects($this->once())->method('read')->will($this->returnValue([]));
 
-        $this->_menuBuilderMock->expects(
+        $this->menuBuilderMock->expects(
             $this->exactly(1)
         )->method(
             'getResult'
         )->will(
-            $this->returnValue($this->_menuMock)
+            $this->returnValue($this->menuMock)
         );
 
-        $this->assertEquals($this->_menuMock, $this->_model->getMenu());
+        $this->assertEquals($this->menuMock, $this->model->getMenu());
     }
 
     /**
@@ -186,7 +147,7 @@ class ConfigTest extends \PHPUnit_Framework_TestCase
     public function testGetMenuExceptionLogged($expectedException)
     {
         $this->setExpectedException($expectedException);
-        $this->_menuBuilderMock->expects(
+        $this->menuBuilderMock->expects(
             $this->exactly(1)
         )->method(
             'getResult'
@@ -194,7 +155,7 @@ class ConfigTest extends \PHPUnit_Framework_TestCase
             $this->throwException(new $expectedException())
         );
 
-        $this->_model->getMenu();
+        $this->model->getMenu();
     }
 
     public function getMenuExceptionLoggedDataProvider()
@@ -208,9 +169,9 @@ class ConfigTest extends \PHPUnit_Framework_TestCase
 
     public function testGetMenuGenericExceptionIsNotLogged()
     {
-        $this->_logger->expects($this->never())->method('critical');
+        $this->logger->expects($this->never())->method('critical');
 
-        $this->_menuBuilderMock->expects(
+        $this->menuBuilderMock->expects(
             $this->exactly(1)
         )->method(
             'getResult'
@@ -218,7 +179,7 @@ class ConfigTest extends \PHPUnit_Framework_TestCase
             $this->throwException(new \Exception())
         );
         try {
-            $this->_model->getMenu();
+            $this->model->getMenu();
         } catch (\Exception $e) {
             return;
         }
diff --git a/app/code/Magento/Backend/Test/Unit/Model/Menu/Filter/IteratorTest.php b/app/code/Magento/Backend/Test/Unit/Model/Menu/Filter/IteratorTest.php
index 19836ba7c94017d575aaae060ab120667a273ff2..06dee1f01fd88439ad1a1bcf1f959e19eb13e9be 100644
--- a/app/code/Magento/Backend/Test/Unit/Model/Menu/Filter/IteratorTest.php
+++ b/app/code/Magento/Backend/Test/Unit/Model/Menu/Filter/IteratorTest.php
@@ -5,49 +5,49 @@
  */
 namespace Magento\Backend\Test\Unit\Model\Menu\Filter;
 
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+
 class IteratorTest extends \PHPUnit_Framework_TestCase
 {
     /**
      * @var \Magento\Backend\Model\Menu
      */
-    protected $_menuModel;
+    private $menuModel;
 
     /**
      * @var \Magento\Backend\Model\Menu\Item[]
      */
-    protected $_items = [];
+    private $items = [];
 
     protected function setUp()
     {
-        $this->_items['item1'] = $this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false);
-        $this->_items['item1']->expects($this->any())->method('getId')->will($this->returnValue('item1'));
-        $this->_items['item1']->expects($this->any())->method('isDisabled')->will($this->returnValue(false));
-        $this->_items['item1']->expects($this->any())->method('isAllowed')->will($this->returnValue(true));
-
-        $this->_items['item2'] = $this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false);
-        $this->_items['item2']->expects($this->any())->method('getId')->will($this->returnValue('item2'));
-        $this->_items['item2']->expects($this->any())->method('isDisabled')->will($this->returnValue(true));
-        $this->_items['item2']->expects($this->any())->method('isAllowed')->will($this->returnValue(true));
-
-        $this->_items['item3'] = $this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false);
-        $this->_items['item3']->expects($this->any())->method('getId')->will($this->returnValue('item3'));
-        $this->_items['item3']->expects($this->any())->method('isDisabled')->will($this->returnValue(false));
-        $this->_items['item3']->expects($this->any())->method('isAllowed')->will($this->returnValue(false));
-
-        $loggerMock = $this->getMock(\Psr\Log\LoggerInterface::class);
-
-        $this->_menuModel = new \Magento\Backend\Model\Menu($loggerMock);
+        $this->items['item1'] = $this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false);
+        $this->items['item1']->expects($this->any())->method('getId')->will($this->returnValue('item1'));
+        $this->items['item1']->expects($this->any())->method('isDisabled')->will($this->returnValue(false));
+        $this->items['item1']->expects($this->any())->method('isAllowed')->will($this->returnValue(true));
+
+        $this->items['item2'] = $this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false);
+        $this->items['item2']->expects($this->any())->method('getId')->will($this->returnValue('item2'));
+        $this->items['item2']->expects($this->any())->method('isDisabled')->will($this->returnValue(true));
+        $this->items['item2']->expects($this->any())->method('isAllowed')->will($this->returnValue(true));
+
+        $this->items['item3'] = $this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false);
+        $this->items['item3']->expects($this->any())->method('getId')->will($this->returnValue('item3'));
+        $this->items['item3']->expects($this->any())->method('isDisabled')->will($this->returnValue(false));
+        $this->items['item3']->expects($this->any())->method('isAllowed')->will($this->returnValue(false));
+
+        $this->menuModel = (new ObjectManager($this))->getObject(\Magento\Backend\Model\Menu::class);
     }
 
     public function testLoopWithAllItemsDisabledDoesntIterate()
     {
-        $this->_menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false));
-        $this->_menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false));
-        $this->_menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false));
-        $this->_menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false));
-        $this->_menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false));
+        $this->menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false));
+        $this->menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false));
+        $this->menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false));
+        $this->menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false));
+        $this->menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false));
         $filterIteratorModel = new \Magento\Backend\Model\Menu\Filter\Iterator(
-            $this->_menuModel->getIterator()
+            $this->menuModel->getIterator()
         );
 
         $items = [];
@@ -59,15 +59,15 @@ class IteratorTest extends \PHPUnit_Framework_TestCase
 
     public function testLoopIteratesOnlyValidItems()
     {
-        $this->_menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false));
-        $this->_menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false));
+        $this->menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false));
+        $this->menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false));
 
-        $this->_menuModel->add($this->_items['item1']);
+        $this->menuModel->add($this->items['item1']);
 
-        $this->_menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false));
-        $this->_menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false));
+        $this->menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false));
+        $this->menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false));
         $filterIteratorModel = new \Magento\Backend\Model\Menu\Filter\Iterator(
-            $this->_menuModel->getIterator()
+            $this->menuModel->getIterator()
         );
 
         $items = [];
@@ -79,16 +79,16 @@ class IteratorTest extends \PHPUnit_Framework_TestCase
 
     public function testLoopIteratesDosntIterateDisabledItems()
     {
-        $this->_menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false));
-        $this->_menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false));
+        $this->menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false));
+        $this->menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false));
 
-        $this->_menuModel->add($this->_items['item1']);
-        $this->_menuModel->add($this->_items['item2']);
+        $this->menuModel->add($this->items['item1']);
+        $this->menuModel->add($this->items['item2']);
 
-        $this->_menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false));
-        $this->_menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false));
+        $this->menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false));
+        $this->menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false));
         $filterIteratorModel = new \Magento\Backend\Model\Menu\Filter\Iterator(
-            $this->_menuModel->getIterator()
+            $this->menuModel->getIterator()
         );
 
         $items = [];
@@ -100,16 +100,16 @@ class IteratorTest extends \PHPUnit_Framework_TestCase
 
     public function testLoopIteratesDosntIterateNotAllowedItems()
     {
-        $this->_menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false));
-        $this->_menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false));
+        $this->menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false));
+        $this->menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false));
 
-        $this->_menuModel->add($this->_items['item1']);
-        $this->_menuModel->add($this->_items['item3']);
+        $this->menuModel->add($this->items['item1']);
+        $this->menuModel->add($this->items['item3']);
 
-        $this->_menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false));
-        $this->_menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false));
+        $this->menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false));
+        $this->menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false));
         $filterIteratorModel = new \Magento\Backend\Model\Menu\Filter\Iterator(
-            $this->_menuModel->getIterator()
+            $this->menuModel->getIterator()
         );
 
         $items = [];
@@ -121,17 +121,17 @@ class IteratorTest extends \PHPUnit_Framework_TestCase
 
     public function testLoopIteratesMixedItems()
     {
-        $this->_menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false));
-        $this->_menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false));
+        $this->menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false));
+        $this->menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false));
 
-        $this->_menuModel->add($this->_items['item1']);
-        $this->_menuModel->add($this->_items['item2']);
-        $this->_menuModel->add($this->_items['item3']);
+        $this->menuModel->add($this->items['item1']);
+        $this->menuModel->add($this->items['item2']);
+        $this->menuModel->add($this->items['item3']);
 
-        $this->_menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false));
-        $this->_menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false));
+        $this->menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false));
+        $this->menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false));
         $filterIteratorModel = new \Magento\Backend\Model\Menu\Filter\Iterator(
-            $this->_menuModel->getIterator()
+            $this->menuModel->getIterator()
         );
 
         $items = [];
diff --git a/app/code/Magento/Backend/Test/Unit/Model/Menu/ItemTest.php b/app/code/Magento/Backend/Test/Unit/Model/Menu/ItemTest.php
index fcef1bd374c01b4160880143c095464e3020fb18..b6cd61870d60f69f6b93eea88dd6aa56b121d66a 100644
--- a/app/code/Magento/Backend/Test/Unit/Model/Menu/ItemTest.php
+++ b/app/code/Magento/Backend/Test/Unit/Model/Menu/ItemTest.php
@@ -40,16 +40,14 @@ class ItemTest extends \PHPUnit_Framework_TestCase
      */
     protected $_moduleManager;
 
-    /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $_validatorMock;
-
     /**
      * @var \PHPUnit_Framework_MockObject_MockObject
      */
     protected $_moduleListMock;
 
+    /** @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager */
+    private $objectManager;
+
     /**
      * @var array
      */
@@ -58,8 +56,8 @@ class ItemTest extends \PHPUnit_Framework_TestCase
         'title' => 'Item Title',
         'action' => '/system/config',
         'resource' => 'Magento_Config::config',
-        'dependsOnModule' => 'Magento_Backend',
-        'dependsOnConfig' => 'system/config/isEnabled',
+        'depends_on_module' => 'Magento_Backend',
+        'depends_on_config' => 'system/config/isEnabled',
         'tooltip' => 'Item tooltip',
     ];
 
@@ -76,15 +74,15 @@ class ItemTest extends \PHPUnit_Framework_TestCase
         );
         $this->_urlModelMock = $this->getMock(\Magento\Backend\Model\Url::class, [], [], '', false);
         $this->_moduleManager = $this->getMock(\Magento\Framework\Module\Manager::class, [], [], '', false);
-        $this->_validatorMock = $this->getMock(\Magento\Backend\Model\Menu\Item\Validator::class);
-        $this->_validatorMock->expects($this->any())->method('validate');
+        $validatorMock = $this->getMock(\Magento\Backend\Model\Menu\Item\Validator::class);
+        $validatorMock->expects($this->any())->method('validate');
         $this->_moduleListMock = $this->getMock(\Magento\Framework\Module\ModuleListInterface::class);
 
-        $helper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
-        $this->_model = $helper->getObject(
+        $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+        $this->_model = $this->objectManager->getObject(
             \Magento\Backend\Model\Menu\Item::class,
             [
-                'validator' => $this->_validatorMock,
+                'validator' => $validatorMock,
                 'authorization' => $this->_aclMock,
                 'scopeConfig' => $this->_scopeConfigMock,
                 'menuFactory' => $this->_menuFactoryMock,
@@ -99,8 +97,7 @@ class ItemTest extends \PHPUnit_Framework_TestCase
     public function testGetUrlWithEmptyActionReturnsHashSign()
     {
         $this->_params['action'] = '';
-        $helper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
-        $item = $helper->getObject(
+        $item = $this->objectManager->getObject(
             \Magento\Backend\Model\Menu\Item::class,
             ['menuFactory' => $this->_menuFactoryMock, 'data' => $this->_params]
         );
@@ -129,8 +126,7 @@ class ItemTest extends \PHPUnit_Framework_TestCase
     public function testHasClickCallbackReturnsTrueIfItemHasNoAction()
     {
         $this->_params['action'] = '';
-        $helper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
-        $item = $helper->getObject(
+        $item = $this->objectManager->getObject(
             \Magento\Backend\Model\Menu\Item::class,
             ['menuFactory' => $this->_menuFactoryMock, 'data' => $this->_params]
         );
@@ -140,8 +136,7 @@ class ItemTest extends \PHPUnit_Framework_TestCase
     public function testGetClickCallbackReturnsStoppingJsIfItemDoesntHaveAction()
     {
         $this->_params['action'] = '';
-        $helper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
-        $item = $helper->getObject(
+        $item = $this->objectManager->getObject(
             \Magento\Backend\Model\Menu\Item::class,
             ['menuFactory' => $this->_menuFactoryMock, 'data' => $this->_params]
         );
@@ -218,15 +213,86 @@ class ItemTest extends \PHPUnit_Framework_TestCase
 
     public function testGetChildrenCreatesSubmenuOnFirstCall()
     {
-        $menuMock = $this->getMock(
-            \Magento\Backend\Model\Menu::class,
-            [],
-            [$this->getMock(\Psr\Log\LoggerInterface::class)]
-        );
+        $menuMock = $this->getMock(\Magento\Backend\Model\Menu::class, [], [], '', false);
 
         $this->_menuFactoryMock->expects($this->once())->method('create')->will($this->returnValue($menuMock));
 
         $this->_model->getChildren();
         $this->_model->getChildren();
     }
+
+    /**
+     * @param array $data
+     * @param array $expected
+     * @dataProvider toArrayDataProvider
+     */
+    public function testToArray(array $data, array $expected)
+    {
+        $menuMock = $this->getMock(\Magento\Backend\Model\Menu::class, [], [], '', false);
+        $this->_menuFactoryMock->method('create')->will($this->returnValue($menuMock));
+        $menuMock->method('toArray')
+            ->willReturn($data['sub_menu']);
+
+        $model = $this->objectManager->getObject(
+            \Magento\Backend\Model\Menu\Item::class,
+            [
+                'authorization' => $this->_aclMock,
+                'scopeConfig' => $this->_scopeConfigMock,
+                'menuFactory' => $this->_menuFactoryMock,
+                'urlModel' => $this->_urlModelMock,
+                'moduleList' => $this->_moduleListMock,
+                'moduleManager' => $this->_moduleManager,
+                'data' => $data
+            ]
+        );
+        $this->assertEquals($expected, $model->toArray());
+    }
+
+    /**
+     * @return array
+     */
+    public function toArrayDataProvider()
+    {
+        return include __DIR__ . '/../_files/menu_item_data.php';
+    }
+
+    /**
+     * @param array $constructorData
+     * @param array $populateFromData
+     * @param array $expected
+     * @dataProvider populateFromArrayDataProvider
+     */
+    public function testPopulateFromArray(
+        array $constructorData,
+        array $populateFromData,
+        array $expected
+    ) {
+        $menuMock = $this->getMock(\Magento\Backend\Model\Menu::class, [], [], '', false);
+        $this->_menuFactoryMock->method('create')->willReturn($menuMock);
+        $menuMock->method('toArray')
+            ->willReturn(['submenuArray']);
+
+        $model = $this->objectManager->getObject(
+            \Magento\Backend\Model\Menu\Item::class,
+            [
+                'authorization' => $this->_aclMock,
+                'scopeConfig' => $this->_scopeConfigMock,
+                'menuFactory' => $this->_menuFactoryMock,
+                'urlModel' => $this->_urlModelMock,
+                'moduleList' => $this->_moduleListMock,
+                'moduleManager' => $this->_moduleManager,
+                'data' => $constructorData
+            ]
+        );
+        $model->populateFromArray($populateFromData);
+        $this->assertEquals($expected, $model->toArray());
+    }
+
+    /**
+     * @return array
+     */
+    public function populateFromArrayDataProvider()
+    {
+        return include __DIR__ . '/../_files/menu_item_constructor_data.php';
+    }
 }
diff --git a/app/code/Magento/Backend/Test/Unit/Model/MenuTest.php b/app/code/Magento/Backend/Test/Unit/Model/MenuTest.php
index c985bec92074a8f93e4df4b9fb73e336a5037f99..12968df9f340f888a2999d516a1304510b181316 100644
--- a/app/code/Magento/Backend/Test/Unit/Model/MenuTest.php
+++ b/app/code/Magento/Backend/Test/Unit/Model/MenuTest.php
@@ -5,6 +5,10 @@
  */
 namespace Magento\Backend\Test\Unit\Model;
 
+use Magento\Backend\Model\Menu\Item;
+use Magento\Backend\Model\Menu\Item\Factory;
+use Magento\Framework\Serialize\SerializerInterface;
+
 class MenuTest extends \PHPUnit_Framework_TestCase
 {
     /**
@@ -22,8 +26,14 @@ class MenuTest extends \PHPUnit_Framework_TestCase
      */
     protected $_items = [];
 
+    /**
+     * @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager
+     */
+    private $objectManagerHelper;
+
     protected function setUp()
     {
+        $this->objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
         $this->_items['item1'] = $this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false);
         $this->_items['item1']->expects($this->any())->method('getId')->will($this->returnValue('item1'));
 
@@ -35,7 +45,12 @@ class MenuTest extends \PHPUnit_Framework_TestCase
 
         $this->_logger = $this->getMock(\Psr\Log\LoggerInterface::class);
 
-        $this->_model = new \Magento\Backend\Model\Menu($this->_logger);
+        $this->_model = $this->objectManagerHelper->getObject(
+            \Magento\Backend\Model\Menu::class,
+            [
+                'logger' => $this->_logger
+            ]
+        );
     }
 
     public function testAdd()
@@ -53,7 +68,7 @@ class MenuTest extends \PHPUnit_Framework_TestCase
 
     public function testAddToItem()
     {
-        $subMenu = $this->getMock(\Magento\Backend\Model\Menu::class, [], [$this->_logger]);
+        $subMenu = $this->getMockBuilder(\Magento\Backend\Model\Menu::class)->disableOriginalConstructor()->getMock();
         $subMenu->expects($this->once())->method("add")->with($this->_items['item2']);
 
         $this->_items['item1']->expects($this->once())->method("getChildren")->will($this->returnValue($subMenu));
@@ -101,19 +116,29 @@ class MenuTest extends \PHPUnit_Framework_TestCase
 
     public function testGetRecursive()
     {
-        $menu1 = new \Magento\Backend\Model\Menu($this->_logger);
-        $menu2 = new \Magento\Backend\Model\Menu($this->_logger);
+        $menuOne = $this->objectManagerHelper->getObject(
+            \Magento\Backend\Model\Menu::class,
+            [
+                'logger' => $this->_logger
+            ]
+        );
+        $menuTwo = $this->objectManagerHelper->getObject(
+            \Magento\Backend\Model\Menu::class,
+            [
+                'logger' => $this->_logger
+            ]
+        );
 
         $this->_items['item1']->expects($this->any())->method('hasChildren')->will($this->returnValue(true));
-        $this->_items['item1']->expects($this->any())->method('getChildren')->will($this->returnValue($menu1));
+        $this->_items['item1']->expects($this->any())->method('getChildren')->will($this->returnValue($menuOne));
         $this->_model->add($this->_items['item1']);
 
         $this->_items['item2']->expects($this->any())->method('hasChildren')->will($this->returnValue(true));
-        $this->_items['item2']->expects($this->any())->method('getChildren')->will($this->returnValue($menu2));
-        $menu1->add($this->_items['item2']);
+        $this->_items['item2']->expects($this->any())->method('getChildren')->will($this->returnValue($menuTwo));
+        $menuOne->add($this->_items['item2']);
 
         $this->_items['item3']->expects($this->any())->method('hasChildren')->will($this->returnValue(false));
-        $menu2->add($this->_items['item3']);
+        $menuTwo->add($this->_items['item3']);
 
         $this->assertEquals($this->_items['item1'], $this->_model->get('item1'));
         $this->assertEquals($this->_items['item2'], $this->_model->get('item2'));
@@ -126,11 +151,7 @@ class MenuTest extends \PHPUnit_Framework_TestCase
         $this->_model->add($this->_items['item2']);
         $this->_model->add($this->_items['item3']);
 
-        $subMenu = $this->getMock(
-            \Magento\Backend\Model\Menu::class,
-            [],
-            [$this->getMock(\Psr\Log\LoggerInterface::class)]
-        );
+        $subMenu = $this->getMockBuilder(\Magento\Backend\Model\Menu::class)->disableOriginalConstructor()->getMock();
         $subMenu->expects($this->once())->method("add")->with($this->_items['item3']);
 
         $this->_items['item1']->expects($this->once())->method("getChildren")->will($this->returnValue($subMenu));
@@ -179,11 +200,7 @@ class MenuTest extends \PHPUnit_Framework_TestCase
 
     public function testRemoveRemovesMenuItemRecursively()
     {
-        $menuMock = $this->getMock(
-            \Magento\Backend\Model\Menu::class,
-            [],
-            [$this->getMock(\Psr\Log\LoggerInterface::class)]
-        );
+        $menuMock = $this->getMockBuilder(\Magento\Backend\Model\Menu::class)->disableOriginalConstructor()->getMock();
         $menuMock->expects($this->once())->method('remove')->with($this->equalTo('item2'));
 
         $this->_items['item1']->expects($this->any())->method('hasChildren')->will($this->returnValue(true));
@@ -214,7 +231,12 @@ class MenuTest extends \PHPUnit_Framework_TestCase
     {
         $this->_logger->expects($this->any())->method('log');
 
-        $subMenu = new \Magento\Backend\Model\Menu($this->_logger);
+        $subMenu = $this->objectManagerHelper->getObject(
+            \Magento\Backend\Model\Menu::class,
+            [
+                'logger' => $this->_logger
+            ]
+        );
 
         $this->_items['item1']->expects($this->any())->method("hasChildren")->will($this->returnValue(true));
 
@@ -285,11 +307,11 @@ class MenuTest extends \PHPUnit_Framework_TestCase
             $items[] = $item->getId();
         }
 
-        $items2 = [];
+        $itemsTwo = [];
         foreach ($this->_model as $item) {
-            $items2[] = $item->getId();
+            $itemsTwo[] = $item->getId();
         }
-        $this->assertEquals($items, $items2);
+        $this->assertEquals($items, $itemsTwo);
     }
 
     /**
@@ -307,10 +329,10 @@ class MenuTest extends \PHPUnit_Framework_TestCase
             'item3' => ['item1', 'item2', 'item3'],
         ];
         $actual = [];
-        foreach ($this->_model as $valLoop1) {
-            $keyLevel1 = $valLoop1->getId();
-            foreach ($this->_model as $valLoop2) {
-                $actual[$keyLevel1][] = $valLoop2->getId();
+        foreach ($this->_model as $valLoopOne) {
+            $keyLevelOne = $valLoopOne->getId();
+            foreach ($this->_model as $valLoopTwo) {
+                $actual[$keyLevelOne][] = $valLoopTwo->getId();
             }
         }
         $this->assertEquals($expected, $actual);
@@ -318,7 +340,45 @@ class MenuTest extends \PHPUnit_Framework_TestCase
 
     public function testSerialize()
     {
-        $this->assertNotEmpty($this->_model->serialize());
-        $this->_model->add($this->_items['item1']);
+        $serializerMock = $this->getMock(SerializerInterface::class);
+        $serializerMock->expects($this->once())
+            ->method('serialize')
+            ->with([['arrayData']])
+            ->willReturn('serializedString');
+        $menu = $this->objectManagerHelper->getObject(
+            \Magento\Backend\Model\Menu::class,
+            [
+                'logger' => $this->_logger,
+                'serializer' => $serializerMock,
+            ]
+        );
+        $itemMock = $this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false);
+        $itemMock->expects($this->any())->method('getId')->will($this->returnValue('item1'));
+        $itemMock->expects($this->once())
+            ->method('toArray')
+            ->willReturn(['arrayData']);
+        $menu->add($itemMock);
+        $this->assertEquals('serializedString', $menu->serialize());
+    }
+
+    public function testUnserialize()
+    {
+        $serializerMock = $this->getMock(SerializerInterface::class);
+        $serializerMock->expects($this->once())
+            ->method('unserialize')
+            ->willReturn([['unserializedData']]);
+        $menuItemFactoryMock = $this->getMock(Factory::class, [], [], '', false);
+        $menuItemFactoryMock->expects($this->once())
+            ->method('create')
+            ->with(['unserializedData']);
+        $menu = $this->objectManagerHelper->getObject(
+            \Magento\Backend\Model\Menu::class,
+            [
+                'logger' => $this->_logger,
+                'serializer' => $serializerMock,
+                'menuItemFactory' => $menuItemFactoryMock,
+            ]
+        );
+        $menu->unserialize('serializedString');
     }
 }
diff --git a/app/code/Magento/Backend/Test/Unit/Model/UrlTest.php b/app/code/Magento/Backend/Test/Unit/Model/UrlTest.php
index 4eda145156c6dbf881eadf3d88981ffb9318d32c..fa83eb4210d467ba7d33935f934cbcc4801470fa 100644
--- a/app/code/Magento/Backend/Test/Unit/Model/UrlTest.php
+++ b/app/code/Magento/Backend/Test/Unit/Model/UrlTest.php
@@ -75,11 +75,7 @@ class UrlTest extends \PHPUnit_Framework_TestCase
     protected function setUp()
     {
         $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
-        $this->_menuMock = $this->getMock(
-            \Magento\Backend\Model\Menu::class,
-            [],
-            [$this->getMock(\Psr\Log\LoggerInterface::class)]
-        );
+        $this->_menuMock = $this->getMock(\Magento\Backend\Model\Menu::class, [], [], '', false);
 
         $this->_menuConfigMock = $this->getMock(\Magento\Backend\Model\Menu\Config::class, [], [], '', false);
         $this->_menuConfigMock->expects($this->any())->method('getMenu')->will($this->returnValue($this->_menuMock));
diff --git a/app/code/Magento/Backend/Test/Unit/Model/_files/menu_item_constructor_data.php b/app/code/Magento/Backend/Test/Unit/Model/_files/menu_item_constructor_data.php
new file mode 100644
index 0000000000000000000000000000000000000000..213e98de13866b610be60c311b984466d27dc7c0
--- /dev/null
+++ b/app/code/Magento/Backend/Test/Unit/Model/_files/menu_item_constructor_data.php
@@ -0,0 +1,133 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+return [
+    'default data to constructor' => [
+        [],
+        [
+            'id' => 'item',
+            'title' => 'Item Title',
+            'action' => '/system/config',
+            'resource' => 'Magento_Config::config',
+            'depends_on_module' => 'Magento_Backend',
+            'depends_on_config' => 'system/config/isEnabled',
+            'tooltip' => 'Item tooltip',
+        ],
+        [
+            'parent_id' => null,
+            'module_name' => 'Magento_Backend',
+            'sort_index' => null,
+            'depends_on_config' => 'system/config/isEnabled',
+            'id' => 'item',
+            'resource' => 'Magento_Config::config',
+            'path' => '',
+            'action' => '/system/config',
+            'depends_on_module' => 'Magento_Backend',
+            'tooltip' => 'Item tooltip',
+            'title' => 'Item Title',
+            'sub_menu' => null
+        ],
+    ],
+    'data without submenu to constructor' => [
+        [
+            'id' => 'item',
+            'title' => 'Item Title',
+            'action' => '/system/config',
+            'resource' => 'Magento_Config::config',
+            'depends_on_module' => 'Magento_Backend',
+            'depends_on_config' => 'system/config/isEnabled',
+            'tooltip' => 'Item tooltip',
+        ],
+        [
+            'parent_id' => '1',
+            'module_name' => 'Magento_Module1',
+            'sort_index' => '50',
+            'depends_on_config' => null,
+            'id' => '5',
+            'resource' => null,
+            'path' => null,
+            'action' => null,
+            'depends_on_module' => null,
+            'tooltip' => null,
+            'title' => null,
+            'sub_menu' => [
+                'id' => 'item',
+                'title' => 'Item Title',
+                'action' => '/system/config',
+                'resource' => 'Magento_Config::config',
+                'depends_on_module' => 'Magento_Backend',
+                'depends_on_config' => 'system/config/isEnabled',
+                'tooltip' => 'Item tooltip',
+            ],
+        ],
+        [
+            'parent_id' => '1',
+            'module_name' => 'Magento_Module1',
+            'sort_index' => '50',
+            'depends_on_config' => null,
+            'id' => '5',
+            'resource' => null,
+            'path' => '',
+            'action' => null,
+            'depends_on_module' => null,
+            'tooltip' => '',
+            'title' => null,
+            'sub_menu' => ['submenuArray']
+        ],
+    ],
+    'data with submenu to constructor' => [
+        [
+            'parent_id' => '1',
+            'module_name' => 'Magento_Module1',
+            'sort_index' => '50',
+            'depends_on_config' => null,
+            'id' => '5',
+            'resource' => null,
+            'path' => null,
+            'action' => null,
+            'depends_on_module' => null,
+            'tooltip' => null,
+            'title' => null,
+            'sub_menu' => [
+                'id' => 'item',
+                'title' => 'Item Title',
+                'action' => '/system/config',
+                'resource' => 'Magento_Config::config',
+                'depends_on_module' => 'Magento_Backend',
+                'depends_on_config' => 'system/config/isEnabled',
+                'tooltip' => 'Item tooltip',
+            ],
+        ],
+        [
+            'parent_id' => '1',
+            'module_name' => 'Magento_Module1',
+            'sort_index' => '50',
+            'sub_menu' => [
+                'id' => 'item',
+                'title' => 'Item Title',
+                'action' => '/system/config',
+                'resource' => 'Magento_Config::config',
+                'depends_on_module' => 'Magento_Backend',
+                'depends_on_config' => 'system/config/isEnabled',
+                'tooltip' => 'Item tooltip',
+            ],
+        ],
+        [
+            'parent_id' => '1',
+            'module_name' => 'Magento_Module1',
+            'sort_index' => '50',
+            'depends_on_config' => null,
+            'id' => null,
+            'resource' => null,
+            'path' => '',
+            'action' => null,
+            'depends_on_module' => null,
+            'tooltip' => '',
+            'title' => null,
+            'sub_menu' => ['submenuArray']
+        ],
+    ]
+];
diff --git a/app/code/Magento/Backend/Test/Unit/Model/_files/menu_item_data.php b/app/code/Magento/Backend/Test/Unit/Model/_files/menu_item_data.php
new file mode 100644
index 0000000000000000000000000000000000000000..c4c97e95af68e7a95b4a7c53df64b35c6fb85d14
--- /dev/null
+++ b/app/code/Magento/Backend/Test/Unit/Model/_files/menu_item_data.php
@@ -0,0 +1,118 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+return [
+    'no submenu' => [
+        [
+            'id' => 'item',
+            'title' => 'Item Title',
+            'action' => '/system/config',
+            'resource' => 'Magento_Config::config',
+            'depends_on_module' => 'Magento_Backend',
+            'depends_on_config' => 'system/config/isEnabled',
+            'tooltip' => 'Item tooltip',
+            'sub_menu' => null,
+        ],
+        [
+            'parent_id' => null,
+            'module_name' => 'Magento_Backend',
+            'sort_index' => null,
+            'depends_on_config' => 'system/config/isEnabled',
+            'id' => 'item',
+            'resource' => 'Magento_Config::config',
+            'path' => '',
+            'action' => '/system/config',
+            'depends_on_module' => 'Magento_Backend',
+            'tooltip' => 'Item tooltip',
+            'title' => 'Item Title',
+            'sub_menu' => null,
+        ]
+    ],
+    'with submenu' => [
+        [
+            'parent_id' => '1',
+            'module_name' => 'Magento_Module1',
+            'sort_index' => '50',
+            'depends_on_config' => null,
+            'id' => '5',
+            'resource' => null,
+            'path' => null,
+            'action' => null,
+            'depends_on_module' => null,
+            'tooltip' => null,
+            'title' => null,
+            'sub_menu' => [
+                'id' => 'item',
+                'title' => 'Item Title',
+                'action' => '/system/config',
+                'resource' => 'Magento_Config::config',
+                'depends_on_module' => 'Magento_Backend',
+                'depends_on_config' => 'system/config/isEnabled',
+                'tooltip' => 'Item tooltip',
+            ],
+        ],
+        [
+            'parent_id' => '1',
+            'module_name' => 'Magento_Module1',
+            'sort_index' => '50',
+            'depends_on_config' => null,
+            'id' => '5',
+            'resource' => null,
+            'path' => null,
+            'action' => null,
+            'depends_on_module' => null,
+            'tooltip' => '',
+            'title' => null,
+            'sub_menu' => [
+                'id' => 'item',
+                'title' => 'Item Title',
+                'action' => '/system/config',
+                'resource' => 'Magento_Config::config',
+                'depends_on_module' => 'Magento_Backend',
+                'depends_on_config' => 'system/config/isEnabled',
+                'tooltip' => 'Item tooltip',
+            ]
+        ]
+    ],
+    'small set of data' => [
+        [
+            'parent_id' => '1',
+            'module_name' => 'Magento_Module1',
+            'sort_index' => '50',
+            'sub_menu' => [
+                'id' => 'item',
+                'title' => 'Item Title',
+                'action' => '/system/config',
+                'resource' => 'Magento_Config::config',
+                'depends_on_module' => 'Magento_Backend',
+                'depends_on_config' => 'system/config/isEnabled',
+                'tooltip' => 'Item tooltip',
+            ],
+        ],
+        [
+            'parent_id' => '1',
+            'module_name' => 'Magento_Module1',
+            'sort_index' => '50',
+            'depends_on_config' => null,
+            'id' => null,
+            'resource' => null,
+            'path' => '',
+            'action' => null,
+            'depends_on_module' => null,
+            'tooltip' => '',
+            'title' => null,
+            'sub_menu' => [
+                'id' => 'item',
+                'title' => 'Item Title',
+                'action' => '/system/config',
+                'resource' => 'Magento_Config::config',
+                'depends_on_module' => 'Magento_Backend',
+                'depends_on_config' => 'system/config/isEnabled',
+                'tooltip' => 'Item tooltip',
+            ]
+        ]
+    ]
+];
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/Checkout/Model/PaymentInformationManagement.php b/app/code/Magento/Checkout/Model/PaymentInformationManagement.php
index 79e76feb4366190cb1d81389e7c54ac4f97cca9e..4a0f502da20dfdc94545a81c20dfa061ffef0008 100644
--- a/app/code/Magento/Checkout/Model/PaymentInformationManagement.php
+++ b/app/code/Magento/Checkout/Model/PaymentInformationManagement.php
@@ -14,6 +14,7 @@ class PaymentInformationManagement implements \Magento\Checkout\Api\PaymentInfor
 {
     /**
      * @var \Magento\Quote\Api\BillingAddressManagementInterface
+     * @deprecated This call was substituted to eliminate extra quote::save call
      */
     protected $billingAddressManagement;
 
@@ -42,6 +43,11 @@ class PaymentInformationManagement implements \Magento\Checkout\Api\PaymentInfor
      */
     private $logger;
 
+    /**
+     * @var \Magento\Quote\Api\CartRepositoryInterface
+     */
+    private $cartRepository;
+
     /**
      * @param \Magento\Quote\Api\BillingAddressManagementInterface $billingAddressManagement
      * @param \Magento\Quote\Api\PaymentMethodManagementInterface $paymentMethodManagement
@@ -99,7 +105,19 @@ class PaymentInformationManagement implements \Magento\Checkout\Api\PaymentInfor
         \Magento\Quote\Api\Data\AddressInterface $billingAddress = null
     ) {
         if ($billingAddress) {
-            $this->billingAddressManagement->assign($cartId, $billingAddress);
+            /** @var \Magento\Quote\Api\CartRepositoryInterface $quoteRepository */
+            $quoteRepository = $this->getCartRepository();
+            /** @var \Magento\Quote\Model\Quote $quote */
+            $quote = $quoteRepository->getActive($cartId);
+            $quote->removeAddress($quote->getBillingAddress()->getId());
+            $quote->setBillingAddress($billingAddress);
+            $quote->setDataChanges(true);
+            $shippingAddress = $quote->getShippingAddress();
+            if ($shippingAddress && $shippingAddress->getShippingMethod()) {
+                $shippingDataArray = explode('_', $shippingAddress->getShippingMethod());
+                $shippingCarrier = array_shift($shippingDataArray);
+                $shippingAddress->setLimitCarrier($shippingCarrier);
+            }
         }
         $this->paymentMethodManagement->set($cartId, $paymentMethod);
         return true;
@@ -130,4 +148,19 @@ class PaymentInformationManagement implements \Magento\Checkout\Api\PaymentInfor
         }
         return $this->logger;
     }
+
+    /**
+     * Get Cart repository
+     *
+     * @return \Magento\Quote\Api\CartRepositoryInterface
+     * @deprecated
+     */
+    private function getCartRepository()
+    {
+        if (!$this->cartRepository) {
+            $this->cartRepository = \Magento\Framework\App\ObjectManager::getInstance()
+                ->get(\Magento\Quote\Api\CartRepositoryInterface::class);
+        }
+        return $this->cartRepository;
+    }
 }
diff --git a/app/code/Magento/Checkout/Model/ShippingInformationManagement.php b/app/code/Magento/Checkout/Model/ShippingInformationManagement.php
index 237d28e2845e430493d1ba7f73b15160995c7c9c..1b4f8b8c64a864efefb03e56cd52aa8dbb41e304 100644
--- a/app/code/Magento/Checkout/Model/ShippingInformationManagement.php
+++ b/app/code/Magento/Checkout/Model/ShippingInformationManagement.php
@@ -144,6 +144,7 @@ class ShippingInformationManagement implements \Magento\Checkout\Api\ShippingInf
 
         /** @var \Magento\Quote\Model\Quote $quote */
         $quote = $this->quoteRepository->getActive($cartId);
+        $address->setLimitCarrier($carrierCode);
         $quote = $this->prepareShippingAssignment($quote, $address, $carrierCode . '_' . $methodCode);
         $this->validateQuote($quote);
         $quote->setIsMultiShipping(false);
diff --git a/app/code/Magento/Checkout/Test/Unit/Model/PaymentInformationManagementTest.php b/app/code/Magento/Checkout/Test/Unit/Model/PaymentInformationManagementTest.php
index 8da67a1fcb71512dd218a2c62d51b7922bb36c25..f256d8edefd1c9b2bd0dc41c838293cf4b9dfa32 100644
--- a/app/code/Magento/Checkout/Test/Unit/Model/PaymentInformationManagementTest.php
+++ b/app/code/Magento/Checkout/Test/Unit/Model/PaymentInformationManagementTest.php
@@ -5,8 +5,9 @@
  */
 namespace Magento\Checkout\Test\Unit\Model;
 
-use Magento\Framework\Exception\CouldNotSaveException;
-
+/**
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
 class PaymentInformationManagementTest extends \PHPUnit_Framework_TestCase
 {
     /**
@@ -34,6 +35,11 @@ class PaymentInformationManagementTest extends \PHPUnit_Framework_TestCase
      */
     private $loggerMock;
 
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $cartRepositoryMock;
+
     protected function setUp()
     {
         $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
@@ -46,7 +52,7 @@ class PaymentInformationManagementTest extends \PHPUnit_Framework_TestCase
         $this->cartManagementMock = $this->getMock(\Magento\Quote\Api\CartManagementInterface::class);
 
         $this->loggerMock = $this->getMock(\Psr\Log\LoggerInterface::class);
-
+        $this->cartRepositoryMock = $this->getMockBuilder(\Magento\Quote\Api\CartRepositoryInterface::class)->getMock();
         $this->model = $objectManager->getObject(
             \Magento\Checkout\Model\PaymentInformationManagement::class,
             [
@@ -56,6 +62,7 @@ class PaymentInformationManagementTest extends \PHPUnit_Framework_TestCase
             ]
         );
         $objectManager->setBackwardCompatibleProperty($this->model, 'logger', $this->loggerMock);
+        $objectManager->setBackwardCompatibleProperty($this->model, 'cartRepository', $this->cartRepositoryMock);
     }
 
     public function testSavePaymentInformationAndPlaceOrder()
@@ -65,9 +72,7 @@ class PaymentInformationManagementTest extends \PHPUnit_Framework_TestCase
         $paymentMock = $this->getMock(\Magento\Quote\Api\Data\PaymentInterface::class);
         $billingAddressMock = $this->getMock(\Magento\Quote\Api\Data\AddressInterface::class);
 
-        $this->billingAddressManagementMock->expects($this->once())
-            ->method('assign')
-            ->with($cartId, $billingAddressMock);
+        $this->getMockForAssignBillingAddress($cartId, $billingAddressMock);
         $this->paymentMethodManagementMock->expects($this->once())->method('set')->with($cartId, $paymentMock);
         $this->cartManagementMock->expects($this->once())->method('placeOrder')->with($cartId)->willReturn($orderId);
 
@@ -87,9 +92,7 @@ class PaymentInformationManagementTest extends \PHPUnit_Framework_TestCase
         $paymentMock = $this->getMock(\Magento\Quote\Api\Data\PaymentInterface::class);
         $billingAddressMock = $this->getMock(\Magento\Quote\Api\Data\AddressInterface::class);
 
-        $this->billingAddressManagementMock->expects($this->once())
-            ->method('assign')
-            ->with($cartId, $billingAddressMock);
+        $this->getMockForAssignBillingAddress($cartId, $billingAddressMock);
         $this->paymentMethodManagementMock->expects($this->once())->method('set')->with($cartId, $paymentMock);
         $exception = new \Exception(__('DB exception'));
         $this->loggerMock->expects($this->once())->method('critical');
@@ -104,7 +107,6 @@ class PaymentInformationManagementTest extends \PHPUnit_Framework_TestCase
         $orderId = 200;
         $paymentMock = $this->getMock(\Magento\Quote\Api\Data\PaymentInterface::class);
 
-        $this->billingAddressManagementMock->expects($this->never())->method('assign');
         $this->paymentMethodManagementMock->expects($this->once())->method('set')->with($cartId, $paymentMock);
         $this->cartManagementMock->expects($this->once())->method('placeOrder')->with($cartId)->willReturn($orderId);
 
@@ -120,9 +122,7 @@ class PaymentInformationManagementTest extends \PHPUnit_Framework_TestCase
         $paymentMock = $this->getMock(\Magento\Quote\Api\Data\PaymentInterface::class);
         $billingAddressMock = $this->getMock(\Magento\Quote\Api\Data\AddressInterface::class);
 
-        $this->billingAddressManagementMock->expects($this->once())
-            ->method('assign')
-            ->with($cartId, $billingAddressMock);
+        $this->getMockForAssignBillingAddress($cartId, $billingAddressMock);
         $this->paymentMethodManagementMock->expects($this->once())->method('set')->with($cartId, $paymentMock);
 
         $this->assertTrue($this->model->savePaymentInformation($cartId, $paymentMock, $billingAddressMock));
@@ -133,7 +133,6 @@ class PaymentInformationManagementTest extends \PHPUnit_Framework_TestCase
         $cartId = 100;
         $paymentMock = $this->getMock(\Magento\Quote\Api\Data\PaymentInterface::class);
 
-        $this->billingAddressManagementMock->expects($this->never())->method('assign');
         $this->paymentMethodManagementMock->expects($this->once())->method('set')->with($cartId, $paymentMock);
 
         $this->assertTrue($this->model->savePaymentInformation($cartId, $paymentMock));
@@ -149,9 +148,8 @@ class PaymentInformationManagementTest extends \PHPUnit_Framework_TestCase
         $paymentMock = $this->getMock(\Magento\Quote\Api\Data\PaymentInterface::class);
         $billingAddressMock = $this->getMock(\Magento\Quote\Api\Data\AddressInterface::class);
 
-        $this->billingAddressManagementMock->expects($this->once())
-            ->method('assign')
-            ->with($cartId, $billingAddressMock);
+        $this->getMockForAssignBillingAddress($cartId, $billingAddressMock);
+
         $this->paymentMethodManagementMock->expects($this->once())->method('set')->with($cartId, $paymentMock);
         $phrase = new \Magento\Framework\Phrase(__('DB exception'));
         $exception = new \Magento\Framework\Exception\LocalizedException($phrase);
@@ -160,4 +158,31 @@ class PaymentInformationManagementTest extends \PHPUnit_Framework_TestCase
 
         $this->model->savePaymentInformationAndPlaceOrder($cartId, $paymentMock, $billingAddressMock);
     }
+
+    /**
+     * @param int $cartId
+     * @param \PHPUnit_Framework_MockObject_MockObject $billingAddressMock
+     */
+    private function getMockForAssignBillingAddress($cartId, $billingAddressMock)
+    {
+        $billingAddressId = 1;
+        $quoteMock = $this->getMock(\Magento\Quote\Model\Quote::class, [], [], '', false);
+        $quoteBillingAddress = $this->getMock(\Magento\Quote\Model\Quote\Address::class, [], [], '', false);
+        $quoteShippingAddress = $this->getMock(
+            \Magento\Quote\Model\Quote\Address::class,
+            ['setLimitCarrier', 'getShippingMethod'],
+            [],
+            '',
+            false
+        );
+        $this->cartRepositoryMock->expects($this->any())->method('getActive')->with($cartId)->willReturn($quoteMock);
+        $quoteMock->expects($this->once())->method('getBillingAddress')->willReturn($quoteBillingAddress);
+        $quoteMock->expects($this->once())->method('getShippingAddress')->willReturn($quoteShippingAddress);
+        $quoteBillingAddress->expects($this->once())->method('getId')->willReturn($billingAddressId);
+        $quoteMock->expects($this->once())->method('removeAddress')->with($billingAddressId);
+        $quoteMock->expects($this->once())->method('setBillingAddress')->with($billingAddressMock);
+        $quoteMock->expects($this->once())->method('setDataChanges')->willReturnSelf();
+        $quoteShippingAddress->expects($this->any())->method('getShippingMethod')->willReturn('flatrate_flatrate');
+        $quoteShippingAddress->expects($this->once())->method('setLimitCarrier')->with('flatrate')->willReturnSelf();
+    }
 }
diff --git a/app/code/Magento/Checkout/Test/Unit/Model/ShippingInformationManagementTest.php b/app/code/Magento/Checkout/Test/Unit/Model/ShippingInformationManagementTest.php
index 402a0c8228356a7ae8a148d7626e06bb5dc15a27..751bcee6db2a9fd6e2d15405c57f899a2d7ad972 100644
--- a/app/code/Magento/Checkout/Test/Unit/Model/ShippingInformationManagementTest.php
+++ b/app/code/Magento/Checkout/Test/Unit/Model/ShippingInformationManagementTest.php
@@ -109,7 +109,8 @@ class ShippingInformationManagementTest extends \PHPUnit_Framework_TestCase
                 'importCustomerAddressData',
                 'save',
                 'getShippingRateByCode',
-                'getShippingMethod'
+                'getShippingMethod',
+                'setLimitCarrier'
             ],
             [],
             '',
@@ -208,7 +209,7 @@ class ShippingInformationManagementTest extends \PHPUnit_Framework_TestCase
     private function setShippingAssignmentsMocks($shippingMethod)
     {
         $this->quoteMock->expects($this->once())->method('getExtensionAttributes')->willReturn(null);
-
+        $this->shippingAddressMock->expects($this->once())->method('setLimitCarrier');
         $this->cartExtensionMock = $this->getMock(
             \Magento\Quote\Api\Data\CartExtension::class,
             ['getShippingAssignments', 'setShippingAssignments'],
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/CustomerManagement.php b/app/code/Magento/Quote/Model/CustomerManagement.php
index b796ebe9d0db4c0305c9e1d9c8e09838540ba820..04707e152674808b45c72c695861bd11b42cf13a 100644
--- a/app/code/Magento/Quote/Model/CustomerManagement.php
+++ b/app/code/Magento/Quote/Model/CustomerManagement.php
@@ -62,8 +62,6 @@ class CustomerManagement
                 $quote->getPasswordHash()
             );
             $quote->setCustomer($customer);
-        } else {
-            $this->customerRepository->save($customer);
         }
         if (!$quote->getBillingAddress()->getId() && $customer->getDefaultBilling()) {
             $quote->getBillingAddress()->importCustomerAddressData(
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/CustomerManagementTest.php b/app/code/Magento/Quote/Test/Unit/Model/CustomerManagementTest.php
index 600bf1723a5c091a7879c3c1eb706c261f197c18..a1caac3473ccb3a352af6be8e64e36c4c6061cf3 100644
--- a/app/code/Magento/Quote/Test/Unit/Model/CustomerManagementTest.php
+++ b/app/code/Magento/Quote/Test/Unit/Model/CustomerManagementTest.php
@@ -158,4 +158,34 @@ class CustomerManagementTest extends \PHPUnit_Framework_TestCase
             ->willReturn($this->customerMock);
         $this->customerManagement->populateCustomerInfo($this->quoteMock);
     }
+
+    public function testPopulateCustomerInfoForExistingCustomer()
+    {
+        $this->quoteMock->expects($this->once())
+            ->method('getCustomer')
+            ->willReturn($this->customerMock);
+        $this->customerMock->expects($this->atLeastOnce())
+            ->method('getId')
+            ->willReturn(1);
+        $this->customerMock->expects($this->atLeastOnce())
+            ->method('getDefaultBilling')
+            ->willReturn(100500);
+        $this->quoteMock->expects($this->atLeastOnce())
+            ->method('getBillingAddress')
+            ->willReturn($this->quoteAddressMock);
+        $this->quoteMock->expects($this->atLeastOnce())
+            ->method('getShippingAddress')
+            ->willReturn($this->quoteAddressMock);
+        $this->quoteAddressMock->expects($this->atLeastOnce())
+            ->method('getId')
+            ->willReturn(null);
+        $this->customerAddressRepositoryMock->expects($this->atLeastOnce())
+            ->method('getById')
+            ->with(100500)
+            ->willReturn($this->customerAddressMock);
+        $this->quoteAddressMock->expects($this->atLeastOnce())
+            ->method('importCustomerAddressData')
+            ->willReturnSelf();
+        $this->customerManagement->populateCustomerInfo($this->quoteMock);
+    }
 }
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/Ui/Model/Manager.php b/app/code/Magento/Ui/Model/Manager.php
index 348b7d398800d71bc763eecb719313b89f44252e..a2a4f05eb8bad7b2a4e379b552e245df9c00e13c 100644
--- a/app/code/Magento/Ui/Model/Manager.php
+++ b/app/code/Magento/Ui/Model/Manager.php
@@ -1,6 +1,6 @@
 <?php
 /**
- * Copyright © 2016 Magento. All rights reserved.
+ * Copyright © 2017 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
 namespace Magento\Ui\Model;
@@ -17,6 +17,8 @@ use Magento\Framework\View\Element\UiComponent\Config\ManagerInterface;
 use Magento\Framework\View\Element\UiComponent\Config\Provider\Component\Definition as ComponentDefinition;
 use Magento\Framework\View\Element\UiComponent\Config\ReaderFactory;
 use Magento\Framework\View\Element\UiComponent\Config\UiReaderInterface;
+use Magento\Framework\Serialize\SerializerInterface;
+use Magento\Framework\App\ObjectManager;
 
 /**
  * Class Manager
@@ -94,6 +96,11 @@ class Manager implements ManagerInterface
      */
     protected $uiReader;
 
+    /**
+     * @var SerializerInterface
+     */
+    private $serializer;
+
     /**
      * @param ComponentDefinition $componentConfigProvider
      * @param DomMergerInterface $domMerger
@@ -102,6 +109,7 @@ class Manager implements ManagerInterface
      * @param AggregatedFileCollectorFactory $aggregatedFileCollectorFactory
      * @param CacheInterface $cache
      * @param InterpreterInterface $argumentInterpreter
+     * @param SerializerInterface|null $serializer
      */
     public function __construct(
         ComponentDefinition $componentConfigProvider,
@@ -110,7 +118,8 @@ class Manager implements ManagerInterface
         ArrayObjectFactory $arrayObjectFactory,
         AggregatedFileCollectorFactory $aggregatedFileCollectorFactory,
         CacheInterface $cache,
-        InterpreterInterface $argumentInterpreter
+        InterpreterInterface $argumentInterpreter,
+        SerializerInterface $serializer = null
     ) {
         $this->componentConfigProvider = $componentConfigProvider;
         $this->domMerger = $domMerger;
@@ -120,6 +129,7 @@ class Manager implements ManagerInterface
         $this->aggregatedFileCollectorFactory = $aggregatedFileCollectorFactory;
         $this->cache = $cache;
         $this->argumentInterpreter = $argumentInterpreter;
+        $this->serializer = $serializer ?: ObjectManager::getInstance()->get(SerializerInterface::class);
     }
 
     /**
@@ -164,9 +174,14 @@ class Manager implements ManagerInterface
         $cachedPool = $this->cache->load($cacheID);
         if ($cachedPool === false) {
             $this->prepare($name);
-            $this->cache->save($this->componentsPool->serialize(), $cacheID);
+            $this->cache->save(
+                $this->serializer->serialize($this->componentsPool->getArrayCopy()),
+                $cacheID
+            );
         } else {
-            $this->componentsPool->unserialize($cachedPool);
+            $this->componentsPool->exchangeArray(
+                $this->serializer->unserialize($cachedPool)
+            );
         }
         $this->componentsData->offsetSet($name, $this->componentsPool);
         $this->componentsData->offsetSet($name, $this->evaluateComponentArguments($this->getData($name)));
diff --git a/app/code/Magento/Ui/Test/Unit/Model/ManagerTest.php b/app/code/Magento/Ui/Test/Unit/Model/ManagerTest.php
index 37f97af4597ac069312dbb1e1fb404e36cbdf12f..0e50950cc953eb4a24a2b36ff114a588b700d573 100644
--- a/app/code/Magento/Ui/Test/Unit/Model/ManagerTest.php
+++ b/app/code/Magento/Ui/Test/Unit/Model/ManagerTest.php
@@ -1,6 +1,6 @@
 <?php
 /**
- * Copyright © 2016 Magento. All rights reserved.
+ * Copyright © 2017 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
 
@@ -75,6 +75,9 @@ class ManagerTest extends \PHPUnit_Framework_TestCase
      */
     protected $aggregatedFileCollectorFactory;
 
+    /** @var \Magento\Framework\Serialize\SerializerInterface|\PHPUnit_Framework_MockObject_MockObject */
+    private $serializer;
+
     protected function setUp()
     {
         $this->componentConfigProvider = $this->getMockBuilder(
@@ -105,6 +108,24 @@ class ManagerTest extends \PHPUnit_Framework_TestCase
             ->getMockForAbstractClass();
         $this->argumentInterpreter = $this->getMockBuilder(\Magento\Framework\Data\Argument\InterpreterInterface::class)
             ->getMockForAbstractClass();
+        $this->serializer = $this->getMockBuilder(
+            \Magento\Framework\Serialize\SerializerInterface::class
+        )->getMockForAbstractClass();
+        $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->manager = new Manager(
             $this->componentConfigProvider,
             $this->domMerger,
@@ -112,7 +133,8 @@ class ManagerTest extends \PHPUnit_Framework_TestCase
             $this->arrayObjectFactory,
             $this->aggregatedFileCollectorFactory,
             $this->cacheConfig,
-            $this->argumentInterpreter
+            $this->argumentInterpreter,
+            $this->serializer
         );
     }
 
@@ -192,7 +214,7 @@ class ManagerTest extends \PHPUnit_Framework_TestCase
             [
                 'test_component1',
                 new \ArrayObject(),
-                $cachedData->serialize(),
+                json_encode($cachedData->getArrayCopy()),
                 [],
                 [
                     'test_component1' => [
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/functional/tests/app/Magento/Customer/Test/TestCase/RegisterCustomerFrontendEntityTest.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/RegisterCustomerFrontendEntityTest.xml
index 96e78f58d78c8402a133184b633614e4e4fd20c7..43b4a251edd1b5a97d68d458b7203bd4435d69e0 100644
--- a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/RegisterCustomerFrontendEntityTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/RegisterCustomerFrontendEntityTest.xml
@@ -32,7 +32,7 @@
             <constraint name="Magento\Newsletter\Test\Constraint\AssertCustomerIsSubscribedToNewsletter" />
         </variation>
         <variation name="RegisterCustomerFrontendEntityTestVariation3" summary="Register Customer" ticketId="MAGETWO-12394">
-            <data name="tag" xsi:type="string">test_type:acceptance_test, test_type:extended_acceptance_test</data>
+            <data name="tag" xsi:type="string">test_type:acceptance_test, test_type:extended_acceptance_test, stable:no</data>
             <data name="customer/data/firstname" xsi:type="string">john</data>
             <data name="customer/data/lastname" xsi:type="string">doe</data>
             <data name="customer/data/email" xsi:type="string">johndoe%isolation%@example.com</data>
diff --git a/dev/tests/integration/testsuite/Magento/Backend/Block/MenuTest.php b/dev/tests/integration/testsuite/Magento/Backend/Block/MenuTest.php
index f36c17889aa30145019690c3f2ad302780aa4dd1..c3988187c686d939206c045c4dd9a78d2422de6c 100644
--- a/dev/tests/integration/testsuite/Magento/Backend/Block/MenuTest.php
+++ b/dev/tests/integration/testsuite/Magento/Backend/Block/MenuTest.php
@@ -28,6 +28,11 @@ class MenuTest extends \PHPUnit_Framework_TestCase
      */
     protected $backupRegistrar;
 
+    /**
+     * @var \Magento\Backend\Model\Menu\Config
+     */
+    private $menuConfig;
+
     protected function setUp()
     {
         $this->configCacheType = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
@@ -35,15 +40,18 @@ class MenuTest extends \PHPUnit_Framework_TestCase
         );
         $this->configCacheType->save('', \Magento\Backend\Model\Menu\Config::CACHE_MENU_OBJECT);
 
-        $this->blockMenu = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
-            \Magento\Backend\Block\Menu::class
-        );
-
         $reflection = new \ReflectionClass(\Magento\Framework\Component\ComponentRegistrar::class);
         $paths = $reflection->getProperty('paths');
         $paths->setAccessible(true);
         $this->backupRegistrar = $paths->getValue();
         $paths->setAccessible(false);
+
+        $this->menuConfig = $this->prepareMenuConfig();
+
+        $this->blockMenu = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
+            \Magento\Backend\Block\Menu::class,
+            ['menuConfig' => $this->menuConfig]
+        );
     }
 
     /**
@@ -51,8 +59,7 @@ class MenuTest extends \PHPUnit_Framework_TestCase
      */
     public function testRenderNavigation()
     {
-        $menuConfig = $this->prepareMenuConfig();
-        $menuHtml = $this->blockMenu->renderNavigation($menuConfig->getMenu());
+        $menuHtml = $this->blockMenu->renderNavigation($this->menuConfig->getMenu());
         $menu = new \SimpleXMLElement($menuHtml);
 
         $item = $menu->xpath('/ul/li/a/span')[0];
diff --git a/dev/tests/integration/testsuite/Magento/Backend/Model/MenuTest.php b/dev/tests/integration/testsuite/Magento/Backend/Model/MenuTest.php
index f6fad14d210e9a2b2602014e353451b8f049c213..6c51e061f9db7af18ebf5629742c4edeb03771ca 100644
--- a/dev/tests/integration/testsuite/Magento/Backend/Model/MenuTest.php
+++ b/dev/tests/integration/testsuite/Magento/Backend/Model/MenuTest.php
@@ -15,30 +15,28 @@ class MenuTest extends \PHPUnit_Framework_TestCase
     /**
      * @var \Magento\Backend\Model\Menu
      */
-    protected $_model;
+    private $model;
+
+    /** @var \Magento\Framework\ObjectManagerInterface */
+    private $objectManager;
 
     protected function setUp()
     {
         parent::setUp();
         \Magento\TestFramework\Helper\Bootstrap::getInstance()
             ->loadArea(\Magento\Backend\App\Area\FrontNameResolver::AREA_CODE);
-        $this->_model = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()
-            ->create(\Magento\Backend\Model\Auth::class);
-        \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(
-            \Magento\Framework\Config\ScopeInterface::class
-        )->setCurrentScope(\Magento\Backend\App\Area\FrontNameResolver::AREA_CODE);
+        $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
+        $this->model = $this->objectManager->create(\Magento\Backend\Model\Auth::class);
+        $this->objectManager->get(\Magento\Framework\Config\ScopeInterface::class)
+            ->setCurrentScope(\Magento\Backend\App\Area\FrontNameResolver::AREA_CODE);
     }
 
     public function testMenuItemManipulation()
     {
         /* @var $menu \Magento\Backend\Model\Menu */
-        $menu = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(
-            \Magento\Backend\Model\Menu\Config::class
-        )->getMenu();
+        $menu = $this->objectManager->create(\Magento\Backend\Model\Menu\Config::class)->getMenu();
         /* @var $itemFactory \Magento\Backend\Model\Menu\Item\Factory */
-        $itemFactory = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
-            \Magento\Backend\Model\Menu\Item\Factory::class
-        );
+        $itemFactory = $this->objectManager->create(\Magento\Backend\Model\Menu\Item\Factory::class);
 
         // Add new item in top level
         $menu->add(
@@ -52,7 +50,7 @@ class MenuTest extends \PHPUnit_Framework_TestCase
             )
         );
 
-        //Add submenu
+        // Add submenu
         $menu->add(
             $itemFactory->create(
                 [
@@ -79,4 +77,100 @@ class MenuTest extends \PHPUnit_Framework_TestCase
         // Move menu item
         $menu->move('Magento_Catalog::catalog_products', 'Magento_Backend::system2');
     }
+
+    /**
+     * @magentoAppIsolation enabled
+     */
+    public function testSerialize()
+    {
+        /** @var Menu $menu */
+        $menu = $this->objectManager->get(\Magento\Backend\Model\MenuFactory::class)->create();
+        /* @var \Magento\Backend\Model\Menu\Item\Factory $itemFactory */
+        $itemFactory = $this->objectManager->create(\Magento\Backend\Model\Menu\Item\Factory::class);
+
+        // Add new item in top level
+        $menu->add(
+            $itemFactory->create(
+                [
+                    'id' => 'Magento_Backend::system3',
+                    'title' => 'Extended System',
+                    'module' => 'Magento_Backend',
+                    'resource' => 'Magento_Backend::system3',
+                ]
+            )
+        );
+
+        // Add submenu
+        $menu->add(
+            $itemFactory->create(
+                [
+                    'id' => 'Magento_Backend::system3_acl',
+                    'title' => 'Acl',
+                    'module' => 'Magento_Backend',
+                    'action' => 'admin/backend/acl/index',
+                    'resource' => 'Magento_Backend::system3_acl',
+                ]
+            ),
+            'Magento_Backend::system3'
+        );
+        $serializedString = $menu->serialize();
+        $expected = '[{"parent_id":null,"module_name":"Magento_Backend","sort_index":null,"depends_on_config":null,'
+            . '"id":"Magento_Backend::system3","resource":"Magento_Backend::system3","path":"","action":null,'
+            . '"depends_on_module":null,"tooltip":"","title":"Extended System",'
+            . '"sub_menu":[{"parent_id":null,"module_name":"Magento_Backend","sort_index":null,'
+            . '"depends_on_config":null,"id":"Magento_Backend::system3_acl","resource":"Magento_Backend::system3_acl",'
+            . '"path":"","action":"admin\/backend\/acl\/index","depends_on_module":null,"tooltip":"","title":"Acl",'
+            . '"sub_menu":null}]}]';
+        $this->assertEquals($expected, $serializedString);
+    }
+
+    /**
+     * @magentoAppIsolation enabled
+     */
+    public function testUnserialize()
+    {
+        $serializedMenu = '[{"parent_id":null,"module_name":"Magento_Backend","sort_index":null,'
+            . '"depends_on_config":null,"id":"Magento_Backend::system3","resource":"Magento_Backend::system3",'
+            . '"path":"","action":null,"depends_on_module":null,"tooltip":"","title":"Extended System",'
+            . '"sub_menu":[{"parent_id":null,"module_name":"Magento_Backend","sort_index":null,'
+            . '"depends_on_config":null,"id":"Magento_Backend::system3_acl","resource":"Magento_Backend::system3_acl",'
+            . '"path":"","action":"admin\/backend\/acl\/index","depends_on_module":null,"tooltip":"","title":"Acl",'
+            . '"sub_menu":null}]}]';
+        /** @var Menu $menu */
+        $menu = $this->objectManager->get(\Magento\Backend\Model\MenuFactory::class)->create();
+        $menu->unserialize($serializedMenu);
+        $expected = [
+            [
+                'parent_id' => null,
+                'module_name' => 'Magento_Backend',
+                'sort_index' => null,
+                'depends_on_config' => null,
+                'id' => 'Magento_Backend::system3',
+                'resource' => 'Magento_Backend::system3',
+                'path' => '',
+                'action' => null,
+                'depends_on_module' => null,
+                'tooltip' => '',
+                'title' => 'Extended System',
+                'sub_menu' =>
+                    [
+                        [
+                            'parent_id' => null,
+                            'module_name' => 'Magento_Backend',
+                            'sort_index' => null,
+                            'depends_on_config' => null,
+                            'id' => 'Magento_Backend::system3_acl',
+                            'resource' => 'Magento_Backend::system3_acl',
+                            'path' => '',
+                            'action' => 'admin/backend/acl/index',
+                            'depends_on_module' => null,
+                            'tooltip' => '',
+                            'title' => 'Acl',
+                            'sub_menu' => null,
+                        ],
+                    ],
+            ],
+        ];
+        $this->assertEquals($expected, $menu->toArray());
+    }
 }
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/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/ko/bind/datepicker.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/ko/bind/datepicker.test.js
index e5f90863ec63071f191b82b0df7fdbba0ac411fa..3e99c1c454cf4b2261d99e3623f365570684a1e3 100644
--- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/ko/bind/datepicker.test.js
+++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/ko/bind/datepicker.test.js
@@ -1,5 +1,5 @@
 /**
- * Copyright © 2016 Magento. All rights reserved.
+ * Copyright © 2017 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
 
@@ -18,21 +18,23 @@ define([
             config;
 
         beforeEach(function () {
-            element    = $('<input />');
+            element = $('<input />');
             observable = ko.observable();
 
             config = {
-                options : {
+                options: {
                     dateFormat: 'M/d/yy',
-                    'storeLocale': 'en_US',
-                    'timeFormat': 'h:mm: a'
+                    storeLocale: 'en_US',
+                    timeFormat: 'h:mm: a'
                 },
-                storage:ko.observable(moment().format('MM/DD/YYYY'))
+                storage: observable
             };
 
             $(document.body).append(element);
 
-            ko.applyBindingsToNode(element[0], { datepicker: config });
+            ko.applyBindingsToNode(element[0], {
+                datepicker: config
+            });
         });
 
         afterEach(function () {
@@ -40,20 +42,16 @@ define([
         });
 
         it('writes picked date\'s value to assigned observable', function () {
-            var todayDate,
-                momentFormat,
-                result,
-                inputFormat;
-
-            inputFormat = 'M/d/yy';
+            var todayDate, momentFormat, result,
+                inputFormat = 'M/d/yy';
 
             momentFormat = utils.convertToMomentFormat(inputFormat);
+            todayDate = moment().format(momentFormat);
 
-            todayDate   = moment().format(momentFormat);
-
-            result = $('input:last').val();
+            element.datepicker('setTimezoneDate').blur().trigger('change');
+            result = moment(observable()).format(momentFormat);
 
             expect(todayDate).toEqual(result);
         });
     });
-});
\ No newline at end of file
+});
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/App/Http/Context.php b/lib/internal/Magento/Framework/App/Http/Context.php
index 4146dac725f03a70971e85d6a29b27803e795412..59ab6f7602c3f4cc3369584ff5fa09f9629fae6e 100644
--- a/lib/internal/Magento/Framework/App/Http/Context.php
+++ b/lib/internal/Magento/Framework/App/Http/Context.php
@@ -1,6 +1,6 @@
 <?php
 /**
- * Copyright © 2016 Magento. All rights reserved.
+ * Copyright © 2017 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
 namespace Magento\Framework\App\Http;
@@ -27,6 +27,16 @@ class Context
      */
     protected $default = [];
 
+    /**
+     * @param array $data
+     * @param array $default
+     */
+    public function __construct(array $data = [], array $default = [])
+    {
+        $this->data = $data;
+        $this->default = $default;
+    }
+
     /**
      * Data setter
      *
@@ -99,4 +109,17 @@ class Context
         }
         return null;
     }
+
+    /**
+     * Get data and default data in "key-value" format
+     *
+     * @return array
+     */
+    public function toArray()
+    {
+        return [
+            'data' => $this->data,
+            'default' => $this->default
+        ];
+    }
 }
diff --git a/lib/internal/Magento/Framework/App/PageCache/Kernel.php b/lib/internal/Magento/Framework/App/PageCache/Kernel.php
index 8a83592bc322e86c046b68480f815878f3de8855..02d6646c67d0f76ee4a527bf29e7d0f165a8f822 100644
--- a/lib/internal/Magento/Framework/App/PageCache/Kernel.php
+++ b/lib/internal/Magento/Framework/App/PageCache/Kernel.php
@@ -1,12 +1,10 @@
 <?php
 /**
- * Copyright © 2016 Magento. All rights reserved.
+ * Copyright © 2017 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
 namespace Magento\Framework\App\PageCache;
 
-use Magento\Framework\App\ObjectManager;
-
 /**
  * Builtin cache processor
  */
@@ -34,19 +32,76 @@ class Kernel
      */
     private $fullPageCache;
 
+    /**
+     * @var \Magento\Framework\Serialize\SerializerInterface
+     */
+    private $serializer;
+
+    /**
+     * @var \Magento\Framework\App\Http\Context
+     */
+    private $context;
+
+    /**
+     * @var \Magento\Framework\App\Http\ContextFactory
+     */
+    private $contextFactory;
+
+    /**
+     * @var \Magento\Framework\App\Response\HttpFactory
+     */
+    private $httpFactory;
+
     /**
      * @param Cache $cache
      * @param Identifier $identifier
      * @param \Magento\Framework\App\Request\Http $request
+     * @param \Magento\Framework\App\Http\Context|null $context
+     * @param \Magento\Framework\App\Http\ContextFactory|null $contextFactory
+     * @param \Magento\Framework\App\Response\HttpFactory|null $httpFactory
+     * @param \Magento\Framework\Serialize\SerializerInterface|null $serializer
      */
     public function __construct(
         \Magento\Framework\App\PageCache\Cache $cache,
         \Magento\Framework\App\PageCache\Identifier $identifier,
-        \Magento\Framework\App\Request\Http $request
+        \Magento\Framework\App\Request\Http $request,
+        \Magento\Framework\App\Http\Context $context = null,
+        \Magento\Framework\App\Http\ContextFactory $contextFactory = null,
+        \Magento\Framework\App\Response\HttpFactory $httpFactory = null,
+        \Magento\Framework\Serialize\SerializerInterface $serializer = null
     ) {
         $this->cache = $cache;
         $this->identifier = $identifier;
         $this->request = $request;
+
+        if ($context) {
+            $this->context = $context;
+        } else {
+            $this->context = \Magento\Framework\App\ObjectManager::getInstance()->get(
+                \Magento\Framework\App\Http\Context::class
+            );
+        }
+        if ($contextFactory) {
+            $this->contextFactory = $contextFactory;
+        } else {
+            $this->contextFactory = \Magento\Framework\App\ObjectManager::getInstance()->get(
+                \Magento\Framework\App\Http\ContextFactory::class
+            );
+        }
+        if ($httpFactory) {
+            $this->httpFactory = $httpFactory;
+        } else {
+            $this->httpFactory = \Magento\Framework\App\ObjectManager::getInstance()->get(
+                \Magento\Framework\App\Response\HttpFactory::class
+            );
+        }
+        if ($serializer) {
+            $this->serializer = $serializer;
+        } else {
+            $this->serializer = \Magento\Framework\App\ObjectManager::getInstance()->get(
+                \Magento\Framework\Serialize\SerializerInterface::class
+            );
+        }
     }
 
     /**
@@ -57,7 +112,12 @@ class Kernel
     public function load()
     {
         if ($this->request->isGet() || $this->request->isHead()) {
-            return unserialize($this->getCache()->load($this->identifier->getValue()));
+            $responseData = $this->serializer->unserialize($this->getCache()->load($this->identifier->getValue()));
+            if (!$responseData) {
+                return false;
+            }
+
+            return $this->buildResponse($responseData);
         }
         return false;
     }
@@ -84,11 +144,63 @@ class Kernel
                 if (!headers_sent()) {
                     header_remove('Set-Cookie');
                 }
-                $this->getCache()->save(serialize($response), $this->identifier->getValue(), $tags, $maxAge);
+
+                $this->getCache()->save(
+                    $this->serializer->serialize($this->getPreparedData($response)),
+                    $this->identifier->getValue(),
+                    $tags,
+                    $maxAge
+                );
             }
         }
     }
 
+    /**
+     * Get prepared data for storage in the cache.
+     *
+     * @param \Magento\Framework\App\Response\Http $response
+     * @return array
+     */
+    private function getPreparedData(\Magento\Framework\App\Response\Http $response)
+    {
+        return [
+            'content' => $response->getContent(),
+            'status_code' => $response->getStatusCode(),
+            'headers' => $response->getHeaders()->toArray(),
+            'context' => $this->context->toArray()
+        ];
+
+    }
+
+    /**
+     * Build response using response data.
+     *
+     * @param array $responseData
+     * @return \Magento\Framework\App\Response\Http
+     */
+    private function buildResponse($responseData)
+    {
+        $context = $this->contextFactory->create(
+            [
+                'data' => $responseData['context']['data'],
+                'default' => $responseData['context']['default']
+            ]
+        );
+
+        $response = $this->httpFactory->create(
+            [
+                'context' => $context
+            ]
+        );
+        $response->setStatusCode($responseData['status_code']);
+        $response->setContent($responseData['content']);
+        foreach ($responseData['headers'] as $headerKey => $headerValue) {
+            $response->setHeader($headerKey, $headerValue, true);
+        }
+
+        return $response;
+    }
+
     /**
      * TODO: Workaround to support backwards compatibility, will rework to use Dependency Injection in MAGETWO-49547
      *
@@ -97,7 +209,9 @@ class Kernel
     private function getCache()
     {
         if (!$this->fullPageCache) {
-            $this->fullPageCache = ObjectManager::getInstance()->get(\Magento\PageCache\Model\Cache\Type::class);
+            $this->fullPageCache = \Magento\Framework\App\ObjectManager::getInstance()->get(
+                \Magento\PageCache\Model\Cache\Type::class
+            );
         }
         return $this->fullPageCache;
     }
diff --git a/lib/internal/Magento/Framework/App/Test/Unit/Http/ContextTest.php b/lib/internal/Magento/Framework/App/Test/Unit/Http/ContextTest.php
index 05f589e0dc61a9299f717aeab0905f8b205fdafe..8ce4f006861e8d3cc518df48a0882cda22a15b14 100644
--- a/lib/internal/Magento/Framework/App/Test/Unit/Http/ContextTest.php
+++ b/lib/internal/Magento/Framework/App/Test/Unit/Http/ContextTest.php
@@ -1,6 +1,6 @@
 <?php
 /**
- * Copyright © 2016 Magento. All rights reserved.
+ * Copyright © 2017 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
 
@@ -64,4 +64,19 @@ class ContextTest extends \PHPUnit_Framework_TestCase
         ksort($data);
         $this->assertEquals(sha1(serialize($data)), $this->object->getVaryString());
     }
+
+    public function testToArray()
+    {
+        $newObject = new \Magento\Framework\App\Http\Context(['key' => 'value']);
+
+        $newObject->setValue('key1', 'value1', 'default1');
+        $newObject->setValue('key2', 'value2', 'default2');
+        $this->assertEquals(
+            [
+                'data' => ['key' => 'value', 'key1' => 'value1', 'key2' => 'value2'],
+                'default' => ['key1' => 'default1', 'key2' => 'default2']
+            ],
+            $newObject->toArray()
+        );
+    }
 }
diff --git a/lib/internal/Magento/Framework/App/Test/Unit/PageCache/KernelTest.php b/lib/internal/Magento/Framework/App/Test/Unit/PageCache/KernelTest.php
index 81b828b3f938c45333a5ac8b096d8b23d013a81a..7e65b174abdd97a3adc231b415c96a62f634e194 100644
--- a/lib/internal/Magento/Framework/App/Test/Unit/PageCache/KernelTest.php
+++ b/lib/internal/Magento/Framework/App/Test/Unit/PageCache/KernelTest.php
@@ -1,12 +1,17 @@
 <?php
 /**
- * Copyright © 2016 Magento. All rights reserved.
+ * Copyright © 2017 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
 namespace Magento\Framework\App\Test\Unit\PageCache;
 
 use \Magento\Framework\App\PageCache\Kernel;
+use \Magento\Framework\App\Http\ContextFactory;
+use \Magento\Framework\App\Response\HttpFactory;
 
+/**
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
 class KernelTest extends \PHPUnit_Framework_TestCase
 {
     /** @var Kernel */
@@ -27,39 +32,136 @@ class KernelTest extends \PHPUnit_Framework_TestCase
     /** @var  \PHPUnit_Framework_MockObject_MockObject|\Magento\PageCache\Model\Cache\Type */
     private $fullPageCacheMock;
 
+    /** @var \Magento\Framework\App\Response\Http|\PHPUnit_Framework_MockObject_MockObject */
+    private $httpResponseMock;
+
+    /** @var ContextFactory|\PHPUnit_Framework_MockObject_MockObject */
+    private $contextFactoryMock;
+
+    /** @var HttpFactory|\PHPUnit_Framework_MockObject_MockObject */
+    private $httpFactoryMock;
+
+    /** @var \Magento\Framework\Serialize\SerializerInterface|\PHPUnit_Framework_MockObject_MockObject */
+    private $serializer;
+
+    /** @var \Magento\Framework\App\Http\Context|\PHPUnit_Framework_MockObject_MockObject */
+    private $contextMock;
+
     /**
      * Setup
      */
     protected function setUp()
     {
+        $headersMock = $this->getMock(\Zend\Http\Headers::class, [], [], '', false);
         $this->cacheMock = $this->getMock(\Magento\Framework\App\PageCache\Cache::class, [], [], '', false);
         $this->fullPageCacheMock = $this->getMock(\Magento\PageCache\Model\Cache\Type::class, [], [], '', false);
-        $this->identifierMock =
-            $this->getMock(\Magento\Framework\App\PageCache\Identifier::class, [], [], '', false);
+        $this->contextMock = $this->getMock(\Magento\Framework\App\Http\Context::class, [], [], '', false);
+        $this->httpResponseMock = $this->getMock(\Magento\Framework\App\Response\Http::class, [], [], '', false);
+        $this->identifierMock = $this->getMock(\Magento\Framework\App\PageCache\Identifier::class, [], [], '', false);
         $this->requestMock = $this->getMock(\Magento\Framework\App\Request\Http::class, [], [], '', false);
-        $this->kernel = new Kernel($this->cacheMock, $this->identifierMock, $this->requestMock);
+        $this->serializer = $this->getMock(\Magento\Framework\Serialize\SerializerInterface::class, [], [], '', false);
+        $this->responseMock = $this->getMock(\Magento\Framework\App\Response\Http::class, [], [], '', false);
+        $this->contextFactoryMock = $this->getMock(ContextFactory::class, ['create'], [], '', false);
+        $this->httpFactoryMock = $this->getMock(HttpFactory::class, ['create'], [], '', false);
+        $this->responseMock->expects($this->any())->method('getHeaders')->willReturn($headersMock);
+
+        $this->kernel = new Kernel(
+            $this->cacheMock,
+            $this->identifierMock,
+            $this->requestMock,
+            $this->contextMock,
+            $this->contextFactoryMock,
+            $this->httpFactoryMock,
+            $this->serializer
+        );
 
         $reflection = new \ReflectionClass(\Magento\Framework\App\PageCache\Kernel::class);
         $reflectionProperty = $reflection->getProperty('fullPageCache');
         $reflectionProperty->setAccessible(true);
         $reflectionProperty->setValue($this->kernel, $this->fullPageCacheMock);
+    }
 
-        $this->responseMock = $this->getMockBuilder(
-            \Magento\Framework\App\Response\Http::class
-        )->setMethods(
-            ['getHeader', 'getHttpResponseCode', 'setNoCacheHeaders', 'clearHeader', '__wakeup']
-        )->disableOriginalConstructor()->getMock();
+    /**
+     * @dataProvider dataProviderForResultWithCachedData
+     * @param string $id
+     * @param mixed $cache
+     * @param bool $isGet
+     * @param bool $isHead
+     */
+    public function testLoadWithCachedData($id, $cache, $isGet, $isHead)
+    {
+        $this->serializer->expects($this->once())
+            ->method('unserialize')
+            ->willReturnCallback(
+                function ($value) {
+                    return json_decode($value, true);
+                }
+            );
+
+        $this->contextFactoryMock
+            ->expects($this->once())
+            ->method('create')
+            ->with(
+                [
+                    'data' => ['context_data'],
+                    'default' => ['context_default_data']
+                ]
+            )
+            ->willReturn($this->contextMock);
+
+        $this->httpFactoryMock
+            ->expects($this->once())
+            ->method('create')
+            ->with(['context' => $this->contextMock])
+            ->willReturn($this->httpResponseMock);
+
+        $this->requestMock->expects($this->once())->method('isGet')->will($this->returnValue($isGet));
+        $this->requestMock->expects($this->any())->method('isHead')->will($this->returnValue($isHead));
+        $this->fullPageCacheMock->expects(
+            $this->any()
+        )->method(
+            'load'
+        )->with(
+            $this->equalTo($id)
+        )->will(
+            $this->returnValue(json_encode($cache))
+        );
+        $this->httpResponseMock->expects($this->once())->method('setStatusCode')->with($cache['status_code']);
+        $this->httpResponseMock->expects($this->once())->method('setContent')->with($cache['content']);
+        $this->httpResponseMock->expects($this->once())->method('setHeader')->with(0, 'header', true);
+        $this->identifierMock->expects($this->any())->method('getValue')->will($this->returnValue($id));
+        $this->assertEquals($this->httpResponseMock, $this->kernel->load());
+    }
+
+    /**
+     * @return array
+     */
+    public function dataProviderForResultWithCachedData()
+    {
+        $data = [
+            'context' => [
+                'data' => ['context_data'],
+                'default' => ['context_default_data']
+            ],
+            'status_code' => 'status_code',
+            'content' => 'content',
+            'headers' => ['header']
+        ];
+
+        return [
+            ['existing key', $data, true, false],
+            ['existing key', $data, false, true],
+        ];
     }
 
     /**
-     * @dataProvider loadProvider
-     * @param mixed $expected
+     * @dataProvider dataProviderForResultWithoutCachedData
      * @param string $id
      * @param mixed $cache
      * @param bool $isGet
      * @param bool $isHead
      */
-    public function testLoad($expected, $id, $cache, $isGet, $isHead)
+    public function testLoadWithoutCachedData($id, $cache, $isGet, $isHead)
     {
         $this->requestMock->expects($this->once())->method('isGet')->will($this->returnValue($isGet));
         $this->requestMock->expects($this->any())->method('isHead')->will($this->returnValue($isHead));
@@ -70,31 +172,21 @@ class KernelTest extends \PHPUnit_Framework_TestCase
         )->with(
             $this->equalTo($id)
         )->will(
-            $this->returnValue(serialize($cache))
+            $this->returnValue(json_encode($cache))
         );
         $this->identifierMock->expects($this->any())->method('getValue')->will($this->returnValue($id));
-        $this->assertEquals($expected, $this->kernel->load());
+        $this->assertEquals(false, $this->kernel->load());
     }
 
     /**
      * @return array
      */
-    public function loadProvider()
+    public function dataProviderForResultWithoutCachedData()
     {
-        $data = [1, 2, 3];
         return [
-            [$data, 'existing key', $data, true, false],
-            [$data, 'existing key', $data, false, true],
-            [
-                new \Magento\Framework\DataObject($data),
-                'existing key',
-                new \Magento\Framework\DataObject($data),
-                true,
-                false
-            ],
-            [false, 'existing key', $data, false, false],
-            [false, 'non existing key', false, true, false],
-            [false, 'non existing key', false, false, false]
+            ['existing key', [], false, false],
+            ['non existing key', false, true, false],
+            ['non existing key', false, false, false]
         ];
     }
 
@@ -104,6 +196,14 @@ class KernelTest extends \PHPUnit_Framework_TestCase
      */
     public function testProcessSaveCache($httpCode, $at)
     {
+        $this->serializer->expects($this->once())
+            ->method('serialize')
+            ->willReturnCallback(
+                function ($value) {
+                    return json_encode($value);
+                }
+            );
+
         $cacheControlHeader = \Zend\Http\Header\CacheControl::fromString(
             'Cache-Control: public, max-age=100, s-maxage=100'
         );
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();
     }
 }
diff --git a/lib/internal/Magento/Framework/View/Layout.php b/lib/internal/Magento/Framework/View/Layout.php
index 3334967c8da8327cb1de7eb396fb46978fc0c08c..ac3938c94c5c7432ba8095ea98c29162afb8b954 100755
--- a/lib/internal/Magento/Framework/View/Layout.php
+++ b/lib/internal/Magento/Framework/View/Layout.php
@@ -1,6 +1,6 @@
 <?php
 /**
- * Copyright © 2016 Magento. All rights reserved.
+ * Copyright © 2017 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
 namespace Magento\Framework\View;
@@ -8,11 +8,13 @@ namespace Magento\Framework\View;
 use Magento\Framework\Cache\FrontendInterface;
 use Magento\Framework\Event\ManagerInterface;
 use Magento\Framework\Message\ManagerInterface as MessageManagerInterface;
+use Magento\Framework\Serialize\SerializerInterface;
 use Magento\Framework\View\Layout\Element;
 use Magento\Framework\View\Layout\ScheduledStructure;
 use Magento\Framework\App\State as AppState;
 use Psr\Log\LoggerInterface as Logger;
 use Magento\Framework\Exception\LocalizedException;
+use Magento\Framework\App\ObjectManager;
 
 /**
  * Layout model
@@ -165,6 +167,11 @@ class Layout extends \Magento\Framework\Simplexml\Config implements \Magento\Fra
      */
     protected $logger;
 
+    /**
+     * @var SerializerInterface
+     */
+    private $serializer;
+
     /**
      * @param Layout\ProcessorFactory $processorFactory
      * @param ManagerInterface $eventManager
@@ -179,6 +186,7 @@ class Layout extends \Magento\Framework\Simplexml\Config implements \Magento\Fra
      * @param \Magento\Framework\App\State $appState
      * @param \Psr\Log\LoggerInterface $logger
      * @param bool $cacheable
+     * @param SerializerInterface|null $serializer
      */
     public function __construct(
         Layout\ProcessorFactory $processorFactory,
@@ -193,10 +201,12 @@ class Layout extends \Magento\Framework\Simplexml\Config implements \Magento\Fra
         Layout\Generator\ContextFactory $generatorContextFactory,
         AppState $appState,
         Logger $logger,
-        $cacheable = true
+        $cacheable = true,
+        SerializerInterface $serializer = null
     ) {
         $this->_elementClass = \Magento\Framework\View\Layout\Element::class;
         $this->_renderingOutput = new \Magento\Framework\DataObject();
+        $this->serializer = $serializer ?: ObjectManager::getInstance()->get(SerializerInterface::class);
 
         $this->_processorFactory = $processorFactory;
         $this->_eventManager = $eventManager;
@@ -308,12 +318,19 @@ class Layout extends \Magento\Framework\Simplexml\Config implements \Magento\Fra
         $cacheId = 'structure_' . $this->getUpdate()->getCacheId();
         $result = $this->cache->load($cacheId);
         if ($result) {
-            $this->readerContext = unserialize($result);
+            $data = $this->serializer->unserialize($result);
+            $this->getReaderContext()->getPageConfigStructure()->populateWithArray($data['pageConfigStructure']);
+            $this->getReaderContext()->getScheduledStructure()->populateWithArray($data['scheduledStructure']);
         } else {
             \Magento\Framework\Profiler::start('build_structure');
             $this->readerPool->interpret($this->getReaderContext(), $this->getNode());
             \Magento\Framework\Profiler::stop('build_structure');
-            $this->cache->save(serialize($this->getReaderContext()), $cacheId, $this->getUpdate()->getHandles());
+
+            $data = [
+                'pageConfigStructure' => $this->getReaderContext()->getPageConfigStructure()->__toArray(),
+                'scheduledStructure'  => $this->getReaderContext()->getScheduledStructure()->__toArray(),
+            ];
+            $this->cache->save($this->serializer->serialize($data), $cacheId, $this->getUpdate()->getHandles());
         }
 
         $generatorContext = $this->generatorContextFactory->create(
diff --git a/lib/internal/Magento/Framework/View/Layout/ScheduledStructure.php b/lib/internal/Magento/Framework/View/Layout/ScheduledStructure.php
index cf1981335d6be9a6b12b38944623d727abe6fdeb..117fb8278145f89f22674b7ab25d21fab57946ff 100644
--- a/lib/internal/Magento/Framework/View/Layout/ScheduledStructure.php
+++ b/lib/internal/Magento/Framework/View/Layout/ScheduledStructure.php
@@ -1,6 +1,6 @@
 <?php
 /**
- * Copyright © 2016 Magento. All rights reserved.
+ * Copyright © 2017 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
 namespace Magento\Framework\View\Layout;
@@ -19,6 +19,23 @@ class ScheduledStructure
     const ELEMENT_IS_AFTER = 'isAfter';
     /**#@-*/
 
+    /**
+     * Map of class properties.
+     *
+     * @var array
+     */
+    private $serializableProperties = [
+        'scheduledStructure',
+        'scheduledData',
+        'scheduledElements',
+        'scheduledMoves',
+        'scheduledRemoves',
+        'scheduledIfconfig',
+        'scheduledPaths',
+        'elementsToSort',
+        'brokenParent',
+    ];
+
     /**
      * Information about structural elements, scheduled for creation
      *
@@ -84,18 +101,10 @@ class ScheduledStructure
 
     /**
      * @param array $data
-     *
-     * @SuppressWarnings(PHPMD.NPathComplexity)
      */
     public function __construct(array $data = [])
     {
-        $this->scheduledStructure = isset($data['scheduledStructure']) ? $data['scheduledStructure'] : [];
-        $this->scheduledData = isset($data['scheduledData']) ? $data['scheduledData'] : [];
-        $this->scheduledElements = isset($data['scheduledElements']) ? $data['scheduledElements'] : [];
-        $this->scheduledMoves = isset($data['scheduledMoves']) ? $data['scheduledMoves'] : [];
-        $this->scheduledRemoves = isset($data['scheduledRemoves']) ? $data['scheduledRemoves'] : [];
-        $this->scheduledIfconfig = isset($data['scheduledIfconfig']) ? $data['scheduledIfconfig'] : [];
-        $this->scheduledPaths = isset($data['scheduledPaths']) ? $data['scheduledPaths'] : [];
+        $this->populateWithArray($data);
     }
 
     /**
@@ -531,4 +540,44 @@ class ScheduledStructure
         $this->scheduledElements = [];
         $this->scheduledStructure = [];
     }
+
+    /**
+     * Reformat 'Layout scheduled structure' to array.
+     *
+     * @return array
+     */
+    public function __toArray()
+    {
+        $result = [];
+        foreach ($this->serializableProperties as $property) {
+            $result[$property] = $this->{$property};
+        }
+
+        return $result;
+    }
+
+    /**
+     * Update 'Layout scheduled structure' data.
+     *
+     * @param array $data
+     * @return void
+     */
+    public function populateWithArray(array $data)
+    {
+        foreach ($this->serializableProperties as $property) {
+            $this->{$property} = $this->getArrayValueByKey($property, $data);
+        }
+    }
+
+    /**
+     * Get value from array by key.
+     *
+     * @param string $key
+     * @param array $array
+     * @return array
+     */
+    private function getArrayValueByKey($key, array $array)
+    {
+        return isset($array[$key]) ? $array[$key] : [];
+    }
 }
diff --git a/lib/internal/Magento/Framework/View/Page/Config/Structure.php b/lib/internal/Magento/Framework/View/Page/Config/Structure.php
index 4ab89319f6d82aeeaad6e637076ed7e181fab2d4..d7fe402044e8ffd589e2669eb0c0611cdb4b7f61 100644
--- a/lib/internal/Magento/Framework/View/Page/Config/Structure.php
+++ b/lib/internal/Magento/Framework/View/Page/Config/Structure.php
@@ -1,6 +1,6 @@
 <?php
 /**
- * Copyright © 2016 Magento. All rights reserved.
+ * Copyright © 2017 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
 
@@ -12,6 +12,22 @@ namespace Magento\Framework\View\Page\Config;
  */
 class Structure
 {
+    /**
+     * Map of class properties.
+     *
+     * @var array
+     */
+    private $serializableProperties = [
+        'assets',
+        'removeAssets',
+        'title',
+        'metadata',
+        'elementAttributes',
+        'removeElementAttributes',
+        'bodyClasses',
+        'isBodyClassesDeleted',
+    ];
+
     /**
      * Information assets elements on page
      *
@@ -194,4 +210,44 @@ class Structure
     {
         return $this->assets;
     }
+
+    /**
+     * Reformat 'Page config structure' to array.
+     *
+     * @return array
+     */
+    public function __toArray()
+    {
+        $result = [];
+        foreach ($this->serializableProperties as $property) {
+            $result[$property] = $this->{$property};
+        }
+
+        return $result;
+    }
+
+    /**
+     * Update 'Page config structure' data.
+     *
+     * @param array $data
+     * @return void
+     */
+    public function populateWithArray(array $data)
+    {
+        foreach ($this->serializableProperties as $property) {
+            $this->{$property} = $this->getArrayValueByKey($property, $data);
+        }
+    }
+
+    /**
+     * Get value from array by key.
+     *
+     * @param string $key
+     * @param array $array
+     * @return array
+     */
+    private function getArrayValueByKey($key, array $array)
+    {
+        return isset($array[$key]) ? $array[$key] : [];
+    }
 }
diff --git a/lib/internal/Magento/Framework/View/Test/Unit/LayoutTest.php b/lib/internal/Magento/Framework/View/Test/Unit/LayoutTest.php
index 413b1e4cd1ac83008600dbf062d038796a408642..640ece658edaa0620c3c470206914b431cf403bc 100755
--- a/lib/internal/Magento/Framework/View/Test/Unit/LayoutTest.php
+++ b/lib/internal/Magento/Framework/View/Test/Unit/LayoutTest.php
@@ -1,10 +1,12 @@
 <?php
 /**
- * Copyright © 2016 Magento. All rights reserved.
+ * Copyright © 2017 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
 namespace Magento\Framework\View\Test\Unit;
 
+use Magento\Framework\Serialize\SerializerInterface;
+
 /**
  * @SuppressWarnings(PHPMD.TooManyFields)
  * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
@@ -81,6 +83,16 @@ class LayoutTest extends \PHPUnit_Framework_TestCase
      */
     protected $readerContextMock;
 
+    /**
+     * @var \Magento\Framework\View\Page\Config\Structure|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $pageConfigStructure;
+
+    /**
+     * @var \Magento\Framework\View\Layout\ScheduledStructure|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $layoutScheduledSructure;
+
     /**
      * @var \Magento\Framework\View\Layout\Generator\ContextFactory|\PHPUnit_Framework_MockObject_MockObject
      */
@@ -96,6 +108,11 @@ class LayoutTest extends \PHPUnit_Framework_TestCase
      */
     protected $loggerMock;
 
+    /**
+     * @var SerializerInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $serializer;
+
     protected function setUp()
     {
         $this->structureMock = $this->getMockBuilder(\Magento\Framework\View\Layout\Data\Structure::class)
@@ -141,9 +158,22 @@ class LayoutTest extends \PHPUnit_Framework_TestCase
         $this->readerContextFactoryMock = $this->getMockBuilder(
             \Magento\Framework\View\Layout\Reader\ContextFactory::class
         )->disableOriginalConstructor()->getMock();
+
+        $this->pageConfigStructure = $this->getMockBuilder(\Magento\Framework\View\Page\Config\Structure::class)
+            ->setMethods(['__toArray', 'populateWithArray'])
+            ->getMock();
+        $this->layoutScheduledSructure = $this->getMockBuilder(\Magento\Framework\View\Layout\ScheduledStructure::class)
+            ->setMethods(['__toArray', 'populateWithArray'])
+            ->getMock();
         $this->readerContextMock = $this->getMockBuilder(\Magento\Framework\View\Layout\Reader\Context::class)
+            ->setMethods(['getPageConfigStructure', 'getScheduledStructure'])
             ->disableOriginalConstructor()
             ->getMock();
+        $this->readerContextMock->expects($this->any())->method('getPageConfigStructure')
+            ->willReturn($this->pageConfigStructure);
+        $this->readerContextMock->expects($this->any())->method('getScheduledStructure')
+            ->willReturn($this->layoutScheduledSructure);
+
         $this->generatorContextFactoryMock = $this->getMockBuilder(
             \Magento\Framework\View\Layout\Generator\ContextFactory::class
         )
@@ -154,6 +184,15 @@ class LayoutTest extends \PHPUnit_Framework_TestCase
             ->getMock();
         $this->loggerMock = $this->getMockBuilder(\Psr\Log\LoggerInterface::class)
             ->getMock();
+        $this->serializer = $this->getMock(\Magento\Framework\Serialize\SerializerInterface::class);
+        $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\Framework\View\Layout(
             $this->processorFactoryMock,
@@ -168,7 +207,8 @@ class LayoutTest extends \PHPUnit_Framework_TestCase
             $this->generatorContextFactoryMock,
             $this->appStateMock,
             $this->loggerMock,
-            true
+            true,
+            $this->serializer
         );
     }
 
@@ -735,9 +775,32 @@ class LayoutTest extends \PHPUnit_Framework_TestCase
             ->with($this->readerContextMock, $xml)
             ->willReturnSelf();
 
+        $pageConfigStructureData = [
+            'field_1' => 123,
+            'field_2' => 'text',
+            'field_3' => [
+                'field_3_1' => '1244',
+                'field_3_2' => null,
+                'field_3_3' => false,
+            ]
+        ];
+        $this->pageConfigStructure->expects($this->any())->method('__toArray')
+            ->willReturn($pageConfigStructureData);
+
+        $layoutScheduledStructureData = [
+            'field_1' => 1283,
+            'field_2' => 'text_qwertyuiop[]asdfghjkl;'
+        ];
+        $this->layoutScheduledSructure->expects($this->any())->method('__toArray')
+            ->willReturn($layoutScheduledStructureData);
+        $data = [
+            'pageConfigStructure' => $pageConfigStructureData,
+            'scheduledStructure' => $layoutScheduledStructureData
+        ];
+
         $this->cacheMock->expects($this->once())
             ->method('save')
-            ->with(serialize($this->readerContextMock), 'structure_' . $layoutCacheId, $handles)
+            ->with(json_encode($data), 'structure_' . $layoutCacheId, $handles)
             ->willReturn(true);
 
         $generatorContextMock = $this->getMockBuilder(\Magento\Framework\View\Layout\Generator\Context::class)
@@ -774,6 +837,9 @@ class LayoutTest extends \PHPUnit_Framework_TestCase
         $xml = simplexml_load_string('<layout/>', \Magento\Framework\View\Layout\Element::class);
         $this->model->setXml($xml);
 
+        $this->readerContextFactoryMock->expects($this->once())
+            ->method('create')
+            ->willReturn($this->readerContextMock);
         $themeMock = $this->getMockForAbstractClass(\Magento\Framework\View\Design\ThemeInterface::class);
         $this->themeResolverMock->expects($this->once())
             ->method('get')
@@ -787,14 +853,33 @@ class LayoutTest extends \PHPUnit_Framework_TestCase
             ->method('getCacheId')
             ->willReturn($layoutCacheId);
 
-        $readerContextMock = $this->getMockBuilder(\Magento\Framework\View\Layout\Reader\Context::class)
-            ->disableOriginalConstructor()
-            ->getMock();
+        $pageConfigStructureData = [
+            'field_1' => 123,
+            'field_2' => 'text',
+            'field_3' => [
+                'field_3_1' => '1244',
+                'field_3_2' => null,
+                'field_3_3' => false,
+            ]
+        ];
+        $this->pageConfigStructure->expects($this->once())->method('populateWithArray')
+            ->with($pageConfigStructureData);
+
+        $layoutScheduledStructureData = [
+            'field_1' => 1283,
+            'field_2' => 'text_qwertyuiop[]asdfghjkl;'
+        ];
+        $this->layoutScheduledSructure->expects($this->once())->method('populateWithArray')
+            ->with($layoutScheduledStructureData);
+        $data = [
+            'pageConfigStructure' => $pageConfigStructureData,
+            'scheduledStructure' => $layoutScheduledStructureData
+        ];
 
         $this->cacheMock->expects($this->once())
             ->method('load')
             ->with('structure_' . $layoutCacheId)
-            ->willReturn(serialize($readerContextMock));
+            ->willReturn(json_encode($data));
 
         $this->readerPoolMock->expects($this->never())
             ->method('interpret');
@@ -811,7 +896,7 @@ class LayoutTest extends \PHPUnit_Framework_TestCase
 
         $this->generatorPoolMock->expects($this->once())
             ->method('process')
-            ->with($readerContextMock, $generatorContextMock)
+            ->with($this->readerContextMock, $generatorContextMock)
             ->willReturn(true);
 
         $elements = [