diff --git a/app/code/Magento/Backend/Block/Menu.php b/app/code/Magento/Backend/Block/Menu.php
index 55ad3f2cbca00cec0f08004c0a0db5867727d769..087fd1fa351709778cc536f519c4b84206d97134 100644
--- a/app/code/Magento/Backend/Block/Menu.php
+++ b/app/code/Magento/Backend/Block/Menu.php
@@ -436,6 +436,7 @@ class Menu extends \Magento\Backend\Block\Template
      * @param array $colBrakes
      * @return string HTML
      * @SuppressWarnings(PHPMD.NPathComplexity)
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      */
     public function renderNavigation($menu, $level = 0, $limit = 0, $colBrakes = [])
     {
@@ -454,21 +455,30 @@ class Menu extends \Magento\Backend\Block\Template
             }
 
             $id = $this->getJsId($menuItem->getId());
-            $output .= '<li ' . $this->getUiId(
-                $menuItem->getId()
-            ) . ' class="item-' . $itemClass . ' ' . $this->_renderItemCssClass(
-                $menuItem,
-                $level
-            ) . ($level == 0 ? '" id="' . $id . '" aria-haspopup="true' : '')
-                . '" role="menu-item">' . $this->_renderAnchor(
-                $menuItem,
-                $level
-            ) . $this->_addSubMenu(
-                $menuItem,
-                $level,
-                $limit,
-                $id
-            ) . '</li>';
+            if (count($menu) > 1 || $level != 1) {
+                $output .= '<li ' . $this->getUiId(
+                        $menuItem->getId()
+                    ) . ' class="item-' . $itemClass . ' ' . $this->_renderItemCssClass(
+                        $menuItem,
+                        $level
+                    ) . ($level == 0 ? '" id="' . $id . '" aria-haspopup="true' : '')
+                    . '" role="menu-item">' . $this->_renderAnchor(
+                        $menuItem,
+                        $level
+                    ) . $this->_addSubMenu(
+                        $menuItem,
+                        $level,
+                        $limit,
+                        $id
+                    ) . '</li>';
+            } else {
+                $output .= $this->_addSubMenu(
+                    $menuItem,
+                    $level,
+                    $limit,
+                    $id);
+            }
+
             $itemPosition++;
         }
 
diff --git a/app/code/Magento/Bundle/etc/data_object.xml b/app/code/Magento/Bundle/etc/service_data_attributes.xml
similarity index 70%
rename from app/code/Magento/Bundle/etc/data_object.xml
rename to app/code/Magento/Bundle/etc/service_data_attributes.xml
index 2b3da013978f971bb20baca3a5e0ca95f2b501fc..8150a2dceeddd7d70d4e16ffa3d1b6996f316d5d 100644
--- a/app/code/Magento/Bundle/etc/data_object.xml
+++ b/app/code/Magento/Bundle/etc/service_data_attributes.xml
@@ -5,8 +5,8 @@
  * See COPYING.txt for license details.
  */
 -->
-<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/Api/etc/data_object.xsd">
-    <custom_attributes for="Magento\Catalog\Api\Data\ProductInterface">
+<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/Api/etc/service_data_attributes.xsd">
+    <extension_attributes for="Magento\Catalog\Api\Data\ProductInterface">
         <attribute code="bundle_product_options" type="Magento\Bundle\Api\Data\OptionInterface[]" />
-    </custom_attributes>
+    </extension_attributes>
 </config>
diff --git a/app/code/Magento/CatalogInventory/etc/service_data_attributes.xml b/app/code/Magento/CatalogInventory/etc/service_data_attributes.xml
new file mode 100644
index 0000000000000000000000000000000000000000..577b4678c42e99ad5d250f34409c2c5e51654848
--- /dev/null
+++ b/app/code/Magento/CatalogInventory/etc/service_data_attributes.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<!--
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+-->
+<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/Api/etc/service_data_attributes.xsd">
+    <extension_attributes for="Magento\Catalog\Api\Data\ProductInterface">
+    <!--
+        Once this is merged with the branch with the CatalogInventory integration, need to make sure the permission
+        below is actually used.
+        <attribute code="stock_item" type="Magento\CatalogInventory\Api\Data\StockItemInterface">
+            <resources>
+                <resource ref="Magento_CatalogInventory::cataloginventory"/>
+            </resources>
+        </attribute>
+    -->
+    </extension_attributes>
+</config>
diff --git a/app/code/Magento/GiftMessage/etc/data_object.xml b/app/code/Magento/GiftMessage/etc/service_data_attributes.xml
similarity index 64%
rename from app/code/Magento/GiftMessage/etc/data_object.xml
rename to app/code/Magento/GiftMessage/etc/service_data_attributes.xml
index a1255cc8a161a5a8d28090697088a87ede8920e7..f02c0a717e169224d0b7d450e861f38d7176dc7f 100644
--- a/app/code/Magento/GiftMessage/etc/data_object.xml
+++ b/app/code/Magento/GiftMessage/etc/service_data_attributes.xml
@@ -5,11 +5,11 @@
  * See COPYING.txt for license details.
  */
 -->
-<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/Api/etc/data_object.xsd">
-    <custom_attributes for="Magento\Sales\Api\Data\OrderInterface">
+<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/Api/etc/service_data_attributes.xsd">
+    <extension_attributes for="Magento\Sales\Api\Data\OrderInterface">
         <attribute code="gift_message" type="Magento\GiftMessage\Api\Data\MessageInterface" />
-    </custom_attributes>
-    <custom_attributes for="Magento\Sales\Api\Data\OrderItemInterface">
+    </extension_attributes>
+    <extension_attributes for="Magento\Sales\Api\Data\OrderItemInterface">
         <attribute code="gift_message" type="Magento\GiftMessage\Api\Data\MessageInterface" />
-    </custom_attributes>
+    </extension_attributes>
 </config>
diff --git a/app/code/Magento/GroupedProduct/etc/data_object.xml b/app/code/Magento/GroupedProduct/etc/service_data_attributes.xml
similarity index 66%
rename from app/code/Magento/GroupedProduct/etc/data_object.xml
rename to app/code/Magento/GroupedProduct/etc/service_data_attributes.xml
index d6a76ebaa081f2e742c78e66d70dc504c460bdde..0618cc9286cfd8ccb0cab46f6a505b05a39c4ee2 100644
--- a/app/code/Magento/GroupedProduct/etc/data_object.xml
+++ b/app/code/Magento/GroupedProduct/etc/service_data_attributes.xml
@@ -5,8 +5,8 @@
  * See COPYING.txt for license details.
  */
 -->
-<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/Api/etc/data_object.xsd">
-    <custom_attributes for="Magento\Catalog\Api\Data\ProductLinkInterface">
+<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/Api/etc/service_data_attributes.xsd">
+    <extension_attributes for="Magento\Catalog\Api\Data\ProductLinkInterface">
         <attribute code="qty" type="float" />
-    </custom_attributes>
+    </extension_attributes>
 </config>
diff --git a/app/code/Magento/Sales/etc/data_object.xml b/app/code/Magento/Sales/etc/service_data_attributes.xml
similarity index 78%
rename from app/code/Magento/Sales/etc/data_object.xml
rename to app/code/Magento/Sales/etc/service_data_attributes.xml
index 8ef8080db8a29120f255cedfe0c083f45d85e5e5..1e7f320c18ed6e98b0c979d23e80e6ff48478fa4 100644
--- a/app/code/Magento/Sales/etc/data_object.xml
+++ b/app/code/Magento/Sales/etc/service_data_attributes.xml
@@ -5,10 +5,10 @@
  * See COPYING.txt for license details.
  */
 -->
-<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/Api/etc/data_object.xsd">
-    <custom_attributes for="Magento\Sales\Api\Data\OrderInterface">
+<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/Api/etc/service_data_attributes.xsd">
+    <extension_attributes for="Magento\Sales\Api\Data\OrderInterface">
         <attribute code="applied_taxes" type="Magento\Tax\Api\Data\OrderTaxDetailsAppliedTaxInterface[]" />
         <attribute code="item_applied_taxes" type="Magento\Tax\Api\Data\OrderTaxDetailsItemInterface[]" />
         <attribute code="converting_from_quote" type="boolean" />
-    </custom_attributes>
+    </extension_attributes>
 </config>
diff --git a/app/code/Magento/Webapi/Controller/Rest/Router/Route.php b/app/code/Magento/Webapi/Controller/Rest/Router/Route.php
index 5c125c29611d9e2000436a7147329dfa449ab729..03e6d2fd8ca06eb864bfa318af4a91182e8c1bb7 100644
--- a/app/code/Magento/Webapi/Controller/Rest/Router/Route.php
+++ b/app/code/Magento/Webapi/Controller/Rest/Router/Route.php
@@ -69,7 +69,7 @@ class Route implements RouterInterface
                 $this->variables[$key] = substr($value, 1);
                 $value = null;
             }
-            $result[$key] = strtolower($value);
+            $result[$key] = $value;
         }
         return $result;
     }
@@ -92,19 +92,12 @@ class Route implements RouterInterface
     /**
      * Retrieve unified requested path
      *
-     * Lowercase all path chunks, except variables names.
-     * E.g. the path '/V1/Categories/:categoryId' will be converted to '/v1/categories/:categoryId'.
-     *
      * @param string $path
      * @return array
      */
     protected function getPathParts($path)
     {
-        $result = explode('/', trim($path, '/'));
-        array_walk($result, function (&$item) {
-            $item = substr($item, 0, 1) === ":" ? $item : strtolower($item);
-        });
-        return $result;
+        return explode('/', trim($path, '/'));
     }
 
     /**
diff --git a/app/code/Magento/Webapi/Controller/Soap/Request/Handler.php b/app/code/Magento/Webapi/Controller/Soap/Request/Handler.php
index 25d196ce6a80461109ec3246bbe3a5bb895cfa22..ec73bd7236c104f5364b03433e83d8c622e12414 100644
--- a/app/code/Magento/Webapi/Controller/Soap/Request/Handler.php
+++ b/app/code/Magento/Webapi/Controller/Soap/Request/Handler.php
@@ -15,6 +15,7 @@ use Magento\Framework\Webapi\ServiceInputProcessor;
 use Magento\Webapi\Controller\Soap\Request as SoapRequest;
 use Magento\Framework\Webapi\Exception as WebapiException;
 use Magento\Webapi\Model\Soap\Config as SoapConfig;
+use Magento\Framework\Reflection\MethodsMap;
 
 /**
  * Handler of requests to SOAP server.
@@ -48,6 +49,9 @@ class Handler
     /** @var DataObjectProcessor */
     protected $_dataObjectProcessor;
 
+    /** @var MethodsMap */
+    protected $methodsMapProcessor;
+
     /**
      * Initialize dependencies.
      *
@@ -58,6 +62,7 @@ class Handler
      * @param SimpleDataObjectConverter $dataObjectConverter
      * @param ServiceInputProcessor $serviceInputProcessor
      * @param DataObjectProcessor $dataObjectProcessor
+     * @param MethodsMap $methodsMapProcessor
      */
     public function __construct(
         SoapRequest $request,
@@ -66,7 +71,8 @@ class Handler
         AuthorizationInterface $authorization,
         SimpleDataObjectConverter $dataObjectConverter,
         ServiceInputProcessor $serviceInputProcessor,
-        DataObjectProcessor $dataObjectProcessor
+        DataObjectProcessor $dataObjectProcessor,
+        MethodsMap $methodsMapProcessor
     ) {
         $this->_request = $request;
         $this->_objectManager = $objectManager;
@@ -75,6 +81,7 @@ class Handler
         $this->_dataObjectConverter = $dataObjectConverter;
         $this->serviceInputProcessor = $serviceInputProcessor;
         $this->_dataObjectProcessor = $dataObjectProcessor;
+        $this->methodsMapProcessor = $methodsMapProcessor;
     }
 
     /**
@@ -149,7 +156,7 @@ class Handler
     protected function _prepareResponseData($data, $serviceClassName, $serviceMethodName)
     {
         /** @var string $dataType */
-        $dataType = $this->_dataObjectProcessor->getMethodReturnType($serviceClassName, $serviceMethodName);
+        $dataType = $this->methodsMapProcessor->getMethodReturnType($serviceClassName, $serviceMethodName);
         $result = null;
         if (is_object($data)) {
             $result = $this->_dataObjectConverter
diff --git a/app/code/Magento/Webapi/Model/Rest/Config.php b/app/code/Magento/Webapi/Model/Rest/Config.php
index dfee1d873c02158645f482b3fe7242ecc5636bfe..51d0e67d7803603ef4ff02e6db406f041166b2d9 100644
--- a/app/code/Magento/Webapi/Model/Rest/Config.php
+++ b/app/code/Magento/Webapi/Model/Rest/Config.php
@@ -67,7 +67,7 @@ class Config
         /** @var $route \Magento\Webapi\Controller\Rest\Router\Route */
         $route = $this->_routeFactory->createRoute(
             'Magento\Webapi\Controller\Rest\Router\Route',
-            $this->_formatRoutePath($routeData[self::KEY_ROUTE_PATH])
+            $routeData[self::KEY_ROUTE_PATH]
         );
 
         $route->setServiceClass($routeData[self::KEY_CLASS])
@@ -78,22 +78,6 @@ class Config
         return $route;
     }
 
-    /**
-     * Lowercase all parts of the given route path except for the path parameters.
-     *
-     * @param string $routePath The route path (e.g. '/V1/Categories/:categoryId')
-     * @return string The modified route path (e.g. '/v1/categories/:categoryId')
-     */
-    protected function _formatRoutePath($routePath)
-    {
-        $routePathParts = explode('/', $routePath);
-        $pathParts = [];
-        foreach ($routePathParts as $pathPart) {
-            $pathParts[] = substr($pathPart, 0, 1) === ":" ? $pathPart : strtolower($pathPart);
-        }
-        return implode('/', $pathParts);
-    }
-
     /**
      * Get service base URL
      *
diff --git a/app/code/Magento/Webapi/Test/Unit/Controller/Rest/Router/RouteTest.php b/app/code/Magento/Webapi/Test/Unit/Controller/Rest/Router/RouteTest.php
index 6732d012dc1e726e29e4afab132711759d4ce7f9..4a9192b36882b9f69a66755af08cd3f050374beb 100644
--- a/app/code/Magento/Webapi/Test/Unit/Controller/Rest/Router/RouteTest.php
+++ b/app/code/Magento/Webapi/Test/Unit/Controller/Rest/Router/RouteTest.php
@@ -95,10 +95,7 @@ class RouteTest extends \PHPUnit_Framework_TestCase
             ['/V1/one/two/:threeValue/four/:fiveValue', '/V1/one/two/3/four/5', ['threeValue' => 3, 'fiveValue' => 5]],
 
             ['/v1/One', '/v1/One', []],
-            ['/v1/oNe', '/V1/one', []],
-            ['/v1/onE', '/V1/oNe', []],
 
-            ['/v1/One/:twoValue', '/V1/one/2', ['twoValue' => 2]],
             ['/v1/oNe/:TwoValue', '/v1/oNe/2', ['TwoValue' => 2]],
             ['/v1/onE/:twovalue', '/v1/onE/2', ['twovalue' => 2]],
 
@@ -108,6 +105,9 @@ class RouteTest extends \PHPUnit_Framework_TestCase
             ['/V1/one-one/:two_value', '/V1/one-one/2', ['two_value' => 2]],
 
             // Error
+            ['/v1/oNe', '/V1/one', false],
+            ['/v1/onE', '/V1/oNe', false],
+            ['/v1/One/:twoValue', '/V1/one/2', false],
             ['/V1/one', '/V1/two', false],
             ['/V1/one/:twoValue', '/V1/one', false],
             ['/V1/one/two', '/V1/one', false],
diff --git a/app/code/Magento/Webapi/Test/Unit/Controller/Soap/Request/HandlerTest.php b/app/code/Magento/Webapi/Test/Unit/Controller/Soap/Request/HandlerTest.php
index 2800d5466585fdc8eec97ba82dd53d7f5fee0c93..8c3741c3b8d48c86e0e876125cee6558a2c3a403 100644
--- a/app/code/Magento/Webapi/Test/Unit/Controller/Soap/Request/HandlerTest.php
+++ b/app/code/Magento/Webapi/Test/Unit/Controller/Soap/Request/HandlerTest.php
@@ -40,6 +40,9 @@ class HandlerTest extends \PHPUnit_Framework_TestCase
     /** @var \Magento\Framework\Reflection\DataObjectProcessor|\PHPUnit_Framework_MockObject_MockObject */
     protected $_dataObjectProcessorMock;
 
+    /** @var \Magento\Framework\Reflection\MethodsMap|\PHPUnit_Framework_MockObject_MockObject */
+    protected $_methodsMapProcessorMock;
+
     /** @var array */
     protected $_arguments;
 
@@ -67,7 +70,13 @@ class HandlerTest extends \PHPUnit_Framework_TestCase
         );
         $this->_dataObjectProcessorMock = $this->getMock(
             'Magento\Framework\Reflection\DataObjectProcessor',
-            ['getMethodReturnType'],
+            [],
+            [],
+            '',
+            false);
+        $this->_methodsMapProcessorMock = $this->getMock(
+            'Magento\Framework\Reflection\MethodsMap',
+            [],
             [],
             '',
             false);
@@ -80,7 +89,8 @@ class HandlerTest extends \PHPUnit_Framework_TestCase
             $this->_authorizationMock,
             $this->_dataObjectConverter,
             $this->_serviceInputProcessorMock,
-            $this->_dataObjectProcessorMock
+            $this->_dataObjectProcessorMock,
+            $this->_methodsMapProcessorMock
         );
         parent::setUp();
     }
@@ -128,10 +138,6 @@ class HandlerTest extends \PHPUnit_Framework_TestCase
             ->method('process')
             ->will($this->returnArgument(2));
 
-        $this->_dataObjectProcessorMock->expects($this->any())->method('getMethodReturnType')
-            ->with($className, $methodName)
-            ->will($this->returnValue('string'));
-
         /** Execute SUT. */
         $this->assertEquals(
             ['result' => $serviceResponse],
diff --git a/app/code/Magento/Webapi/Test/Unit/Model/DataObjectProcessorTest.php b/app/code/Magento/Webapi/Test/Unit/Model/DataObjectProcessorTest.php
index 3453c7e1d7951de030d96012f813477fe73efd4b..c3f586d835a8d3c3d1d85e3626e258680541441c 100644
--- a/app/code/Magento/Webapi/Test/Unit/Model/DataObjectProcessorTest.php
+++ b/app/code/Magento/Webapi/Test/Unit/Model/DataObjectProcessorTest.php
@@ -23,7 +23,21 @@ class DataObjectProcessorTest extends \PHPUnit_Framework_TestCase
     protected function setup()
     {
         $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
-        $this->dataObjectProcessor = $objectManager->getObject('Magento\Framework\Reflection\DataObjectProcessor');
+        $methodsMapProcessor = $objectManager->getObject(
+            'Magento\Framework\Reflection\MethodsMap',
+            [
+                'fieldNamer' => $objectManager->getObject('Magento\Framework\Reflection\FieldNamer'),
+                'typeProcessor' => $objectManager->getObject('Magento\Framework\Reflection\TypeProcessor'),
+            ]
+        );
+        $this->dataObjectProcessor = $objectManager->getObject(
+            'Magento\Framework\Reflection\DataObjectProcessor',
+            [
+                'methodsMapProcessor' => $methodsMapProcessor,
+                'typeCaster' => $objectManager->getObject('Magento\Framework\Reflection\TypeCaster'),
+                'fieldNamer' => $objectManager->getObject('Magento\Framework\Reflection\FieldNamer'),
+            ]
+        );
         parent::setUp();
     }
 
diff --git a/app/code/Magento/Webapi/Test/Unit/Model/Files/TestDataInterface.php b/app/code/Magento/Webapi/Test/Unit/Model/Files/TestDataInterface.php
index 1b4f971c2c3a447261a22ce6bb898311813e65b7..2010509ff416165858cbdcb1b1d3b3ae298c9759 100644
--- a/app/code/Magento/Webapi/Test/Unit/Model/Files/TestDataInterface.php
+++ b/app/code/Magento/Webapi/Test/Unit/Model/Files/TestDataInterface.php
@@ -8,11 +8,23 @@ namespace Magento\Webapi\Test\Unit\Model\Files;
 
 interface TestDataInterface
 {
+    /**
+     * @return string
+     */
     public function getId();
 
+    /**
+     * @return string
+     */
     public function getAddress();
 
+    /**
+     * @return string
+     */
     public function isDefaultShipping();
 
+    /**
+     * @return string
+     */
     public function isRequiredBilling();
 }
diff --git a/app/code/Magento/Webapi/etc/di.xml b/app/code/Magento/Webapi/etc/di.xml
index 12b661f639c428c681b98b1df7c0f5a8131da632..c58acdbf51c4b9e3252745d425b3d365e2a60449 100644
--- a/app/code/Magento/Webapi/etc/di.xml
+++ b/app/code/Magento/Webapi/etc/di.xml
@@ -22,11 +22,17 @@
     <type name="Magento\Framework\Xml\Parser" shared="false" />
     <type name="Magento\Framework\Code\Scanner\DirectoryScanner" shared="false" />
     <type name="Magento\Server\Reflection" shared="false" />
-    <type name="Magento\Framework\Reflection\DataObjectProcessor">
+    <type name="Magento\Framework\Reflection\MethodsMap">
         <arguments>
             <argument name="cache" xsi:type="object">Magento\Framework\App\Cache\Type\Webapi</argument>
         </arguments>
     </type>
+    <type name="Magento\Framework\Reflection\DataObjectProcessor">
+        <arguments>
+            <argument name="extensionAttributesProcessor" xsi:type="object">Magento\Framework\Reflection\ExtensionAttributesProcessor\Proxy</argument>
+            <argument name="customAttributesProcessor" xsi:type="object">Magento\Framework\Reflection\CustomAttributesProcessor\Proxy</argument>
+        </arguments>
+    </type>
     <type name="Magento\Integration\Model\ConfigBasedIntegrationManager">
         <plugin name="webapiSetup" type="Magento\Webapi\Model\Plugin\Manager" />
     </type>
diff --git a/app/code/Magento/Webapi/etc/webapi_rest/di.xml b/app/code/Magento/Webapi/etc/webapi_rest/di.xml
index 48420045d4afca1644c159d3fa68a541cd8c403a..7941e76f564b0fa13986a9847e250a34f36d383c 100644
--- a/app/code/Magento/Webapi/etc/webapi_rest/di.xml
+++ b/app/code/Magento/Webapi/etc/webapi_rest/di.xml
@@ -71,4 +71,25 @@
     <type name="Magento\Framework\Authorization">
         <plugin name="guestAuthorization" type="Magento\Webapi\Model\Plugin\GuestAuthorization" />
     </type>
+
+    <!-- Configuration to check that the permissions are checked on fields -->
+    <virtualType name="Magento\Framework\Reflection\ExtensionAttributesProcessorPermissionChecked" type="Magento\Framework\Reflection\ExtensionAttributesProcessor">
+        <arguments>
+            <argument name="isPermissionChecked" xsi:type="boolean">true</argument>
+            <argument name="dataObjectProcessor" xsi:type="object">Magento\Framework\Reflection\DataObjectProcessor\Proxy</argument>
+        </arguments>
+    </virtualType>
+    <virtualType name="Magento\Framework\Reflection\DataObjectProcessorPermissionChecked" type="Magento\Framework\Reflection\DataObjectProcessor">
+        <arguments>
+            <argument name="extensionAttributesProcessor" xsi:type="object">Magento\Framework\Reflection\ExtensionAttributesProcessorPermissionChecked</argument>
+            <argument name="customAttributesProcessor" xsi:type="object">Magento\Framework\Reflection\CustomAttributesProcessor\Proxy</argument>
+        </arguments>
+    </virtualType>
+
+    <type name="Magento\Framework\Webapi\ServiceOutputProcessor">
+        <arguments>
+            <argument name="dataObjectProcessor" xsi:type="object">Magento\Framework\Reflection\DataObjectProcessorPermissionChecked</argument>
+        </arguments>
+    </type>
+    <!-- End of configuration to check that permissions are checked on fields -->
 </config>
diff --git a/app/code/Magento/Webapi/etc/webapi_soap/di.xml b/app/code/Magento/Webapi/etc/webapi_soap/di.xml
index 6d5607c49c18dc46d9e6d9cbc429bc11f4a26467..c8cabfba0ac2529cb3365da99ae129086bee75fe 100644
--- a/app/code/Magento/Webapi/etc/webapi_soap/di.xml
+++ b/app/code/Magento/Webapi/etc/webapi_soap/di.xml
@@ -39,4 +39,26 @@
     <type name="Magento\Framework\Authorization">
         <plugin name="guestAuthorization" type="Magento\Webapi\Model\Plugin\GuestAuthorization" />
     </type>
+
+    <!-- Configuration to check that the permissions are checked on fields -->
+    <virtualType name="Magento\Framework\Reflection\ExtensionAttributesProcessorPermissionChecked" type="Magento\Framework\Reflection\ExtensionAttributesProcessor">
+        <arguments>
+            <argument name="isPermissionChecked" xsi:type="boolean">true</argument>
+            <argument name="dataObjectProcessor" xsi:type="object">Magento\Framework\Reflection\DataObjectProcessor\Proxy</argument>
+        </arguments>
+    </virtualType>
+    <virtualType name="Magento\Framework\Reflection\DataObjectProcessorPermissionChecked" type="Magento\Framework\Reflection\DataObjectProcessor">
+        <arguments>
+            <argument name="extensionAttributesProcessor" xsi:type="object">Magento\Framework\Reflection\ExtensionAttributesProcessorPermissionChecked</argument>
+            <argument name="customAttributesProcessor" xsi:type="object">Magento\Framework\Reflection\CustomAttributesProcessor\Proxy</argument>
+        </arguments>
+    </virtualType>
+
+    <type name="Magento\Webapi\Controller\Soap\Request\Handler">
+        <arguments>
+            <argument name="dataObjectProcessor" xsi:type="object">Magento\Framework\Reflection\DataObjectProcessorPermissionChecked</argument>
+        </arguments>
+    </type>
+    <!-- End of configuration to check that permissions are checked on fields -->
+
 </config>
diff --git a/dev/tests/api-functional/_files/Magento/TestModule1/etc/data_object.xml b/dev/tests/api-functional/_files/Magento/TestModule1/etc/service_data_attributes.xml
similarity index 69%
rename from dev/tests/api-functional/_files/Magento/TestModule1/etc/data_object.xml
rename to dev/tests/api-functional/_files/Magento/TestModule1/etc/service_data_attributes.xml
index de2236e2195f380aedd5614447065bc9e480f7aa..fa96514a063b6112004e7a6073a2cc131a87f44c 100644
--- a/dev/tests/api-functional/_files/Magento/TestModule1/etc/data_object.xml
+++ b/dev/tests/api-functional/_files/Magento/TestModule1/etc/service_data_attributes.xml
@@ -5,13 +5,13 @@
  * See COPYING.txt for license details.
  */
 -->
-<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/Api/etc/data_object.xsd">
-    <custom_attributes for="Magento\TestModule1\Service\V1\Entity\Item">
+<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/Api/etc/service_data_attributes.xsd">
+    <extension_attributes for="Magento\TestModule1\Service\V1\Entity\Item">
         <attribute code="custom_attribute_data_object" type="Magento\TestModuleMSC\Model\Data\CustomAttributeDataObject" />
         <attribute code="custom_attribute_string" type="string" />
-    </custom_attributes>
-    <custom_attributes for="Magento\TestModuleMSC\Model\Data\CustomAttributeDataObject">
+    </extension_attributes>
+    <extension_attributes for="Magento\TestModuleMSC\Model\Data\CustomAttributeDataObject">
         <attribute code="custom_attribute_nested" type="Magento\TestModuleMSC\Model\Data\CustomAttributeNestedDataObject" />
         <attribute code="custom_attribute_int" type="int" />
-    </custom_attributes>
+    </extension_attributes>
 </config>
diff --git a/dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/data_object.xml b/dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/service_data_attributes.xml
similarity index 69%
rename from dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/data_object.xml
rename to dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/service_data_attributes.xml
index ece2b1f581775daa25e1acec4f4fc120a876c431..f11e639ccd2753296d65071cf32f3e5fb47e0e7d 100644
--- a/dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/data_object.xml
+++ b/dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/service_data_attributes.xml
@@ -5,13 +5,13 @@
  * See COPYING.txt for license details.
  */
 -->
-<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/Api/etc/data_object.xsd">
-    <custom_attributes for="Magento\TestModuleMSC\Api\Data\ItemInterface">
+<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/Api/etc/service_data_attributes.xsd">
+    <extension_attributes for="Magento\TestModuleMSC\Api\Data\ItemInterface">
         <attribute code="custom_attribute_data_object" type="Magento\TestModuleMSC\Api\Data\CustomAttributeDataObjectInterface" />
         <attribute code="custom_attribute_string" type="string" />
-    </custom_attributes>
-    <custom_attributes for="Magento\TestModuleMSC\Api\Data\CustomAttributeDataObjectInterface">
+    </extension_attributes>
+    <extension_attributes for="Magento\TestModuleMSC\Api\Data\CustomAttributeDataObjectInterface">
         <attribute code="custom_attribute_nested" type="Magento\TestModuleMSC\Api\Data\CustomAttributeNestedDataObjectInterface" />
         <attribute code="custom_attribute_int" type="int" />
-    </custom_attributes>
+    </extension_attributes>
 </config>
diff --git a/dev/tests/api-functional/testsuite/Magento/Webapi/Routing/RestErrorHandlingTest.php b/dev/tests/api-functional/testsuite/Magento/Webapi/Routing/RestErrorHandlingTest.php
index 41d6e8a2914deb9a863b42d2634d0c9aab934324..a64744df17ad68e016255d6d2396bad4e59564f6 100644
--- a/dev/tests/api-functional/testsuite/Magento/Webapi/Routing/RestErrorHandlingTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/Webapi/Routing/RestErrorHandlingTest.php
@@ -81,7 +81,7 @@ class RestErrorHandlingTest extends \Magento\TestFramework\TestCase\WebapiAbstra
     {
         $serviceInfo = [
             'rest' => [
-                'resourcePath' => '/V1/errortest/otherexception',
+                'resourcePath' => '/V1/errortest/otherException',
                 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_GET,
             ],
         ];
diff --git a/dev/tests/integration/framework/bootstrap.php b/dev/tests/integration/framework/bootstrap.php
index 41453aa0becc0e2d32513736f2cb99ddc60e8854..b71bb17d945ccd42f693ed57588116e05c474dbb 100644
--- a/dev/tests/integration/framework/bootstrap.php
+++ b/dev/tests/integration/framework/bootstrap.php
@@ -8,6 +8,11 @@ use Magento\Framework\Autoload\AutoloaderRegistry;
 require_once __DIR__ . '/../../../../app/bootstrap.php';
 require_once __DIR__ . '/autoload.php';
 
+$updateAppBootstrap = __DIR__ . '/../../../../update/app/bootstrap.php';
+if (file_exists($updateAppBootstrap)) {
+    require_once $updateAppBootstrap;
+}
+
 $testsBaseDir = dirname(__DIR__);
 $testsTmpDir = "{$testsBaseDir}/tmp";
 $magentoBaseDir = realpath("{$testsBaseDir}/../../../");
diff --git a/dev/tests/integration/phpunit.xml.dist b/dev/tests/integration/phpunit.xml.dist
index 7a9e365c8f15056e5060cd27827720e2d18d2fce..bd6cbffb247d64f6617eef5fc9c8ebaebb753b7e 100644
--- a/dev/tests/integration/phpunit.xml.dist
+++ b/dev/tests/integration/phpunit.xml.dist
@@ -18,6 +18,7 @@
         </testsuite>
         <testsuite name="Magento Integration Tests">
             <directory suffix="Test.php">testsuite</directory>
+            <directory suffix="Test.php">../../../update/dev/tests/integration/testsuite</directory>
             <exclude>testsuite/Magento/Test/Integrity</exclude>
             <exclude>testsuite/Magento/MemoryUsageTest.php</exclude>
         </testsuite>
@@ -27,6 +28,7 @@
         <whitelist addUncoveredFilesFromWhiteList="true">
             <directory suffix=".php">../../../app/code/Magento</directory>
             <directory suffix=".php">../../../lib/internal/Magento</directory>
+            <directory suffix=".php">../../../update/app/code</directory>
         </whitelist>
     </filter>
     <!-- PHP INI settings and constants definition -->
diff --git a/dev/tests/integration/testsuite/Magento/Backend/Block/_files/menu/expected.txt b/dev/tests/integration/testsuite/Magento/Backend/Block/_files/menu/expected.txt
index fc890c803aae34f8ca74f4c00a541415b426034a..dc07065f7be1e4b2db53584c769bb52abb79de21 100644
--- a/dev/tests/integration/testsuite/Magento/Backend/Block/_files/menu/expected.txt
+++ b/dev/tests/integration/testsuite/Magento/Backend/Block/_files/menu/expected.txt
@@ -1 +1 @@
-<ul id="nav" role="menubar" ><li  data-ui-id="magento-backend-system"  class="item-system  parent last level-0" id="magento-backend-system" aria-haspopup="true" role="menu-item"><a href="#"  onclick="return false;" class=""><span>System</span></a><div class="submenu" aria-labelledby="magento-backend-system"><ul role="menu" ><li  data-ui-id="magento-backend-system-report"  class="item-system-report  parent  level-1" role="menu-item"><strong class="submenu-group-title" role="presentation"><span>Report</span></strong><div class="submenu"><ul role="menu" ><li  data-ui-id="magento-backend-system-report-private-sales"  class="item-system-report-private-sales    level-2" role="menu-item"><a href="#"  onclick="return false;" class=""><span>Private Sales</span></a></li><li  data-ui-id="magento-backend-system-report-magento-invite-general"  class="item-system-report-magento-invite-general    level-2" role="menu-item"><a href="#"  onclick="return false;" class=""><span>Invite</span></a></li><li  data-ui-id="magento-backend-system-report-magento-invite-customer"  class="item-system-report-magento-invite-customer    level-2" role="menu-item"><a href="#"  onclick="return false;" class=""><span>Invited Customers</span></a></li></ul></div></li></ul></div></li></ul>
\ No newline at end of file
+<ul id="nav" role="menubar" ><li  data-ui-id="magento-backend-system"  class="item-system  parent last level-0" id="magento-backend-system" aria-haspopup="true" role="menu-item"><a href="#"  onclick="return false;" class=""><span>System</span></a><div class="submenu" aria-labelledby="magento-backend-system"><ul role="menu" ><div class="submenu"><ul role="menu" ><li  data-ui-id="magento-backend-system-report-private-sales"  class="item-system-report-private-sales    level-2" role="menu-item"><a href="#"  onclick="return false;" class=""><span>Private Sales</span></a></li><li  data-ui-id="magento-backend-system-report-magento-invite-general"  class="item-system-report-magento-invite-general    level-2" role="menu-item"><a href="#"  onclick="return false;" class=""><span>Invite</span></a></li><li  data-ui-id="magento-backend-system-report-magento-invite-customer"  class="item-system-report-magento-invite-customer    level-2" role="menu-item"><a href="#"  onclick="return false;" class=""><span>Invited Customers</span></a></li></ul></div></ul></div></li></ul>
\ No newline at end of file
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/etc/data_object.xml b/dev/tests/integration/testsuite/Magento/Catalog/_files/etc/service_data_attributes.xml
similarity index 63%
rename from dev/tests/integration/testsuite/Magento/Catalog/_files/etc/data_object.xml
rename to dev/tests/integration/testsuite/Magento/Catalog/_files/etc/service_data_attributes.xml
index c2888a64ee00c0e6f18a7d1126920e4c85a8b091..93cf7bfb484a6de773ab318549385ad2436f2fa4 100644
--- a/dev/tests/integration/testsuite/Magento/Catalog/_files/etc/data_object.xml
+++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/etc/service_data_attributes.xml
@@ -5,22 +5,22 @@
  * See COPYING.txt for license details.
  */
 -->
-<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../../lib/internal/Magento/Framework/Api/etc/data_object.xsd">
-    <custom_attributes for="Magento\Tax\Api\Data\TaxRateInterface">
-    </custom_attributes>
-    <custom_attributes for="Magento\Catalog\Api\Data\ProductInterface">
+<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../../lib/internal/Magento/Framework/Api/etc/service_data_attributes.xsd">
+    <extension_attributes for="Magento\Tax\Api\Data\TaxRateInterface">
+    </extension_attributes>
+    <extension_attributes for="Magento\Catalog\Api\Data\ProductInterface">
         <attribute code="stock_item" type="Magento\CatalogInventory\Service\Data\V1\StockItem" />
-    </custom_attributes>
-    <custom_attributes for="Magento\Catalog\Api\Data\CategoryInterface">
+    </extension_attributes>
+    <extension_attributes for="Magento\Catalog\Api\Data\CategoryInterface">
         <attribute code="category_attribute_1" type="Magento\Catalog\Api\Data\CategoryAttributeType1" />
         <attribute code="category_attribute_2" type="Magento\Catalog\Api\Data\CategoryAttributeType2" />
-    </custom_attributes>
-    <custom_attributes for="Magento\Customer\Api\Data\CustomerInterface">
+    </extension_attributes>
+    <extension_attributes for="Magento\Customer\Api\Data\CustomerInterface">
         <attribute code="customer_attribute_1" type="Magento\Customer\Api\Data\CustomerAttributeType1" />
         <attribute code="customer_attribute_2" type="Magento\Customer\Api\Data\CustomerAttributeType2" />
-    </custom_attributes>
-    <custom_attributes for="Magento\Customer\Api\Data\Address">
+    </extension_attributes>
+    <extension_attributes for="Magento\Customer\Api\Data\Address">
         <attribute code="address_attribute_1" type="Magento\Customer\Api\Data\AddressAttributeType1" />
         <attribute code="address_attribute_2" type="Magento\Customer\Api\Data\AddressAttributeType2" />
-    </custom_attributes>
+    </extension_attributes>
 </config>
diff --git a/dev/tests/integration/testsuite/Magento/Customer/Model/FileResolverStub.php b/dev/tests/integration/testsuite/Magento/Customer/Model/FileResolverStub.php
index 48d81d30eb84119c45e440be2e57bd48b4c3c8e9..9ee9ed911f7c092aac6034ed441e5c96f2e46aa2 100644
--- a/dev/tests/integration/testsuite/Magento/Customer/Model/FileResolverStub.php
+++ b/dev/tests/integration/testsuite/Magento/Customer/Model/FileResolverStub.php
@@ -21,7 +21,7 @@ class FileResolverStub implements \Magento\Framework\Config\FileResolverInterfac
                 'path' => realpath(__DIR__ . '/../_files/etc'),
             ]
         );
-        $paths = ['data_object.xml'];
+        $paths = ['service_data_attributes.xml'];
         return new \Magento\Framework\Config\FileIterator($readDirectory, $paths);
     }
 }
diff --git a/dev/tests/integration/testsuite/Magento/Customer/_files/etc/data_object.xml b/dev/tests/integration/testsuite/Magento/Customer/_files/etc/service_data_attributes.xml
similarity index 63%
rename from dev/tests/integration/testsuite/Magento/Customer/_files/etc/data_object.xml
rename to dev/tests/integration/testsuite/Magento/Customer/_files/etc/service_data_attributes.xml
index a75fa2a653213ade29aa7ea81e8482e752ed9210..a7ae041eda7683ce99dd168befc50c2ae5a46f3c 100644
--- a/dev/tests/integration/testsuite/Magento/Customer/_files/etc/data_object.xml
+++ b/dev/tests/integration/testsuite/Magento/Customer/_files/etc/service_data_attributes.xml
@@ -5,22 +5,22 @@
  * See COPYING.txt for license details.
  */
 -->
-<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../../lib/internal/Magento/Framework/Api/etc/data_object.xsd">
-    <custom_attributes for="Magento\Tax\Api\Data\TaxRateInterface">
-    </custom_attributes>
-    <custom_attributes for="Magento\Catalog\Api\Data\ProductInterface">
+<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../../lib/internal/Magento/Framework/Api/etc/service_data_attributes.xsd">
+    <extension_attributes for="Magento\Tax\Api\Data\TaxRateInterface">
+    </extension_attributes>
+    <extension_attributes for="Magento\Catalog\Api\Data\ProductInterface">
         <attribute code="stock_item" type="Magento\CatalogInventory\Service\Data\V1\StockItem" />
-    </custom_attributes>
-    <custom_attributes for="Magento\Catalog\Api\Data\CategoryInterface">
+    </extension_attributes>
+    <extension_attributes for="Magento\Catalog\Api\Data\CategoryInterface">
         <attribute code="category_attribute_1" type="Magento\Catalog\Api\Data\CategoryAttributeType1" />
         <attribute code="category_attribute_2" type="Magento\Catalog\Api\Data\CategoryAttributeType2" />
-    </custom_attributes>
-    <custom_attributes for="Magento\Customer\Api\Data\CustomerInterface">
+    </extension_attributes>
+    <extension_attributes for="Magento\Customer\Api\Data\CustomerInterface">
         <attribute code="customer_attribute_1" type="Magento\Customer\Api\Data\CustomerAttributeType1" />
         <attribute code="customer_attribute_2" type="Magento\Customer\Api\Data\CustomerAttributeType2" />
-    </custom_attributes>
-    <custom_attributes for="Magento\Customer\Api\Data\AddressInterface">
+    </extension_attributes>
+    <extension_attributes for="Magento\Customer\Api\Data\AddressInterface">
         <attribute code="address_attribute_1" type="Magento\Customer\Api\Data\AddressAttributeType1" />
         <attribute code="address_attribute_2" type="Magento\Customer\Api\Data\AddressAttributeType2" />
-    </custom_attributes>
+    </extension_attributes>
 </config>
diff --git a/dev/tests/integration/testsuite/Magento/Framework/Api/Config/ReaderTest.php b/dev/tests/integration/testsuite/Magento/Framework/Api/Config/ReaderTest.php
index 351a0ba03144a218481d9ab798cca18989ca8db8..07fceddb6424b3bc01d7e4448833cb92a709d6c9 100644
--- a/dev/tests/integration/testsuite/Magento/Framework/Api/Config/ReaderTest.php
+++ b/dev/tests/integration/testsuite/Magento/Framework/Api/Config/ReaderTest.php
@@ -76,12 +76,24 @@ class ReaderTest extends \PHPUnit_Framework_TestCase
         $expectedArray = [
             'Magento\Tax\Api\Data\TaxRateInterface' => [],
             'Magento\Catalog\Api\Data\Product' => [
-                'stock_item' => "Magento\CatalogInventory\Api\Data\StockItem",
+                'stock_item' => [
+                    "type" => "Magento\CatalogInventory\Api\Data\StockItem",
+                    "resourceRefs" => [],
+                ],
             ],
             'Magento\Customer\Api\Data\CustomerInterface' => [
-                'custom_1' => "Magento\Customer\Api\Data\CustomerCustom",
-                'custom_2' => "Magento\CustomerExtra\Api\Data\CustomerCustom22",
-                'custom_3' => "Magento\Customer\Api\Data\CustomerCustom3",
+                'custom_1' => [
+                    "type" => "Magento\Customer\Api\Data\CustomerCustom",
+                    "resourceRefs" => [],
+                ],
+                'custom_2' => [
+                    "type" => "Magento\CustomerExtra\Api\Data\CustomerCustom22",
+                    "resourceRefs" => [],
+                ],
+                'custom_3' => [
+                    "type" => "Magento\Customer\Api\Data\CustomerCustom3",
+                    "resourceRefs" => [],
+                ],
             ],
         ];
 
diff --git a/dev/tests/integration/testsuite/Magento/Framework/Api/Config/_files/config_one.xml b/dev/tests/integration/testsuite/Magento/Framework/Api/Config/_files/config_one.xml
index f5a3d522454ab487f461f697e6108f118f1769e9..82aa641d5e8bd9040d9fa26689d95a09b74e19f3 100644
--- a/dev/tests/integration/testsuite/Magento/Framework/Api/Config/_files/config_one.xml
+++ b/dev/tests/integration/testsuite/Magento/Framework/Api/Config/_files/config_one.xml
@@ -5,14 +5,14 @@
  * See COPYING.txt for license details.
  */
 -->
-<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../../../lib/internal/Magento/Framework/Api/etc/data_object.xsd">
-    <custom_attributes for="Magento\Tax\Api\Data\TaxRateInterface">
-    </custom_attributes>
-    <custom_attributes for="Magento\Catalog\Api\Data\Product">
+<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../../../lib/internal/Magento/Framework/Api/etc/service_data_attributes.xsd">
+    <extension_attributes for="Magento\Tax\Api\Data\TaxRateInterface">
+    </extension_attributes>
+    <extension_attributes for="Magento\Catalog\Api\Data\Product">
         <attribute code="stock_item" type="Magento\CatalogInventory\Api\Data\StockItem" />
-    </custom_attributes>
-    <custom_attributes for="Magento\Customer\Api\Data\CustomerInterface">
+    </extension_attributes>
+    <extension_attributes for="Magento\Customer\Api\Data\CustomerInterface">
         <attribute code="custom_1" type="Magento\Customer\Api\Data\CustomerCustom" />
         <attribute code="custom_2" type="Magento\CustomerExtra\Service\V1\Data\CustomerCustom21" />
-    </custom_attributes>
+    </extension_attributes>
 </config>
diff --git a/dev/tests/integration/testsuite/Magento/Framework/Api/Config/_files/config_two.xml b/dev/tests/integration/testsuite/Magento/Framework/Api/Config/_files/config_two.xml
index 629efb9b7a30a400dad479894f71d0711da8f24d..5596f61e572f4b076a1d850b38002b6a448a7297 100644
--- a/dev/tests/integration/testsuite/Magento/Framework/Api/Config/_files/config_two.xml
+++ b/dev/tests/integration/testsuite/Magento/Framework/Api/Config/_files/config_two.xml
@@ -5,9 +5,9 @@
  * See COPYING.txt for license details.
  */
 -->
-<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../../../lib/internal/Magento/Framework/Api/etc/data_object.xsd">
-    <custom_attributes for="Magento\Customer\Api\Data\CustomerInterface">
+<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../../../lib/internal/Magento/Framework/Api/etc/service_data_attributes.xsd">
+    <extension_attributes for="Magento\Customer\Api\Data\CustomerInterface">
         <attribute code="custom_2" type="Magento\CustomerExtra\Api\Data\CustomerCustom22" />
         <attribute code="custom_3" type="Magento\Customer\Api\Data\CustomerCustom3" />
-    </custom_attributes>
+    </extension_attributes>
 </config>
diff --git a/dev/tests/unit/framework/bootstrap.php b/dev/tests/unit/framework/bootstrap.php
index b30486b50a17dc3a6e0b67adaa072868b1747736..45ae70bc21fbb39fc79b347cc4749a6243d18d7f 100755
--- a/dev/tests/unit/framework/bootstrap.php
+++ b/dev/tests/unit/framework/bootstrap.php
@@ -6,6 +6,11 @@
 
 require_once __DIR__ . '/../../../../app/autoload.php';
 
+$updateAppBootstrap = __DIR__ . '/../../../../update/app/bootstrap.php';
+if (file_exists($updateAppBootstrap)) {
+    require_once $updateAppBootstrap;
+}
+
 if (!defined('TESTS_TEMP_DIR')) {
     define('TESTS_TEMP_DIR', dirname(__DIR__) . '/tmp');
 }
diff --git a/dev/tests/unit/phpunit.xml.dist b/dev/tests/unit/phpunit.xml.dist
index 5c785e252e48aa8c82aa8bcfe817c761b38ecc23..4c5587187da794847e7e0e6c47157106193a14fd 100644
--- a/dev/tests/unit/phpunit.xml.dist
+++ b/dev/tests/unit/phpunit.xml.dist
@@ -17,6 +17,7 @@
         <directory suffix="Test.php">../../../lib/internal/*/*/Test/Unit</directory>
         <directory suffix="Test.php">../../../lib/internal/*/*/*/Test/Unit</directory>
         <directory suffix="Test.php">../../../setup/src/*/*/Test/Unit</directory>
+        <directory suffix="Test.php">../../../update/dev/tests/unit/testsuite</directory>
     </testsuite>
     <php>
         <ini name="date.timezone" value="America/Los_Angeles"/>
@@ -26,6 +27,7 @@
             <directory suffix=".php">../../../app/code/*</directory>
             <directory suffix=".php">../../../lib/internal/Magento</directory>
             <directory suffix=".php">../../../setup/src/*</directory>
+            <directory suffix=".php">../../../update/app/code/*</directory>
             <exclude>
                 <directory>../../../app/code/*/*/Test</directory>
                 <directory>../../../lib/internal/*/*/Test</directory>
diff --git a/lib/internal/Magento/Framework/Api/Code/Generator/ExtensionAttributesGenerator.php b/lib/internal/Magento/Framework/Api/Code/Generator/ExtensionAttributesGenerator.php
index 98f5dc5d5e07250fe7b427ca68286cb99c22ee35..aa91250b41fb3ce83f95c8d3df94e144c79a9bfb 100644
--- a/lib/internal/Magento/Framework/Api/Code/Generator/ExtensionAttributesGenerator.php
+++ b/lib/internal/Magento/Framework/Api/Code/Generator/ExtensionAttributesGenerator.php
@@ -8,6 +8,7 @@ namespace Magento\Framework\Api\Code\Generator;
 use Magento\Framework\Code\Generator\DefinedClasses;
 use Magento\Framework\Code\Generator\Io;
 use Magento\Framework\Api\SimpleDataObjectConverter;
+use Magento\Framework\Api\Config\Converter;
 
 /**
  * Code generator for data object extensions.
@@ -79,14 +80,15 @@ class ExtensionAttributesGenerator extends \Magento\Framework\Code\Generator\Ent
     protected function _getClassMethods()
     {
         $methods = [];
-        foreach ($this->getCustomAttributes() as $attributeName => $attributeType) {
+        foreach ($this->getCustomAttributes() as $attributeName => $attributeMetadata) {
+            $attributeType = $attributeMetadata[Converter::DATA_TYPE];
             $propertyName = SimpleDataObjectConverter::snakeCaseToCamelCase($attributeName);
             $getterName = 'get' . ucfirst($propertyName);
             $setterName = 'set' . ucfirst($propertyName);
             $methods[] = [
                 'name' => $getterName,
                 'body' => "return \$this->_get('{$attributeName}');",
-                'docblock' => ['tags' => [['name' => 'return', 'description' => $attributeType]]],
+                'docblock' => ['tags' => [['name' => 'return', 'description' => $attributeType . '|null']]],
             ];
             $methods[] = [
                 'name' => $setterName,
@@ -150,11 +152,12 @@ class ExtensionAttributesGenerator extends \Magento\Framework\Code\Generator\Ent
         }
         $dataInterface = ltrim($this->getSourceClassName(), '\\');
         if (isset($this->allCustomAttributes[$dataInterface])) {
-            foreach ($this->allCustomAttributes[$dataInterface] as $attributeName => $attributeType) {
+            foreach ($this->allCustomAttributes[$dataInterface] as $attributeName => $attributeMetadata) {
+                $attributeType = $attributeMetadata[Converter::DATA_TYPE];
                 if (strpos($attributeType, '\\') !== false) {
                     /** Add preceding slash to class names, while leaving primitive types as is */
                     $attributeType = $this->_getFullyQualifiedClassName($attributeType);
-                    $this->allCustomAttributes[$dataInterface][$attributeName] =
+                    $this->allCustomAttributes[$dataInterface][$attributeName][Converter::DATA_TYPE] =
                         $this->_getFullyQualifiedClassName($attributeType);
                 }
             }
diff --git a/lib/internal/Magento/Framework/Api/Config/Converter.php b/lib/internal/Magento/Framework/Api/Config/Converter.php
index f21db3bbd9b224b1c29eaa36be3f6043dcdf4ae9..68914a98b5c77ab1bc452c90fc26dfbee64797d8 100644
--- a/lib/internal/Magento/Framework/Api/Config/Converter.php
+++ b/lib/internal/Magento/Framework/Api/Config/Converter.php
@@ -7,6 +7,9 @@ namespace Magento\Framework\Api\Config;
 
 class Converter implements \Magento\Framework\Config\ConverterInterface
 {
+    const RESOURCE_PERMISSIONS = "resourceRefs";
+    const DATA_TYPE = "type";
+
     /**
      * Convert dom node tree to array
      *
@@ -21,7 +24,7 @@ class Converter implements \Magento\Framework\Config\ConverterInterface
         }
 
         /** @var \DOMNodeList $types */
-        $types = $source->getElementsByTagName('custom_attributes');
+        $types = $source->getElementsByTagName('extension_attributes');
         /** @var \DOMNode $type */
         foreach ($types as $type) {
             $typeConfig = [];
@@ -32,9 +35,22 @@ class Converter implements \Magento\Framework\Config\ConverterInterface
                 $code = $attribute->getAttribute('code');
                 $codeType = $attribute->getAttribute('type');
 
-                if ($code && $codeType) {
-                    $typeConfig[$code] = $codeType;
+                $resourcesElement = $attribute->getElementsByTagName('resources')->item(0);
+                $resourceRefs = [];
+                if ($resourcesElement && $resourcesElement->nodeType === XML_ELEMENT_NODE) {
+                    $singleResourceElements = $resourcesElement->getElementsByTagName('resource');
+                    foreach ($singleResourceElements as $element) {
+                        if ($element->nodeType != XML_ELEMENT_NODE) {
+                            continue;
+                        }
+                        $resourceRefs[] = $element->attributes->getNamedItem('ref')->nodeValue;
+                    }
                 }
+
+                $typeConfig[$code] = [
+                    self::DATA_TYPE => $codeType,
+                    self::RESOURCE_PERMISSIONS => $resourceRefs,
+                ];
             }
 
             $output[$typeName] = $typeConfig;
diff --git a/lib/internal/Magento/Framework/Api/Config/Reader.php b/lib/internal/Magento/Framework/Api/Config/Reader.php
index 8cd1a8ac3293568553c30f0e126ab1ee61b78a38..6bc97c71c11563cfb46efeaaedf2ecd03fd3bf83 100644
--- a/lib/internal/Magento/Framework/Api/Config/Reader.php
+++ b/lib/internal/Magento/Framework/Api/Config/Reader.php
@@ -13,8 +13,8 @@ class Reader extends \Magento\Framework\Config\Reader\Filesystem
      * @var array
      */
     protected $_idAttributes = [
-        '/config/custom_attributes' => 'for',
-        '/config/custom_attributes/attribute' => 'code',
+        '/config/extension_attributes' => 'for',
+        '/config/extension_attributes/attribute' => 'code',
     ];
 
     /**
@@ -32,7 +32,7 @@ class Reader extends \Magento\Framework\Config\Reader\Filesystem
         \Magento\Framework\Api\Config\Converter $converter,
         \Magento\Framework\Api\Config\SchemaLocator $schemaLocator,
         \Magento\Framework\Config\ValidationStateInterface $validationState,
-        $fileName = 'data_object.xml',
+        $fileName = 'service_data_attributes.xml',
         $idAttributes = [],
         $domDocumentClass = 'Magento\Framework\Config\Dom',
         $defaultScope = 'global'
diff --git a/lib/internal/Magento/Framework/Api/Config/SchemaLocator.php b/lib/internal/Magento/Framework/Api/Config/SchemaLocator.php
index 86662ab2528136ecc4c8182d650a55b9e80f0a2f..1e8334c643def347b9392eba52d624b5fdaab556 100644
--- a/lib/internal/Magento/Framework/Api/Config/SchemaLocator.php
+++ b/lib/internal/Magento/Framework/Api/Config/SchemaLocator.php
@@ -16,7 +16,7 @@ class SchemaLocator implements \Magento\Framework\Config\SchemaLocatorInterface
      */
     public function getSchema()
     {
-        return realpath(__DIR__ . '/../etc/data_object.xsd');
+        return realpath(__DIR__ . '/../etc/service_data_attributes.xsd');
     }
 
     /**
diff --git a/lib/internal/Magento/Framework/Api/DataObjectHelper.php b/lib/internal/Magento/Framework/Api/DataObjectHelper.php
index d0a22a194be444bbc4b71f5d60dd6bf29fd1de42..fc3a3b0920c60430f28de95db7cd6a6ab84f6868 100644
--- a/lib/internal/Magento/Framework/Api/DataObjectHelper.php
+++ b/lib/internal/Magento/Framework/Api/DataObjectHelper.php
@@ -6,6 +6,8 @@
 
 namespace Magento\Framework\Api;
 
+use Magento\Framework\Reflection\MethodsMap;
+
 class DataObjectHelper
 {
     /**
@@ -28,22 +30,30 @@ class DataObjectHelper
      */
     protected $extensionFactory;
 
+    /**
+     * @var MethodsMap
+     */
+    protected $methodsMapProcessor;
+
     /**
      * @param ObjectFactory $objectFactory
      * @param \Magento\Framework\Reflection\DataObjectProcessor $objectProcessor
      * @param \Magento\Framework\Reflection\TypeProcessor $typeProcessor
      * @param \Magento\Framework\Api\ExtensionAttributesFactory $extensionFactory
+     * @param MethodsMap $methodsMapProcessor
      */
     public function __construct(
         ObjectFactory $objectFactory,
         \Magento\Framework\Reflection\DataObjectProcessor $objectProcessor,
         \Magento\Framework\Reflection\TypeProcessor $typeProcessor,
-        \Magento\Framework\Api\ExtensionAttributesFactory $extensionFactory
+        \Magento\Framework\Api\ExtensionAttributesFactory $extensionFactory,
+        MethodsMap $methodsMapProcessor
     ) {
         $this->objectFactory = $objectFactory;
         $this->objectProcessor = $objectProcessor;
         $this->typeProcessor = $typeProcessor;
         $this->extensionFactory = $extensionFactory;
+        $this->methodsMapProcessor = $methodsMapProcessor;
     }
 
     /**
@@ -128,7 +138,7 @@ class DataObjectHelper
         if ($interfaceName == null) {
             $interfaceName = get_class($dataObject);
         }
-        $returnType = $this->objectProcessor->getMethodReturnType($interfaceName, $getterMethodName);
+        $returnType = $this->methodsMapProcessor->getMethodReturnType($interfaceName, $getterMethodName);
         if ($this->typeProcessor->isTypeSimple($returnType)) {
             $dataObject->$methodName($value);
             return $this;
diff --git a/lib/internal/Magento/Framework/Api/Test/Unit/Code/Generator/ExtensionAttributesGeneratorTest.php b/lib/internal/Magento/Framework/Api/Test/Unit/Code/Generator/ExtensionAttributesGeneratorTest.php
index 5207a20588c73dcbf83aa767b907f585db8bb114..efdeb4ae914348fa51302891271d018b06c70067 100644
--- a/lib/internal/Magento/Framework/Api/Test/Unit/Code/Generator/ExtensionAttributesGeneratorTest.php
+++ b/lib/internal/Magento/Framework/Api/Test/Unit/Code/Generator/ExtensionAttributesGeneratorTest.php
@@ -6,6 +6,8 @@
 // @codingStandardsIgnoreFile
 namespace Magento\Framework\Api\Test\Unit\Code\Generator;
 
+use Magento\Framework\Api\Config\Converter;
+
 class ExtensionAttributesGeneratorTest extends \PHPUnit_Framework_TestCase
 {
     /**
@@ -44,11 +46,21 @@ class ExtensionAttributesGeneratorTest extends \PHPUnit_Framework_TestCase
             ->willReturn(
                 [
                     'Magento\Catalog\Api\Data\ProductInterface' => [
-                        'string_attribute' => 'string',
-                        'complex_object_attribute' => '\Magento\Bundle\Api\Data\OptionInterface[]'
+                        'string_attribute' => [
+                            Converter::DATA_TYPE => 'string',
+                            Converter::RESOURCE_PERMISSIONS => [],
+
+                        ],
+                        'complex_object_attribute' => [
+                            Converter::DATA_TYPE => '\Magento\Bundle\Api\Data\OptionInterface[]',
+                            Converter::RESOURCE_PERMISSIONS => [],
+                        ],
                     ],
                     'Magento\Catalog\Api\Data\Product' => [
-                        'should_not_include' => 'string',
+                        'should_not_include' => [
+                            Converter::DATA_TYPE => 'string',
+                            Converter::RESOURCE_PERMISSIONS => [],
+                        ],
                     ],
                 ]
             );
diff --git a/lib/internal/Magento/Framework/Api/Test/Unit/Code/Generator/ExtensionAttributesInterfaceGeneratorTest.php b/lib/internal/Magento/Framework/Api/Test/Unit/Code/Generator/ExtensionAttributesInterfaceGeneratorTest.php
index 8f80baf39beeeec1955800e7ea4a51ac12d02382..33d4ecf9e7906c2abd4bfe15ef429c539405b059 100644
--- a/lib/internal/Magento/Framework/Api/Test/Unit/Code/Generator/ExtensionAttributesInterfaceGeneratorTest.php
+++ b/lib/internal/Magento/Framework/Api/Test/Unit/Code/Generator/ExtensionAttributesInterfaceGeneratorTest.php
@@ -6,6 +6,8 @@
 // @codingStandardsIgnoreFile
 namespace Magento\Framework\Api\Test\Unit\Code\Generator;
 
+use Magento\Framework\Api\Config\Converter;
+
 class ExtensionAttributesInterfaceGeneratorTest extends \PHPUnit_Framework_TestCase
 {
     public function testGenerate()
@@ -19,11 +21,20 @@ class ExtensionAttributesInterfaceGeneratorTest extends \PHPUnit_Framework_TestC
             ->willReturn(
                 [
                     'Magento\Catalog\Api\Data\ProductInterface' => [
-                        'string_attribute' => 'string',
-                        'complex_object_attribute' => '\Magento\Bundle\Api\Data\OptionInterface[]'
+                        'string_attribute' => [
+                            Converter::DATA_TYPE => 'string',
+                            Converter::RESOURCE_PERMISSIONS => [],
+                        ],
+                        'complex_object_attribute' => [
+                            Converter::DATA_TYPE => '\Magento\Bundle\Api\Data\OptionInterface[]',
+                            Converter::RESOURCE_PERMISSIONS => [],
+                        ],
                     ],
                     'Magento\Catalog\Api\Data\Product' => [
-                        'should_not_include' => 'string',
+                        'should_not_include' => [
+                            Converter::DATA_TYPE => 'string',
+                            Converter::RESOURCE_PERMISSIONS => [],
+                        ],
                     ],
                 ]
             );
diff --git a/lib/internal/Magento/Framework/Api/Test/Unit/Code/Generator/_files/SampleExtension.txt b/lib/internal/Magento/Framework/Api/Test/Unit/Code/Generator/_files/SampleExtension.txt
index 8b5caad1ecc4456ae51380e25c735be8f2660d37..0f9838bd8736c9c0545b6bb82ab5adbe9762a946 100644
--- a/lib/internal/Magento/Framework/Api/Test/Unit/Code/Generator/_files/SampleExtension.txt
+++ b/lib/internal/Magento/Framework/Api/Test/Unit/Code/Generator/_files/SampleExtension.txt
@@ -6,7 +6,7 @@ namespace Magento\Catalog\Api\Data;
 class ProductExtension extends \Magento\Framework\Api\AbstractSimpleObject implements \Magento\Catalog\Api\Data\ProductExtensionInterface
 {
     /**
-     * @return string
+     * @return string|null
      */
     public function getStringAttribute()
     {
@@ -24,7 +24,7 @@ class ProductExtension extends \Magento\Framework\Api\AbstractSimpleObject imple
     }
 
     /**
-     * @return \Magento\Bundle\Api\Data\OptionInterface[]
+     * @return \Magento\Bundle\Api\Data\OptionInterface[]|null
      */
     public function getComplexObjectAttribute()
     {
diff --git a/lib/internal/Magento/Framework/Api/Test/Unit/Code/Generator/_files/SampleExtensionInterface.txt b/lib/internal/Magento/Framework/Api/Test/Unit/Code/Generator/_files/SampleExtensionInterface.txt
index ec9edd7affc2d68e5444d914b833bff81ccc1d4d..75dde39b2151952b49beb587ce4eecff56418997 100644
--- a/lib/internal/Magento/Framework/Api/Test/Unit/Code/Generator/_files/SampleExtensionInterface.txt
+++ b/lib/internal/Magento/Framework/Api/Test/Unit/Code/Generator/_files/SampleExtensionInterface.txt
@@ -6,7 +6,7 @@ namespace Magento\Catalog\Api\Data;
 interface ProductExtensionInterface extends \Magento\Framework\Api\ExtensionAttributesInterface
 {
     /**
-     * @return string
+     * @return string|null
      */
     public function getStringAttribute();
 
@@ -17,7 +17,7 @@ interface ProductExtensionInterface extends \Magento\Framework\Api\ExtensionAttr
     public function setStringAttribute($stringAttribute);
 
     /**
-     * @return \Magento\Bundle\Api\Data\OptionInterface[]
+     * @return \Magento\Bundle\Api\Data\OptionInterface[]|null
      */
     public function getComplexObjectAttribute();
 
diff --git a/lib/internal/Magento/Framework/Api/Test/Unit/Config/ConverterTest.php b/lib/internal/Magento/Framework/Api/Test/Unit/Config/ConverterTest.php
index 94f5a4494a75dd9c57afa409c90eb622ad26827c..d4629213b20be2d7bbca2ff16bacf0b36de608e5 100644
--- a/lib/internal/Magento/Framework/Api/Test/Unit/Config/ConverterTest.php
+++ b/lib/internal/Magento/Framework/Api/Test/Unit/Config/ConverterTest.php
@@ -5,6 +5,8 @@
  */
 namespace Magento\Framework\Api\Test\Unit\Config;
 
+use Magento\Framework\Api\Config\Converter;
+
 class ConverterTest extends \PHPUnit_Framework_TestCase
 {
     /**
@@ -47,15 +49,39 @@ class ConverterTest extends \PHPUnit_Framework_TestCase
             'Magento\Tax\Api\Data\TaxRateInterface' => [
             ],
             'Magento\Catalog\Api\Data\ProductInterface' => [
-                'stock_item' => 'Magento\CatalogInventory\Api\Data\StockItemInterface'
+                'stock_item' => [
+                    Converter::DATA_TYPE => 'Magento\CatalogInventory\Api\Data\StockItemInterface',
+                    Converter::RESOURCE_PERMISSIONS => [],
+                ],
             ],
             'Magento\Customer\Api\Data\CustomerInterface' => [
-                'custom_1' => 'Magento\Customer\Api\Data\CustomerCustom',
-                'custom_2' => 'Magento\CustomerExtra\Api\Data\CustomerCustom2'
+                'custom_1' => [
+                    Converter::DATA_TYPE => 'Magento\Customer\Api\Data\CustomerCustom',
+                    Converter::RESOURCE_PERMISSIONS => [],
+                ],
+                'custom_2' => [
+                    Converter::DATA_TYPE => 'Magento\CustomerExtra\Api\Data\CustomerCustom2',
+                    Converter::RESOURCE_PERMISSIONS => [],
+                ],
+            ],
+            'Magento\Customer\Api\Data\CustomerInterface2' => [
+                'custom_with_permission' => [
+                    Converter::DATA_TYPE => 'Magento\Customer\Api\Data\CustomerCustom',
+                    Converter::RESOURCE_PERMISSIONS => [
+                        'Magento_Customer::manage',
+                    ],
+                ],
+                'custom_with_multiple_permissions' => [
+                    Converter::DATA_TYPE => 'Magento\CustomerExtra\Api\Data\CustomerCustom2',
+                    Converter::RESOURCE_PERMISSIONS => [
+                        'Magento_Customer::manage',
+                        'Magento_Customer::manage2',
+                    ],
+                ],
             ],
         ];
 
-        $xmlFile = __DIR__ . '/_files/data_object_valid.xml';
+        $xmlFile = __DIR__ . '/_files/service_data_attributes.xml';
         $dom = new \DOMDocument();
         $dom->loadXML(file_get_contents($xmlFile));
         $result = $this->_converter->convert($dom);
diff --git a/lib/internal/Magento/Framework/Api/Test/Unit/Config/SchemaLocatorTest.php b/lib/internal/Magento/Framework/Api/Test/Unit/Config/SchemaLocatorTest.php
index f0df38d59a070958d77d6ddccb0d339162d256da..f05583db0490194e949261bce0a2c176932dbdb5 100644
--- a/lib/internal/Magento/Framework/Api/Test/Unit/Config/SchemaLocatorTest.php
+++ b/lib/internal/Magento/Framework/Api/Test/Unit/Config/SchemaLocatorTest.php
@@ -22,7 +22,7 @@ class SchemaLocatorTest extends \PHPUnit_Framework_TestCase
 
     public function testGetSchema()
     {
-        $expected = str_replace('\\', '/', BP . '/lib/internal/Magento/Framework/Api/etc/data_object.xsd');
+        $expected = str_replace('\\', '/', BP . '/lib/internal/Magento/Framework/Api/etc/service_data_attributes.xsd');
         $actual = str_replace('\\', '/', $this->_model->getSchema());
         $this->assertEquals($expected, $actual);
     }
@@ -30,7 +30,7 @@ class SchemaLocatorTest extends \PHPUnit_Framework_TestCase
     public function testGetPerFileSchema()
     {
         $actual = str_replace('\\', '/', $this->_model->getPerFileSchema());
-        $expected = str_replace('\\', '/', BP . '/lib/internal/Magento/Framework/Api/etc/data_object.xsd');
+        $expected = str_replace('\\', '/', BP . '/lib/internal/Magento/Framework/Api/etc/service_data_attributes.xsd');
         $this->assertEquals($expected, $actual);
     }
 }
diff --git a/lib/internal/Magento/Framework/Api/Test/Unit/Config/_files/data_object_valid.xml b/lib/internal/Magento/Framework/Api/Test/Unit/Config/_files/data_object_valid.xml
deleted file mode 100644
index 67606deab2eb46e78dc3022a723b41a1bb25bfa3..0000000000000000000000000000000000000000
--- a/lib/internal/Magento/Framework/Api/Test/Unit/Config/_files/data_object_valid.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0"?>
-<!--
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
--->
-<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../../../lib/internal/Magento/Framework/Api/etc/data_object.xsd">
-    <custom_attributes for="Magento\Tax\Api\Data\TaxRateInterface">
-    </custom_attributes>
-    <custom_attributes for="Magento\Catalog\Api\Data\ProductInterface">
-        <attribute code="stock_item" type="Magento\CatalogInventory\Api\Data\StockItemInterface" />
-    </custom_attributes>
-    <custom_attributes for="Magento\Customer\Api\Data\CustomerInterface">
-        <attribute code="custom_1" type="Magento\Customer\Api\Data\CustomerCustom" />
-        <attribute code="custom_2" type="Magento\CustomerExtra\Api\Data\CustomerCustom2" />
-    </custom_attributes>
-</config>
diff --git a/lib/internal/Magento/Framework/Api/Test/Unit/Config/_files/service_data_attributes.xml b/lib/internal/Magento/Framework/Api/Test/Unit/Config/_files/service_data_attributes.xml
new file mode 100644
index 0000000000000000000000000000000000000000..4f6a9838bfcdb6bd9dbfa20b18ffcfde80bd625d
--- /dev/null
+++ b/lib/internal/Magento/Framework/Api/Test/Unit/Config/_files/service_data_attributes.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+<!--
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+-->
+<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../../../lib/internal/Magento/Framework/Api/etc/service_data_attributes.xsd">
+    <extension_attributes for="Magento\Tax\Api\Data\TaxRateInterface">
+    </extension_attributes>
+    <extension_attributes for="Magento\Catalog\Api\Data\ProductInterface">
+        <attribute code="stock_item" type="Magento\CatalogInventory\Api\Data\StockItemInterface" />
+    </extension_attributes>
+    <extension_attributes for="Magento\Customer\Api\Data\CustomerInterface">
+        <attribute code="custom_1" type="Magento\Customer\Api\Data\CustomerCustom" />
+        <attribute code="custom_2" type="Magento\CustomerExtra\Api\Data\CustomerCustom2" />
+    </extension_attributes>
+    <extension_attributes for="Magento\Customer\Api\Data\CustomerInterface2">
+        <attribute code="custom_with_permission" type="Magento\Customer\Api\Data\CustomerCustom">
+            <resources>
+                <resource ref="Magento_Customer::manage"/>
+            </resources>
+        </attribute>
+        <attribute code="custom_with_multiple_permissions" type="Magento\CustomerExtra\Api\Data\CustomerCustom2">
+            <resources>
+                <resource ref="Magento_Customer::manage"/>
+                <resource ref="Magento_Customer::manage2"/>
+            </resources>
+        </attribute>
+    </extension_attributes>
+</config>
diff --git a/lib/internal/Magento/Framework/Api/Test/Unit/DataObjectHelperTest.php b/lib/internal/Magento/Framework/Api/Test/Unit/DataObjectHelperTest.php
index ff229abd7d22e9be0f810da4034336e5e9631f63..65c7cb906d1f2f15b8f251145633cdb6e85848c5 100644
--- a/lib/internal/Magento/Framework/Api/Test/Unit/DataObjectHelperTest.php
+++ b/lib/internal/Magento/Framework/Api/Test/Unit/DataObjectHelperTest.php
@@ -43,6 +43,11 @@ class DataObjectHelperTest extends \PHPUnit_Framework_TestCase
      */
     protected $attributeValueFactoryMock;
 
+    /**
+     * @var \Magento\Framework\Reflection\MethodsMap|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $methodsMapProcessor;
+
     public function setUp()
     {
         $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
@@ -53,6 +58,9 @@ class DataObjectHelperTest extends \PHPUnit_Framework_TestCase
         $this->objectProcessorMock = $this->getMockBuilder('\Magento\Framework\Reflection\DataObjectProcessor')
             ->disableOriginalConstructor()
             ->getMock();
+        $this->methodsMapProcessor = $this->getMockBuilder('\Magento\Framework\Reflection\MethodsMap')
+            ->disableOriginalConstructor()
+            ->getMock();
         $this->attributeValueFactoryMock = $this->getMockBuilder('\Magento\Framework\Api\AttributeValueFactory')
             ->disableOriginalConstructor()
             ->getMock();
@@ -63,6 +71,7 @@ class DataObjectHelperTest extends \PHPUnit_Framework_TestCase
                 'objectFactory' => $this->objectFactoryMock,
                 'typeProcessor' => $this->typeProcessor,
                 'objectProcessor' => $this->objectProcessorMock,
+                'methodsMapProcessor' => $this->methodsMapProcessor,
             ]
         );
     }
@@ -103,11 +112,11 @@ class DataObjectHelperTest extends \PHPUnit_Framework_TestCase
             ],
         ];
 
-        $this->objectProcessorMock->expects($this->at(0))
+        $this->methodsMapProcessor->expects($this->at(0))
             ->method('getMethodReturnType')
             ->with('\Magento\Customer\Api\Data\AddressInterface', 'getStreet')
             ->willReturn('string[]');
-        $this->objectProcessorMock->expects($this->at(1))
+        $this->methodsMapProcessor->expects($this->at(1))
             ->method('getMethodReturnType')
             ->with('\Magento\Customer\Api\Data\AddressInterface', 'getRegion')
             ->willReturn('\Magento\Customer\Api\Data\RegionInterface');
@@ -317,11 +326,11 @@ class DataObjectHelperTest extends \PHPUnit_Framework_TestCase
             ->method('buildOutputDataArray')
             ->with($secondAddressDataObject, get_class($firstAddressDataObject))
             ->willReturn($data2);
-        $this->objectProcessorMock->expects($this->at(1))
+        $this->methodsMapProcessor->expects($this->at(0))
             ->method('getMethodReturnType')
             ->with('Magento\Customer\Model\Data\Address', 'getStreet')
             ->willReturn('string[]');
-        $this->objectProcessorMock->expects($this->at(2))
+        $this->methodsMapProcessor->expects($this->at(1))
             ->method('getMethodReturnType')
             ->with('Magento\Customer\Model\Data\Address', 'getRegion')
             ->willReturn('\Magento\Customer\Api\Data\RegionInterface');
diff --git a/lib/internal/Magento/Framework/Api/etc/data_object.xsd b/lib/internal/Magento/Framework/Api/etc/data_object.xsd
deleted file mode 100644
index 0983dbbf912385c5a83dd1b8db18d768071c42fc..0000000000000000000000000000000000000000
--- a/lib/internal/Magento/Framework/Api/etc/data_object.xsd
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
--->
-<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
-  <xs:element name="config">
-      <xs:complexType>
-          <xs:sequence>
-              <xs:element name="custom_attributes" type="custom_attributesType" minOccurs="1" maxOccurs="unbounded">
-                  <xs:annotation>
-                      <xs:documentation>Main schema element. Extended Attributes</xs:documentation>
-                  </xs:annotation>
-              </xs:element>
-          </xs:sequence>
-      </xs:complexType>
-  </xs:element>
-  <xs:complexType name="attributeType">
-    <xs:simpleContent>
-      <xs:extension base="xs:string">
-        <xs:attribute type="xs:string" name="code" use="required"/>
-        <xs:attribute type="xs:string" name="type" use="required"/>
-      </xs:extension>
-    </xs:simpleContent>
-  </xs:complexType>
-  <xs:complexType name="custom_attributesType">
-    <xs:sequence>
-      <xs:element type="attributeType" name="attribute" minOccurs="0" maxOccurs="unbounded"/>
-    </xs:sequence>
-    <xs:attribute type="xs:string" name="for" use="required"/>
-  </xs:complexType>
-</xs:schema>
diff --git a/lib/internal/Magento/Framework/Api/etc/service_data_attributes.xsd b/lib/internal/Magento/Framework/Api/etc/service_data_attributes.xsd
new file mode 100644
index 0000000000000000000000000000000000000000..24590e3d758c79afeef7ce85c8cb9f6547e6f524
--- /dev/null
+++ b/lib/internal/Magento/Framework/Api/etc/service_data_attributes.xsd
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+-->
+<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified"
+           xmlns:xs="http://www.w3.org/2001/XMLSchema">
+    <xs:element name="config">
+        <xs:complexType>
+            <xs:sequence>
+                <xs:element name="extension_attributes" type="extension_attributesType" minOccurs="1"
+                            maxOccurs="unbounded">
+                    <xs:annotation>
+                        <xs:documentation>Main schema element. Extended Attributes</xs:documentation>
+                    </xs:annotation>
+                </xs:element>
+            </xs:sequence>
+        </xs:complexType>
+    </xs:element>
+    <xs:complexType name="attributeType">
+        <xs:sequence>
+            <xs:element name="resources" type="resourcesType" minOccurs="0" maxOccurs="unbounded"/>
+        </xs:sequence>
+        <xs:attribute type="xs:string" name="code" use="required"/>
+        <xs:attribute type="xs:string" name="type" use="required"/>
+    </xs:complexType>
+    <xs:complexType name="extension_attributesType">
+        <xs:sequence>
+            <xs:element type="attributeType" name="attribute" minOccurs="0" maxOccurs="unbounded"/>
+        </xs:sequence>
+        <xs:attribute type="xs:string" name="for" use="required"/>
+    </xs:complexType>
+    <xs:complexType name="resourcesType">
+        <xs:sequence>
+            <xs:element name="resource" type="resourceType" maxOccurs="unbounded"/>
+        </xs:sequence>
+    </xs:complexType>
+    <xs:complexType name="resourceType">
+        <xs:attribute name="ref" use="required">
+            <xs:simpleType>
+                <xs:restriction base="xs:string">
+                    <xs:pattern value=".+(, ?.+)*"/>
+                </xs:restriction>
+            </xs:simpleType>
+        </xs:attribute>
+    </xs:complexType>
+</xs:schema>
diff --git a/lib/internal/Magento/Framework/Reflection/CustomAttributesProcessor.php b/lib/internal/Magento/Framework/Reflection/CustomAttributesProcessor.php
new file mode 100644
index 0000000000000000000000000000000000000000..0a98c9e39e8c2f135b962bfbf0ef51d44924c183
--- /dev/null
+++ b/lib/internal/Magento/Framework/Reflection/CustomAttributesProcessor.php
@@ -0,0 +1,99 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Framework\Reflection;
+
+use Magento\Framework\Phrase;
+use Magento\Framework\Api\AttributeInterface;
+use Magento\Framework\Api\AttributeValue;
+use Magento\Framework\Api\SimpleDataObjectConverter;
+use Zend\Code\Reflection\MethodReflection;
+use Magento\Framework\Api\CustomAttributesDataInterface;
+use Magento\Framework\Api\AttributeTypeResolverInterface;
+
+/**
+ * Processes custom attributes and produces an array for the data.
+ */
+class CustomAttributesProcessor
+{
+    /**
+     * @var DataObjectProcessor
+     */
+    private $dataObjectProcessor;
+
+    /**
+     * @var AttributeTypeResolverInterface
+     */
+    private $attributeTypeResolver;
+
+    /**
+     * @param DataObjectProcessor $dataObjectProcessor
+     * @param AttributeTypeResolverInterface $typeResolver
+     */
+    public function __construct(
+        DataObjectProcessor $dataObjectProcessor,
+        AttributeTypeResolverInterface $typeResolver
+    ) {
+        $this->dataObjectProcessor = $dataObjectProcessor;
+        $this->attributeTypeResolver = $typeResolver;
+    }
+
+    /**
+     * Writes out the custom attributes for a given object into an array.
+     *
+     * @param CustomAttributesDataInterface $objectWithCustomAttributes
+     * @param string $dataObjectType
+     * @return array
+     */
+    public function buildOutputDataArray(CustomAttributesDataInterface $objectWithCustomAttributes, $dataObjectType)
+    {
+        $customAttributes = $objectWithCustomAttributes->getCustomAttributes();
+        $result = [];
+        foreach ($customAttributes as $customAttribute) {
+            $result[] = $this->convertCustomAttribute($customAttribute, $dataObjectType);
+        }
+        return $result;
+    }
+
+    /**
+     * Convert custom_attribute object to use flat array structure
+     *
+     * @param AttributeInterface $customAttribute
+     * @param string $dataObjectType
+     * @return array
+     */
+    private function convertCustomAttribute(AttributeInterface $customAttribute, $dataObjectType)
+    {
+        $data = [];
+        $data[AttributeValue::ATTRIBUTE_CODE] = $customAttribute->getAttributeCode();
+        $value = $customAttribute->getValue();
+        if (is_object($value)) {
+            $type = $this->attributeTypeResolver->resolveObjectType(
+                $customAttribute->getAttributeCode(),
+                $value,
+                $dataObjectType
+            );
+            $value = $this->dataObjectProcessor->buildOutputDataArray($value, $type);
+        } elseif (is_array($value)) {
+            $valueResult = [];
+            foreach ($value as $singleValue) {
+                if (is_object($singleValue)) {
+                    $type = $this->attributeTypeResolver->resolveObjectType(
+                        $customAttribute->getAttributeCode(),
+                        $singleValue,
+                        $dataObjectType
+                    );
+                    $singleValue = $this->dataObjectProcessor->buildOutputDataArray($singleValue, $type);
+                }
+                // Cannot cast to a type because the type is unknown
+                $valueResult[] = $singleValue;
+            }
+            $value = $valueResult;
+        }
+        $data[AttributeValue::VALUE] = $value;
+        return $data;
+    }
+}
diff --git a/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php b/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php
index 2b9977d7355f565e808b15cc539c7c892f38afa6..4adceb83c7720be26a310fe8d7dea3f19726219c 100644
--- a/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php
+++ b/lib/internal/Magento/Framework/Reflection/DataObjectProcessor.php
@@ -14,54 +14,54 @@ use Zend\Code\Reflection\ClassReflection;
 use Zend\Code\Reflection\MethodReflection;
 
 /**
- * Data object processor for de-serialization using class reflection
+ * Data object processor for array serialization using class reflection
  */
 class DataObjectProcessor
 {
-    const IS_METHOD_PREFIX = 'is';
-    const HAS_METHOD_PREFIX = 'has';
-    const GETTER_PREFIX = 'get';
-    const SERVICE_INTERFACE_METHODS_CACHE_PREFIX = 'serviceInterfaceMethodsMap';
-    const BASE_MODEL_CLASS = 'Magento\Framework\Model\AbstractExtensibleModel';
-
     /**
-     * @var \Magento\Framework\Cache\FrontendInterface
+     * @var MethodsMap
      */
-    protected $cache;
+    private $methodsMapProcessor;
 
     /**
-     * @var TypeProcessor
+     * @var TypeCaster
      */
-    protected $typeProcessor;
+    private $typeCaster;
 
     /**
-     * @var array
+     * @var FieldNamer
      */
-    protected $dataInterfaceMethodsMap = [];
+    private $fieldNamer;
 
     /**
-     * @var array
+     * @var ExtensionAttributesProcessor
      */
-    protected $serviceInterfaceMethodsMap = [];
+    private $extensionAttributesProcessor;
 
     /**
-     * @var \Magento\Framework\Api\AttributeTypeResolverInterface
+     * @var CustomAttributesProcessor
      */
-    protected $attributeTypeResolver;
+    private $customAttributesProcessor;
 
     /**
-     * @param \Magento\Framework\Cache\FrontendInterface $cache
-     * @param TypeProcessor $typeProcessor
-     * @param \Magento\Framework\Api\AttributeTypeResolverInterface $typeResolver
+     * @param MethodsMap $methodsMapProcessor
+     * @param TypeCaster $typeCaster
+     * @param FieldNamer $fieldNamer
+     * @param CustomAttributesProcessor $customAttributesProcessor
+     * @param ExtensionAttributesProcessor $extensionAttributesProcessor
      */
     public function __construct(
-        \Magento\Framework\Cache\FrontendInterface $cache,
-        TypeProcessor $typeProcessor,
-        \Magento\Framework\Api\AttributeTypeResolverInterface $typeResolver
+        MethodsMap $methodsMapProcessor,
+        TypeCaster $typeCaster,
+        FieldNamer $fieldNamer,
+        CustomAttributesProcessor $customAttributesProcessor,
+        ExtensionAttributesProcessor $extensionAttributesProcessor
     ) {
-        $this->cache = $cache;
-        $this->typeProcessor = $typeProcessor;
-        $this->attributeTypeResolver = $typeResolver;
+        $this->methodsMapProcessor = $methodsMapProcessor;
+        $this->typeCaster = $typeCaster;
+        $this->fieldNamer = $fieldNamer;
+        $this->extensionAttributesProcessor = $extensionAttributesProcessor;
+        $this->customAttributesProcessor = $customAttributesProcessor;
     }
 
     /**
@@ -74,43 +74,36 @@ class DataObjectProcessor
      */
     public function buildOutputDataArray($dataObject, $dataObjectType)
     {
-        $methods = $this->getMethodsMap($dataObjectType);
+        $methods = $this->methodsMapProcessor->getMethodsMap($dataObjectType);
         $outputData = [];
 
         /** @var MethodReflection $method */
-        foreach ($methods as $methodName => $methodReflectionData) {
-            // any method with parameter(s) gets ignored because we do not know the type and value of
-            // the parameter(s), so we are not able to process
-            if ($methodReflectionData['parameterCount'] > 0) {
+        foreach (array_keys($methods) as $methodName) {
+            if (!$this->methodsMapProcessor->isMethodValidForDataField($dataObjectType, $methodName)) {
                 continue;
             }
-            $returnType = $methodReflectionData['type'];
-            if (substr($methodName, 0, 2) === self::IS_METHOD_PREFIX) {
-                $value = $dataObject->{$methodName}();
-                if ($value === null && !$methodReflectionData['isRequired']) {
-                    continue;
-                }
-                $key = SimpleDataObjectConverter::camelCaseToSnakeCase(substr($methodName, 2));
-                $outputData[$key] = $this->castValueToType($value, $returnType);
-            } elseif (substr($methodName, 0, 3) === self::HAS_METHOD_PREFIX) {
-                $value = $dataObject->{$methodName}();
-                if ($value === null && !$methodReflectionData['isRequired']) {
-                    continue;
-                }
-                $key = SimpleDataObjectConverter::camelCaseToSnakeCase(substr($methodName, 3));
-                $outputData[$key] = $this->castValueToType($value, $returnType);
-            } elseif (substr($methodName, 0, 3) === self::GETTER_PREFIX) {
-                $value = $dataObject->{$methodName}();
-                if ($methodName === 'getCustomAttributes' && $value === []) {
-                    continue;
-                }
-                if ($value === null && !$methodReflectionData['isRequired']) {
-                    continue;
-                }
-                $key = SimpleDataObjectConverter::camelCaseToSnakeCase(substr($methodName, 3));
-                if ($key === CustomAttributesDataInterface::CUSTOM_ATTRIBUTES) {
-                    $value = $this->convertCustomAttributes($value, $dataObjectType);
-                } elseif (is_object($value) && !($value instanceof Phrase)) {
+
+            $value = $dataObject->{$methodName}();
+            $isMethodReturnValueRequired = $this->methodsMapProcessor->isMethodReturnValueRequired(
+                $dataObjectType,
+                $methodName
+            );
+            if ($value === null && !$isMethodReturnValueRequired) {
+                continue;
+            }
+
+            $returnType = $this->methodsMapProcessor->getMethodReturnType($dataObjectType, $methodName);
+            $key = $this->fieldNamer->getFieldNameForMethodName($methodName);
+            if ($key === CustomAttributesDataInterface::CUSTOM_ATTRIBUTES && $value === []) {
+                continue;
+            }
+
+            if ($key === CustomAttributesDataInterface::CUSTOM_ATTRIBUTES) {
+                $value = $this->customAttributesProcessor->buildOutputDataArray($dataObject, $dataObjectType);
+            } elseif ($key === "extension_attributes") {
+                $value = $this->extensionAttributesProcessor->buildOutputDataArray($value, $returnType);
+            } else {
+                if (is_object($value) && !($value instanceof Phrase)) {
                     $value = $this->buildOutputDataArray($value, $returnType);
                 } elseif (is_array($value)) {
                     $valueResult = [];
@@ -119,192 +112,16 @@ class DataObjectProcessor
                         if (is_object($singleValue) && !($singleValue instanceof Phrase)) {
                             $singleValue = $this->buildOutputDataArray($singleValue, $arrayElementType);
                         }
-                        $valueResult[] = $this->castValueToType($singleValue, $arrayElementType);
+                        $valueResult[] = $this->typeCaster->castValueToType($singleValue, $arrayElementType);
                     }
                     $value = $valueResult;
+                } else {
+                    $value = $this->typeCaster->castValueToType($value, $returnType);
                 }
-                $outputData[$key] = $this->castValueToType($value, $returnType);
             }
-        }
-        return $outputData;
-    }
 
-    /**
-     * Cast the output type to the documented type. This helps for output purposes.
-     *
-     * @param mixed $value
-     * @param string $type
-     * @return mixed
-     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
-     * @SuppressWarnings(PHPMD.NPathComplexity)
-     */
-    protected function castValueToType($value, $type)
-    {
-        if ($value === null) {
-            return null;
+            $outputData[$key] = $value;
         }
-
-        if ($type === "int" || $type === "integer") {
-            return (int)$value;
-        }
-
-        if ($type === "string") {
-            return (string)$value;
-        }
-
-        if ($type === "bool" || $type === "boolean" || $type === "true" || $type == "false") {
-            return (bool)$value;
-        }
-
-        if ($type === "float") {
-            return (float)$value;
-        }
-
-        if ($type === "double") {
-            return (double)$value;
-        }
-
-        return $value;
-    }
-
-    /**
-     * Get return type by interface name and method
-     *
-     * @param string $interfaceName
-     * @param string $methodName
-     * @return string
-     */
-    public function getMethodReturnType($interfaceName, $methodName)
-    {
-        return $this->getMethodsMap($interfaceName)[$methodName]['type'];
-    }
-
-    /**
-     * Convert array of custom_attributes to use flat array structure
-     *
-     * @param \Magento\Framework\Api\AttributeInterface[] $customAttributes
-     * @param string $dataObjectType
-     * @return array
-     */
-    protected function convertCustomAttributes($customAttributes, $dataObjectType)
-    {
-        $result = [];
-        foreach ((array)$customAttributes as $customAttribute) {
-            $result[] = $this->convertCustomAttribute($customAttribute, $dataObjectType);
-        }
-        return $result;
-    }
-
-    /**
-     * Convert custom_attribute object to use flat array structure
-     *
-     * @param \Magento\Framework\Api\AttributeInterface $customAttribute
-     * @param string $dataObjectType
-     * @return array
-     */
-    protected function convertCustomAttribute($customAttribute, $dataObjectType)
-    {
-        $data = [];
-        $data[AttributeValue::ATTRIBUTE_CODE] = $customAttribute->getAttributeCode();
-        $value = $customAttribute->getValue();
-        if (is_object($value)) {
-            $type = $this->attributeTypeResolver->resolveObjectType(
-                $customAttribute->getAttributeCode(),
-                $value,
-                $dataObjectType
-            );
-            $value = $this->buildOutputDataArray($value, $type);
-        } elseif (is_array($value)) {
-            $valueResult = [];
-            foreach ($value as $singleValue) {
-                if (is_object($singleValue)) {
-                    $type = $this->attributeTypeResolver->resolveObjectType(
-                        $customAttribute->getAttributeCode(),
-                        $singleValue,
-                        $dataObjectType
-                    );
-                    $singleValue = $this->buildOutputDataArray($singleValue, $type);
-                }
-                // Cannot cast to a type because the type is unknown
-                $valueResult[] = $singleValue;
-            }
-            $value = $valueResult;
-        }
-        $data[AttributeValue::VALUE] = $value;
-        return $data;
-    }
-
-    /**
-     * Return service interface or Data interface methods loaded from cache
-     *
-     * @param string $interfaceName
-     * @return array
-     * <pre>
-     * Service methods' reflection data stored in cache as 'methodName' => 'returnType'
-     * ex.
-     * [
-     *  'create' => '\Magento\Customer\Api\Data\Customer',
-     *  'validatePassword' => 'boolean'
-     * ]
-     * </pre>
-     */
-    public function getMethodsMap($interfaceName)
-    {
-        $key = self::SERVICE_INTERFACE_METHODS_CACHE_PREFIX . "-" . md5($interfaceName);
-        if (!isset($this->serviceInterfaceMethodsMap[$key])) {
-            $methodMap = $this->cache->load($key);
-            if ($methodMap) {
-                $this->serviceInterfaceMethodsMap[$key] = unserialize($methodMap);
-            } else {
-                $methodMap = $this->getMethodMapViaReflection($interfaceName);
-                $this->serviceInterfaceMethodsMap[$key] = $methodMap;
-                $this->cache->save(serialize($this->serviceInterfaceMethodsMap[$key]), $key);
-            }
-        }
-        return $this->serviceInterfaceMethodsMap[$key];
-    }
-
-    /**
-     * Use reflection to load the method information
-     *
-     * @param string $interfaceName
-     * @return array
-     */
-    protected function getMethodMapViaReflection($interfaceName)
-    {
-        $methodMap = [];
-        $class = new ClassReflection($interfaceName);
-        $baseClassMethods = false;
-        foreach ($class->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
-            // Include all the methods of classes inheriting from AbstractExtensibleObject.
-            // Ignore all the methods of AbstractExtensibleModel's parent classes
-            if ($method->class === self::BASE_MODEL_CLASS) {
-                $baseClassMethods = true;
-            } elseif ($baseClassMethods) {
-                // ReflectionClass::getMethods() sorts the methods by class (lowest in inheritance tree first)
-                // then by the order they are defined in the class definition
-                break;
-            }
-
-            if ($this->isSuitableMethod($method)) {
-                $methodMap[$method->getName()] = $this->typeProcessor->getGetterReturnType($method);
-            }
-        }
-        return $methodMap;
-    }
-
-    /**
-     * Determines if the method is suitable to be used by the processor.
-     *
-     * @param \ReflectionMethod $method
-     * @return bool
-     */
-    protected function isSuitableMethod($method)
-    {
-        $isSuitableMethodType = !($method->isConstructor() || $method->isFinal()
-            || $method->isStatic() || $method->isDestructor());
-
-        $isExcludedMagicMethod = strpos($method->getName(), '__') === 0;
-        return $isSuitableMethodType && !$isExcludedMagicMethod;
+        return $outputData;
     }
 }
diff --git a/lib/internal/Magento/Framework/Reflection/ExtensionAttributesProcessor.php b/lib/internal/Magento/Framework/Reflection/ExtensionAttributesProcessor.php
new file mode 100644
index 0000000000000000000000000000000000000000..c2d2d69c758f8b4676da91027080fb5736d5c880
--- /dev/null
+++ b/lib/internal/Magento/Framework/Reflection/ExtensionAttributesProcessor.php
@@ -0,0 +1,189 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Framework\Reflection;
+
+use Magento\Framework\Api\Config\Reader as ExtensionAttributesConfigReader;
+use Magento\Framework\Api\Config\Converter;
+use Magento\Framework\AuthorizationInterface;
+use Magento\Framework\Phrase;
+use Magento\Framework\Api\SimpleDataObjectConverter;
+use Magento\Framework\Api\ExtensionAttributesInterface;
+use Magento\Framework\Reflection\MethodsMap;
+use Zend\Code\Reflection\MethodReflection;
+
+/**
+ * Processes extension attributes and produces an array for the data.
+ */
+class ExtensionAttributesProcessor
+{
+    /**
+     * @var DataObjectProcessor
+     */
+    private $dataObjectProcessor;
+
+    /**
+     * @var MethodsMap
+     */
+    private $methodsMapProcessor;
+
+    /**
+     * @var AuthorizationInterface
+     */
+    private $authorization;
+
+    /**
+     * @var ExtensionAttributesConfigReader
+     */
+    private $configReader;
+
+    /**
+     * @var bool
+     */
+    private $isPermissionChecked;
+
+    /**
+     * @var FieldNamer
+     */
+    private $fieldNamer;
+
+    /**
+     * @var TypeCaster
+     */
+    private $typeCaster;
+
+    /**
+     * @param DataObjectProcessor $dataObjectProcessor
+     * @param MethodsMap $methodsMapProcessor
+     * @param TypeCaster $typeCaster
+     * @param FieldNamer $fieldNamer
+     * @param AuthorizationInterface $authorization
+     * @param ExtensionAttributesConfigReader $configReader
+     * @param bool $isPermissionChecked
+     */
+    public function __construct(
+        DataObjectProcessor $dataObjectProcessor,
+        MethodsMap $methodsMapProcessor,
+        TypeCaster $typeCaster,
+        FieldNamer $fieldNamer,
+        AuthorizationInterface $authorization,
+        ExtensionAttributesConfigReader $configReader,
+        $isPermissionChecked = false
+    ) {
+        $this->dataObjectProcessor = $dataObjectProcessor;
+        $this->methodsMapProcessor = $methodsMapProcessor;
+        $this->typeCaster = $typeCaster;
+        $this->fieldNamer = $fieldNamer;
+        $this->authorization = $authorization;
+        $this->configReader = $configReader;
+        $this->isPermissionChecked = $isPermissionChecked;
+    }
+
+    /**
+     * Writes out the extension attributes in an array.
+     *
+     * @param ExtensionAttributeInterface $dataObject
+     * @param string $dataObjectType
+     * @return array
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+     */
+    public function buildOutputDataArray(ExtensionAttributesInterface $dataObject, $dataObjectType)
+    {
+        $methods = $this->methodsMapProcessor->getMethodsMap($dataObjectType);
+        $outputData = [];
+
+        /** @var MethodReflection $method */
+        foreach (array_keys($methods) as $methodName) {
+            if (!$this->methodsMapProcessor->isMethodValidForDataField($dataObjectType, $methodName)) {
+                continue;
+            }
+
+            $key = $this->fieldNamer->getFieldNameForMethodName($methodName);
+            if ($this->isPermissionChecked && !$this->isAttributePermissionValid($dataObjectType, $key)) {
+                continue;
+            }
+
+            $value = $dataObject->{$methodName}();
+            if ($value === null) {
+                // all extension attributes are optional so don't need to check if isRequired
+                continue;
+            }
+
+            $returnType = $this->methodsMapProcessor->getMethodReturnType($dataObjectType, $methodName);
+
+            if (is_object($value) && !($value instanceof Phrase)) {
+                $value = $this->dataObjectProcessor->buildOutputDataArray($value, $returnType);
+            } elseif (is_array($value)) {
+                $valueResult = [];
+                $arrayElementType = substr($returnType, 0, -2);
+                foreach ($value as $singleValue) {
+                    if (is_object($singleValue) && !($singleValue instanceof Phrase)) {
+                        $singleValue = $this->dataObjectProcessor->buildOutputDataArray(
+                            $singleValue,
+                            $arrayElementType
+                        );
+                    }
+                    $valueResult[] = $this->typeCaster->castValueToType($singleValue, $arrayElementType);
+                }
+                $value = $valueResult;
+            } else {
+                $value = $this->typeCaster->castValueToType($value, $returnType);
+            }
+
+            $outputData[$key] = $value;
+        }
+
+        return $outputData;
+    }
+
+    /**
+     * @param string $dataObjectType
+     * @param string $attributeCode
+     * @return bool
+     */
+    private function isAttributePermissionValid($dataObjectType, $attributeCode)
+    {
+        $typeName = $this->getRegularTypeForExtensionAttributesType($dataObjectType);
+        $permissions = $this->getPermissionsForTypeAndMethod($typeName, $attributeCode);
+        foreach ($permissions as $permission) {
+            if (!$this->authorization->isAllowed($permission)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * @param string $name
+     * @return string
+     */
+    private function getRegularTypeForExtensionAttributesType($name)
+    {
+        return ltrim(str_replace('ExtensionInterface', 'Interface', $name), '\\');
+    }
+
+    /**
+     * @param string $typeName
+     * @param string $attributeCode
+     * @return string[] A list of permissions
+     */
+    private function getPermissionsForTypeAndMethod($typeName, $attributeCode)
+    {
+        // TODO: Move function to the Config and hope this is cached
+        $attributes = $this->configReader->read();
+        if (isset($attributes[$typeName]) && isset($attributes[$typeName][$attributeCode])) {
+            $attributeMetadata = $attributes[$typeName][$attributeCode];
+            $permissions = [];
+            foreach ($attributeMetadata[Converter::RESOURCE_PERMISSIONS] as $permission) {
+                $permissions[] = $permission;
+            }
+            return $permissions;
+        }
+
+        return [];
+    }
+}
diff --git a/lib/internal/Magento/Framework/Reflection/FieldNamer.php b/lib/internal/Magento/Framework/Reflection/FieldNamer.php
new file mode 100644
index 0000000000000000000000000000000000000000..2e105b9a4f666e2073124e8817a9208762740389
--- /dev/null
+++ b/lib/internal/Magento/Framework/Reflection/FieldNamer.php
@@ -0,0 +1,43 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Framework\Reflection;
+
+use Magento\Framework\Phrase;
+use Magento\Framework\Api\AttributeValue;
+use Magento\Framework\Api\CustomAttributesDataInterface;
+use Magento\Framework\Api\SimpleDataObjectConverter;
+use Zend\Code\Reflection\ClassReflection;
+use Zend\Code\Reflection\MethodReflection;
+
+/**
+ * Determines the name to use for fields in a data output array given method metadata.
+ */
+class FieldNamer
+{
+    const IS_METHOD_PREFIX = 'is';
+    const HAS_METHOD_PREFIX = 'has';
+    const GETTER_PREFIX = 'get';
+    
+    /**
+     * Converts a method's name into a data field name.
+     *
+     * @param string $methodName
+     * @return string|null
+     */
+    public function getFieldNameForMethodName($methodName)
+    {
+        if (substr($methodName, 0, 2) === self::IS_METHOD_PREFIX) {
+            return SimpleDataObjectConverter::camelCaseToSnakeCase(substr($methodName, 2));
+        } elseif (substr($methodName, 0, 3) === self::HAS_METHOD_PREFIX) {
+            return SimpleDataObjectConverter::camelCaseToSnakeCase(substr($methodName, 3));
+        } elseif (substr($methodName, 0, 3) === self::GETTER_PREFIX) {
+            return SimpleDataObjectConverter::camelCaseToSnakeCase(substr($methodName, 3));
+        }
+
+        return null;
+    }
+}
diff --git a/lib/internal/Magento/Framework/Reflection/MethodsMap.php b/lib/internal/Magento/Framework/Reflection/MethodsMap.php
new file mode 100644
index 0000000000000000000000000000000000000000..36b446d1b870a32d6f468bf77b293a63b024fabe
--- /dev/null
+++ b/lib/internal/Magento/Framework/Reflection/MethodsMap.php
@@ -0,0 +1,180 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Framework\Reflection;
+
+use Zend\Code\Reflection\ClassReflection;
+use Zend\Code\Reflection\MethodReflection;
+
+/**
+ * Gathers method metadata information.
+ */
+class MethodsMap
+{
+    const SERVICE_INTERFACE_METHODS_CACHE_PREFIX = 'serviceInterfaceMethodsMap';
+    const BASE_MODEL_CLASS = 'Magento\Framework\Model\AbstractExtensibleModel';
+
+    /**
+     * @var \Magento\Framework\Cache\FrontendInterface
+     */
+    private $cache;
+
+    /**
+     * @var TypeProcessor
+     */
+    private $typeProcessor;
+
+    /**
+     * @var array
+     */
+    private $serviceInterfaceMethodsMap = [];
+
+    /**
+     * @var FieldNamer
+     */
+    private $fieldNamer;
+
+    /**
+     * @param \Magento\Framework\Cache\FrontendInterface $cache
+     * @param TypeProcessor $typeProcessor
+     * @param \Magento\Framework\Api\AttributeTypeResolverInterface $typeResolver
+     * @param FieldNamer $fieldNamer
+     */
+    public function __construct(
+        \Magento\Framework\Cache\FrontendInterface $cache,
+        TypeProcessor $typeProcessor,
+        \Magento\Framework\Api\AttributeTypeResolverInterface $typeResolver,
+        FieldNamer $fieldNamer
+    ) {
+        $this->cache = $cache;
+        $this->typeProcessor = $typeProcessor;
+        $this->attributeTypeResolver = $typeResolver;
+        $this->fieldNamer = $fieldNamer;
+    }
+
+    /**
+     * Get return type by type name and method name.
+     *
+     * @param string $typeName
+     * @param string $methodName
+     * @return string
+     */
+    public function getMethodReturnType($typeName, $methodName)
+    {
+        return $this->getMethodsMap($typeName)[$methodName]['type'];
+    }
+
+    /**
+     * Return service interface or Data interface methods loaded from cache
+     *
+     * @param string $interfaceName
+     * @return array
+     * <pre>
+     * Service methods' reflection data stored in cache as 'methodName' => 'returnType'
+     * ex.
+     * [
+     *  'create' => '\Magento\Customer\Api\Data\Customer',
+     *  'validatePassword' => 'boolean'
+     * ]
+     * </pre>
+     */
+    public function getMethodsMap($interfaceName)
+    {
+        $key = self::SERVICE_INTERFACE_METHODS_CACHE_PREFIX . "-" . md5($interfaceName);
+        if (!isset($this->serviceInterfaceMethodsMap[$key])) {
+            $methodMap = $this->cache->load($key);
+            if ($methodMap) {
+                $this->serviceInterfaceMethodsMap[$key] = unserialize($methodMap);
+            } else {
+                $methodMap = $this->getMethodMapViaReflection($interfaceName);
+                $this->serviceInterfaceMethodsMap[$key] = $methodMap;
+                $this->cache->save(serialize($this->serviceInterfaceMethodsMap[$key]), $key);
+            }
+        }
+        return $this->serviceInterfaceMethodsMap[$key];
+    }
+
+    /**
+     * Use reflection to load the method information
+     *
+     * @param string $interfaceName
+     * @return array
+     */
+    private function getMethodMapViaReflection($interfaceName)
+    {
+        $methodMap = [];
+        $class = new ClassReflection($interfaceName);
+        $baseClassMethods = false;
+        foreach ($class->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
+            // Include all the methods of classes inheriting from AbstractExtensibleObject.
+            // Ignore all the methods of AbstractExtensibleModel's parent classes
+            if ($method->class === self::BASE_MODEL_CLASS) {
+                $baseClassMethods = true;
+            } elseif ($baseClassMethods) {
+                // ReflectionClass::getMethods() sorts the methods by class (lowest in inheritance tree first)
+                // then by the order they are defined in the class definition
+                break;
+            }
+
+            if ($this->isSuitableMethod($method)) {
+                $methodMap[$method->getName()] = $this->typeProcessor->getGetterReturnType($method);
+            }
+        }
+        return $methodMap;
+    }
+
+    /**
+     * Determines if the method is suitable to be used by the processor.
+     *
+     * @param \ReflectionMethod $method
+     * @return bool
+     */
+    private function isSuitableMethod($method)
+    {
+        $isSuitableMethodType = !($method->isConstructor() || $method->isFinal()
+            || $method->isStatic() || $method->isDestructor());
+
+        $isExcludedMagicMethod = strpos($method->getName(), '__') === 0;
+        return $isSuitableMethodType && !$isExcludedMagicMethod;
+    }
+
+    /**
+     * Determines if the given method's on the given type is suitable for an output data array.
+     *
+     * @param string $type
+     * @param string $methodName
+     * @return bool
+     */
+    public function isMethodValidForDataField($type, $methodName)
+    {
+        $methods = $this->getMethodsMap($type);
+        if (isset($methods[$methodName])) {
+            $methodMetadata = $methods[$methodName];
+            // any method with parameter(s) gets ignored because we do not know the type and value of
+            // the parameter(s), so we are not able to process
+            if ($methodMetadata['parameterCount'] > 0) {
+                return false;
+            }
+
+            return $this->fieldNamer->getFieldNameForMethodName($methodName) !== null;
+        }
+
+        return false;
+    }
+
+    /**
+     * If the method has only non-null return types
+     *
+     * @param string $type
+     * @param string $methodName
+     * @return bool
+     */
+    public function isMethodReturnValueRequired($type, $methodName)
+    {
+        $methods = $this->getMethodsMap($type);
+        return $methods[$methodName]['isRequired'];
+    }
+}
diff --git a/lib/internal/Magento/Framework/Reflection/Test/Unit/ExtensionAttributesObject.php b/lib/internal/Magento/Framework/Reflection/Test/Unit/ExtensionAttributesObject.php
new file mode 100644
index 0000000000000000000000000000000000000000..66077712a43b337238402748fe9ccf9c4b0db5f2
--- /dev/null
+++ b/lib/internal/Magento/Framework/Reflection/Test/Unit/ExtensionAttributesObject.php
@@ -0,0 +1,30 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Framework\Reflection\Test\Unit;
+
+use Magento\Framework\Api\ExtensionAttributesInterface;
+
+/**
+ * Dummy data object to be used by ExtensionAttributesProcessorTest
+ */
+class ExtensionAttributesObject implements ExtensionAttributesInterface
+{
+    /**
+     * @return string
+     */
+    public function getAttrName()
+    {
+        return 'attrName';
+    }
+
+    /**
+     * @return bool
+     */
+    public function isActive()
+    {
+        return false;
+    }
+}
diff --git a/lib/internal/Magento/Framework/Reflection/Test/Unit/ExtensionAttributesProcessorTest.php b/lib/internal/Magento/Framework/Reflection/Test/Unit/ExtensionAttributesProcessorTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..8da0c1f734f710da1c69d28c9e9f4ac02999db86
--- /dev/null
+++ b/lib/internal/Magento/Framework/Reflection/Test/Unit/ExtensionAttributesProcessorTest.php
@@ -0,0 +1,172 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Framework\Reflection\Test\Unit;
+
+use Magento\Framework\Api\Config\Converter;
+use Magento\Framework\Api\Config\Reader;
+use Magento\Framework\AuthorizationInterface;
+use Magento\Framework\Reflection\DataObjectProcessor;
+use Magento\Framework\Reflection\ExtensionAttributesProcessor;
+use Magento\Framework\Reflection\FieldNamer;
+use Magento\Framework\Reflection\MethodsMap;
+use Magento\Framework\Reflection\TypeCaster;
+
+/**
+ * ExtensionAttributesProcessor test
+ */
+class ExtensionAttributesProcessorTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var ExtensionAttributesProcessor
+     */
+    private $model;
+
+    /**
+     * @var DataObjectProcessor
+     */
+    private $dataObjectProcessorMock;
+
+    /**
+     * @var MethodsMap
+     */
+    private $methodsMapProcessorMock;
+
+    /**
+     * @var FieldNamer
+     */
+    private $fieldNamerMock;
+
+    /**
+     * @var TypeCaster
+     */
+    private $typeCasterMock;
+
+    /**
+     * @var Reader
+     */
+    private $configReaderMock;
+
+    /**
+     * @var AuthorizationInterface
+     */
+    private $authorizationMock;
+    /**
+     * Set up helper.
+     */
+    public function setUp()
+    {
+        $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+
+        $this->dataObjectProcessorMock = $this->getMockBuilder('Magento\Framework\Reflection\DataObjectProcessor')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->methodsMapProcessorMock = $this->getMockBuilder('Magento\Framework\Reflection\MethodsMap')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->typeCasterMock = $this->getMockBuilder('Magento\Framework\Reflection\TypeCaster')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->fieldNamerMock = $this->getMockBuilder('Magento\Framework\Reflection\FieldNamer')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->configReaderMock = $this->getMockBuilder('Magento\Framework\Api\Config\Reader')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->authorizationMock = $this->getMockBuilder('Magento\Framework\AuthorizationInterface')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->model = $objectManager->getObject(
+            'Magento\Framework\Reflection\ExtensionAttributesProcessor',
+            [
+                'dataObjectProcessor' => $this->dataObjectProcessorMock,
+                'methodsMapProcessor' => $this->methodsMapProcessorMock,
+                'typeCaster' => $this->typeCasterMock,
+                'fieldNamer' => $this->fieldNamerMock,
+                'authorization' => $this->authorizationMock,
+                'configReader' => $this->configReaderMock,
+                'isPermissionChecked' => true,
+            ]
+        );
+    }
+
+    /**
+     * @param bool $isPermissionAllowed
+     * @param array $expectedValue
+     * @dataProvider buildOutputDataArrayWithPermissionProvider
+     */
+    public function testBuildOutputDataArrayWithPermission($isPermissionAllowed, $expectedValue)
+    {
+        $dataObject = new \Magento\Framework\Reflection\Test\Unit\ExtensionAttributesObject();
+        $dataObjectType = 'Magento\Framework\Reflection\Test\Unit\ExtensionAttributesObject';
+        $methodName = 'getAttrName';
+        $attributeName = 'attr_name';
+        $attributeValue = 'attrName';
+
+        $this->methodsMapProcessorMock->expects($this->once())
+            ->method('getMethodsMap')
+            ->with($dataObjectType)
+            ->will($this->returnValue([$methodName => []]));
+        $this->methodsMapProcessorMock->expects($this->once())
+            ->method('isMethodValidForDataField')
+            ->with($dataObjectType, $methodName)
+            ->will($this->returnValue(true));
+        $this->fieldNamerMock->expects($this->once())
+            ->method('getFieldNameForMethodName')
+            ->with($methodName)
+            ->will($this->returnValue($attributeName));
+        $permissionName = 'Magento_Permission';
+        $this->configReaderMock->expects($this->once())
+            ->method('read')
+            ->will($this->returnValue([
+                $dataObjectType => [
+                    $attributeName => [ Converter::RESOURCE_PERMISSIONS => [ $permissionName ] ]
+                ]
+              ]));
+        $this->authorizationMock->expects($this->once())
+            ->method('isAllowed')
+            ->with($permissionName)
+            ->will($this->returnValue($isPermissionAllowed));
+
+        if ($isPermissionAllowed) {
+            $this->methodsMapProcessorMock->expects($this->once())
+                ->method('getMethodReturnType')
+                ->with($dataObjectType, $methodName)
+                ->will($this->returnValue('string'));
+            $this->typeCasterMock->expects($this->once())
+                ->method('castValueToType')
+                ->with($attributeValue, 'string')
+                ->will($this->returnValue($attributeValue));
+        }
+
+        $value = $this->model->buildOutputDataArray(
+            $dataObject,
+            $dataObjectType
+        );
+
+        $this->assertEquals(
+            $value,
+            $expectedValue
+        );
+    }
+
+    public function buildOutputDataArrayWithPermissionProvider()
+    {
+        return [
+            'permission allowed' => [
+                true,
+                [
+                    'attr_name' => 'attrName',
+                ],
+            ],
+            'permission not allowed' => [
+                false,
+                [],
+            ],
+        ];
+    }
+}
diff --git a/lib/internal/Magento/Framework/Reflection/Test/Unit/FieldNamerTest.php b/lib/internal/Magento/Framework/Reflection/Test/Unit/FieldNamerTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..1d498a940ec1a437ccc546e3629df37767748eeb
--- /dev/null
+++ b/lib/internal/Magento/Framework/Reflection/Test/Unit/FieldNamerTest.php
@@ -0,0 +1,52 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Framework\Reflection\Test\Unit;
+
+use Magento\Framework\Reflection\FieldNamer;
+
+/**
+ * Field namer Test
+ */
+class FieldNamerTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var FieldNamer
+     */
+    private $model;
+
+    /**
+     * Set up helper.
+     */
+    public function setUp()
+    {
+        $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+        $this->model = $objectManager->getObject('Magento\Framework\Reflection\FieldNamer');
+    }
+
+    /**
+     * @param string $methodName
+     * @param string $expectedName
+     * @dataProvider methodNameProvider
+     */
+    public function testGetFieldNameForMethodName($methodName, $expectedName)
+    {
+        $value = $this->model->getFieldNameForMethodName($methodName);
+        $this->assertEquals($value, $expectedName);
+    }
+
+    /**
+     * @return array
+     */
+    public function methodNameProvider()
+    {
+        return [
+            'isMethod' => ['isValid', 'valid'],
+            'getMethod' => ['getValue', 'value'],
+            'hasMethod' => ['hasStuff', 'stuff'],
+            'randomMethod' => ['randomMethod', null],
+        ];
+    }
+}
diff --git a/lib/internal/Magento/Framework/Reflection/Test/Unit/MethodsMapTest.php b/lib/internal/Magento/Framework/Reflection/Test/Unit/MethodsMapTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..82f859897da9bfdcdd8f26de0ef7d3201712f699
--- /dev/null
+++ b/lib/internal/Magento/Framework/Reflection/Test/Unit/MethodsMapTest.php
@@ -0,0 +1,174 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Framework\Reflection\Test\Unit;
+
+use Magento\Framework\Reflection\MethodsMap;
+use Magento\Framework\Reflection\TypeProcessor;
+use Magento\Framework\Reflection\FieldNamer;
+
+/**
+ * MethodsMap test
+ */
+class MethodsMapTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var MethodsMap
+     */
+    private $model;
+
+    /**
+     * Set up helper.
+     */
+    public function setUp()
+    {
+        $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+
+        $cacheMock = $this->getMockBuilder('Magento\Framework\Cache\FrontendInterface')
+            ->getMockForAbstractClass();
+        $cacheMock->expects($this->any())
+            ->method('save');
+        $cacheMock->expects($this->any())
+            ->method('load')
+            ->will($this->returnValue(null));
+
+        $attributeTypeResolverMock = $this->getMockBuilder('Magento\Framework\Api\AttributeTypeResolverInterface')
+            ->getMockForAbstractClass();
+        $fieldNamerMock = $this->getMockBuilder('Magento\Framework\Reflection\FieldNamer')
+            ->getMockForAbstractClass();
+        $this->model = $objectManager->getObject(
+            'Magento\Framework\Reflection\MethodsMap',
+            [
+                'cache' => $cacheMock,
+                'typeProcessor' => new TypeProcessor(),
+                'typeResolver' => $attributeTypeResolverMock,
+                'fieldNamer' => $fieldNamerMock,
+            ]
+        );
+    }
+
+    public function testGetMethodReturnType()
+    {
+        $this->assertEquals(
+            'string',
+            $this->model->getMethodReturnType('Magento\Framework\Reflection\FieldNamer', 'getFieldNameForMethodName')
+        );
+        $this->assertEquals(
+            'mixed',
+            $this->model->getMethodReturnType('Magento\Framework\Reflection\TypeCaster', 'castValueToType')
+        );
+        $this->assertEquals(
+            'array',
+            $this->model->getMethodReturnType('Magento\Framework\Reflection\MethodsMap', 'getMethodsMap')
+        );
+    }
+
+    public function testGetMethodsMap()
+    {
+        $methodsMap = $this->model->getMethodsMap('Magento\Framework\Reflection\MethodsMap');
+        $this->assertEquals(
+            $methodsMap,
+            [
+                'getMethodReturnType' => [
+                    'type' => 'string',
+                    'isRequired' => true,
+                    'description' => null,
+                    'parameterCount' => 2,
+                ],
+                'getMethodsMap' => [
+                    'type' => 'array',
+                    'isRequired' => true,
+                    'description' => "<pre> Service methods' reflection data stored in cache as 'methodName' => "
+                        . "'returnType' ex. [ 'create' => '\Magento\Customer\Api\Data\Customer', 'validatePassword' "
+                        . "=> 'boolean' ] </pre>",
+                    'parameterCount' => 1,
+                ],
+                'isMethodValidForDataField' => [
+                    'type' => 'bool',
+                    'isRequired' => true,
+                    'description' => null,
+                    'parameterCount' => 2,
+                ],
+                'isMethodReturnValueRequired' => [
+                    'type' => 'bool',
+                    'isRequired' => true,
+                    'description' => null,
+                    'parameterCount' => 2,
+                ],
+            ]
+        );
+    }
+
+    /**
+     * @param string $type
+     * @param string $methodName
+     * @param bool $expectedResult
+     * @dataProvider isMethodValidForDataFieldProvider
+     */
+    public function testIsMethodValidForDataField($type, $methodName, $expectedResult)
+    {
+        $this->assertEquals($this->model->isMethodValidForDataField($type, $methodName), $expectedResult);
+    }
+
+    /**
+     * @return array
+     */
+    public function isMethodValidForDataFieldProvider()
+    {
+        return [
+            'MethodsMap#isMethodValidForDataField' => [
+                'Magento\Framework\Reflection\MethodsMap',
+                'isMethodValidForDataField',
+                false,
+            ],
+            'DataObject#getAttrName' => [
+                'Magento\Framework\Reflection\Test\Unit\DataObject',
+                'getAttrName',
+                true,
+            ],
+            'DataObject#isActive' => [
+                'Magento\Framework\Reflection\Test\Unit\DataObject',
+                'isActive',
+                true,
+            ],
+        ];
+    }
+
+    /**
+     * @param string $type
+     * @param string $methodName
+     * @param bool $expectedResult
+     * @dataProvider isMethodReturnValueRequiredProvider
+     */
+    public function testIsMethodReturnValueRequired($type, $methodName, $expectedResult)
+    {
+        $this->assertEquals($this->model->isMethodValidForDataField($type, $methodName), $expectedResult);
+    }
+
+    /**
+     * @return array
+     */
+    public function isMethodReturnValueRequiredProvider()
+    {
+        return [
+            'DataObject#getAttrName' => [
+                'Magento\Framework\Reflection\Test\Unit\DataObject',
+                'getAttrName',
+                true,
+            ],
+            'DataObject#isActive' => [
+                'Magento\Framework\Reflection\Test\Unit\DataObject',
+                'isActive',
+                true,
+            ],
+            'FieldNamer#getFieldNameForMethodName' => [
+                'Magento\Framework\Reflection\FieldNamer',
+                'getFieldNameForMethodName',
+                false,
+            ],
+        ];
+    }
+}
diff --git a/lib/internal/Magento/Framework/Reflection/Test/Unit/TypeCasterTest.php b/lib/internal/Magento/Framework/Reflection/Test/Unit/TypeCasterTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..8f7afdbbedcb05e103f92c6c982d5a0686cf7481
--- /dev/null
+++ b/lib/internal/Magento/Framework/Reflection/Test/Unit/TypeCasterTest.php
@@ -0,0 +1,61 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Framework\Reflection\Test\Unit;
+
+use Magento\Framework\Reflection\TypeCaster;
+
+/**
+ * Type caster Test
+ */
+class TypeCasterTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var TypeCaster
+     */
+    private $model;
+
+    /**
+     * Set up helper.
+     */
+    public function setUp()
+    {
+        $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+        $this->model = $objectManager->getObject('Magento\Framework\Reflection\TypeCaster');
+    }
+
+    /**
+     * @param mixed $origValue
+     * @param string $typeToCast
+     * @param mixed $expectedValue
+     * @dataProvider typeCastValueProvider
+     */
+    public function testCastValues($origValue, $typeToCast, $expectedValue)
+    {
+        $value = $this->model->castValueToType($origValue, $typeToCast);
+        $this->assertTrue($value === $expectedValue);
+    }
+
+    /**
+     * @return array
+     */
+    public function typeCastValueProvider()
+    {
+        return [
+            'null' => [null, 'int', null],
+            'int' => ['1', 'int', 1],
+            'integer' => ['1', 'integer', 1],
+            'string' => ['1', 'string', '1'],
+            'bool 0' => ['0', 'bool', false],
+            'bool 1' => ['1', 'bool', true],
+            'boolean 0' => ['0', 'boolean', false],
+            'boolean 1' => ['1', 'boolean', true],
+            'true' => ['1', 'true', true],
+            'false' => ['0', 'false', false],
+            'float' => ['1.03', 'float', 1.03],
+            'double' => ['1.30', 'double', 1.30],
+        ];
+    }
+}
diff --git a/lib/internal/Magento/Framework/Reflection/TypeCaster.php b/lib/internal/Magento/Framework/Reflection/TypeCaster.php
new file mode 100644
index 0000000000000000000000000000000000000000..185b86c1d880b14061f3271da5de4885bf56cf29
--- /dev/null
+++ b/lib/internal/Magento/Framework/Reflection/TypeCaster.php
@@ -0,0 +1,51 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Framework\Reflection;
+
+/**
+ * Casts values to the type given.
+ */
+class TypeCaster
+{
+    /**
+     * Cast the output type to the documented type. This helps for consistent output (e.g. JSON).
+     *
+     * @param mixed $value
+     * @param string $type
+     * @return mixed
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+     * @SuppressWarnings(PHPMD.NPathComplexity)
+     */
+    public function castValueToType($value, $type)
+    {
+        if ($value === null) {
+            return null;
+        }
+
+        if ($type === "int" || $type === "integer") {
+            return (int)$value;
+        }
+
+        if ($type === "string") {
+            return (string)$value;
+        }
+
+        if ($type === "bool" || $type === "boolean" || $type === "true" || $type == "false") {
+            return (bool)$value;
+        }
+
+        if ($type === "float") {
+            return (float)$value;
+        }
+
+        if ($type === "double") {
+            return (double)$value;
+        }
+
+        return $value;
+    }
+}
diff --git a/lib/internal/Magento/Framework/Webapi/ServiceOutputProcessor.php b/lib/internal/Magento/Framework/Webapi/ServiceOutputProcessor.php
index 79cd652f4b22e85a9abc8299e6d6180f4e6037d0..1bf5137218bf4de0d49039d61593c1730a9d871c 100644
--- a/lib/internal/Magento/Framework/Webapi/ServiceOutputProcessor.php
+++ b/lib/internal/Magento/Framework/Webapi/ServiceOutputProcessor.php
@@ -8,6 +8,7 @@ namespace Magento\Framework\Webapi;
 use Magento\Framework\Api\AbstractExtensibleObject;
 use Magento\Framework\Api\ExtensibleDataObjectConverter;
 use Magento\Framework\Reflection\DataObjectProcessor;
+use Magento\Framework\Reflection\MethodsMap;
 
 /**
  * Data object converter for REST
@@ -19,12 +20,21 @@ class ServiceOutputProcessor
      */
     protected $dataObjectProcessor;
 
+    /**
+     * @var MethodsMap
+     */
+    protected $methodsMapProcessor;
+
     /**
      * @param DataObjectProcessor $dataObjectProcessor
+     * @param MethodsMap $methodsMapProcessor
      */
-    public function __construct(DataObjectProcessor $dataObjectProcessor)
-    {
+    public function __construct(
+        DataObjectProcessor $dataObjectProcessor,
+        MethodsMap $methodsMapProcessor
+    ) {
         $this->dataObjectProcessor = $dataObjectProcessor;
+        $this->methodsMapProcessor = $methodsMapProcessor;
     }
 
     /**
@@ -44,7 +54,7 @@ class ServiceOutputProcessor
     public function process($data, $serviceClassName, $serviceMethodName)
     {
         /** @var string $dataType */
-        $dataType = $this->dataObjectProcessor->getMethodReturnType($serviceClassName, $serviceMethodName);
+        $dataType = $this->methodsMapProcessor->getMethodReturnType($serviceClassName, $serviceMethodName);
         if (is_array($data)) {
             $result = [];
             $arrayElementType = substr($dataType, 0, -2);