diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/display/Data.php b/core/modules/views/lib/Drupal/views/Plugin/views/display/Data.php
new file mode 100644
index 0000000..1f4d4aa
--- /dev/null
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/display/Data.php
@@ -0,0 +1,169 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\views\Plugin\views\display\Data.
+ */
+
+namespace Drupal\views\Plugin\views\display;
+
+use Symfony\Component\HttpFoundation\Response;
+use Drupal\Core\Annotation\Plugin;
+use Drupal\Core\Annotation\Translation;
+
+/**
+ * The plugin that handles a Data response callbacks.
+ *
+ * @ingroup views_display_plugins
+ *
+ * @Plugin(
+ *   id = "data",
+ *   title = @Translation("Data"),
+ *   help = @Translation("Display views as data output formats"),
+ *   uses_hook_menu = TRUE,
+ *   admin = @Translation("Data")
+ * )
+ */
+class Data extends PathPluginBase {
+
+  /**
+   * Overrides Drupal\views\Plugin\views\display\DisplayPluginBase::$usesAJAX.
+   */
+  protected $usesAJAX = FALSE;
+
+  /**
+   * Overrides Drupal\views\Plugin\views\display\DisplayPluginBase::$usesPager.
+   */
+  protected $usesPager = FALSE;
+
+  /**
+   * Overrides Drupal\views\Plugin\views\display\DisplayPluginBase::$usesMore.
+   */
+  protected $usesMore = FALSE;
+
+  /**
+   * Overrides Drupal\views\Plugin\views\display\DisplayPluginBase::$usesAreas.
+   */
+  protected $usesAreas = FALSE;
+
+  /**
+   * Overrides Drupal\views\Plugin\views\display\DisplayPluginBase::$usesAreas.
+   */
+  protected $usesOptions = FALSE;
+
+  /**
+   * Overrides the content type of the data response, if needed.
+   */
+  protected $contentType;
+
+  /**
+   * Overrides Drupal\views\Plugin\views\display\DisplayPluginBase::getStyleType().
+   */
+  protected function getStyleType() {
+    return 'data';
+  }
+
+  /**
+   * Overrides Drupal\views\Plugin\views\display\DisplayPluginBase::usesExposed().
+   */
+  public function usesExposed() {
+    return FALSE;
+  }
+
+  /**
+   * Overrides Drupal\views\Plugin\views\display\DisplayPluginBase::displaysExposed().
+   */
+  public function displaysExposed() {
+    return FALSE;
+  }
+
+  /**
+   * Sets the request content type.
+   */
+  public function setContentType($content_type) {
+    $this->contentType = $content_type;
+  }
+
+  /**
+   * Gets the request content type.
+   *
+   * This will return the overriden content type if set, otherwise returns the
+   * content type from the request.
+   */
+  public function getContentType() {
+    if (!isset($this->contentType)) {
+      // Return the content type based on the request object.
+      $negotiation = drupal_container()->get('content_negotiation');
+      $request = drupal_container()->get('request');
+      $content_type = $negotiation->getContentType($request);
+
+      $this->setContentType($request->getMimeType($content_type));
+    }
+
+    return $this->contentType;
+  }
+
+  /**
+   * Overrides Drupal\views\Plugin\views\display\DisplayPluginBase::defineOptions().
+   */
+  protected function defineOptions() {
+    $options = parent::defineOptions();
+
+    // Set the default style plugin to 'json'.
+    $options['style']['contains']['type']['default'] = 'serialize';
+    $options['row']['contains']['type']['default'] = 'data_entity';
+    $options['defaults']['default']['style'] = FALSE;
+    $options['defaults']['default']['row'] = FALSE;
+
+    return $options;
+  }
+
+  /**
+   * Overrides Drupal\views\Plugin\views\display\PathPluginBase::optionsSummary().
+   */
+  public function optionsSummary(&$categories, &$options) {
+    parent::optionsSummary($categories, $options);
+
+    unset($categories['page']);
+    // Hide some settings, as they aren't useful for pure data output.
+    unset($options['hide_admin_links'], $options['analyze-theme']);
+
+    $categories['path'] = array(
+      'title' => t('Path settings'),
+      'column' => 'second',
+      'build' => array(
+        '#weight' => -10,
+      ),
+    );
+
+    $options['path']['category'] = 'path';
+    $options['path']['title'] = t('Path');
+  }
+
+  /**
+   * Overrides Drupal\views\Plugin\views\display\PathPluginBase::execute().
+   */
+  public function execute() {
+    parent::execute();
+
+    $output = $this->view->render();
+
+    $response = new Response($output, 200, array('Content-type' => $this->getContentType()));
+
+    return $response;
+  }
+
+  /**
+   * Overrides Drupal\views\Plugin\views\display\DisplayPluginBase::render().
+   */
+  public function render() {
+    $output = $this->view->style_plugin->render();
+
+    if (!empty($this->view->live_preview)) {
+      return '<pre>' . $output . '</pre>';
+    }
+
+    return $output;
+  }
+
+}
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/row/DataEntityRow.php b/core/modules/views/lib/Drupal/views/Plugin/views/row/DataEntityRow.php
new file mode 100644
index 0000000..c635e5e
--- /dev/null
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/row/DataEntityRow.php
@@ -0,0 +1,41 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\views\Plugin\views\row\DataEntityRow.
+ */
+
+namespace Drupal\views\Plugin\views\row;
+
+use Drupal\views\ViewExecutable;
+use Drupal\Core\Annotation\Plugin;
+use Drupal\Core\Annotation\Translation;
+
+/**
+ * Plugin which displays entities as raw data.
+ *
+ * @ingroup views_row_plugins
+ *
+ * @Plugin(
+ *   id = "data_entity",
+ *   module = "system",
+ *   title = @Translation("Entity"),
+ *   help = @Translation("Use entities as row data."),
+ *   type = "data"
+ * )
+ */
+class DataEntityRow extends RowPluginBase {
+
+  /**
+   * Overrides Drupal\views\Plugin\Plugin::$usesOptions.
+   */
+  protected $usesOptions = FALSE;
+
+  /**
+   * Overrides Drupal\views\Plugin\views\row\RowPluginBase::render().
+   */
+  public function render($row) {
+    return $row->_entity;
+  }
+
+}
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/row/DataFieldRow.php b/core/modules/views/lib/Drupal/views/Plugin/views/row/DataFieldRow.php
new file mode 100644
index 0000000..2c96e0d
--- /dev/null
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/row/DataFieldRow.php
@@ -0,0 +1,128 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\views\Plugin\views\row\DataFieldRow.
+ */
+
+namespace Drupal\views\Plugin\views\row;
+
+use Drupal\views\ViewExecutable;
+use Drupal\Core\Annotation\Plugin;
+use Drupal\Core\Annotation\Translation;
+
+/**
+ * Plugin which displays fields as raw data.
+ *
+ * @ingroup views_row_plugins
+ *
+ * @Plugin(
+ *   id = "data_field",
+ *   module = "system",
+ *   title = @Translation("Fields"),
+ *   help = @Translation("Use fields as row data."),
+ *   type = "data"
+ * )
+ */
+class DataFieldRow extends RowPluginBase {
+
+  /**
+   * Overrides \Drupal\views\Plugin\views\row\RowPluginBase::$usesFields.
+   */
+  protected $usesFields = TRUE;
+
+  /**
+   * Stores an array of prepared field aliases from options.
+   *
+   * @var array
+   */
+  protected $replacementAliases = array();
+
+  /**
+   * Overrides \Drupal\views\Plugin\views\row\RowPluginBase::init().
+   */
+  public function init(ViewExecutable $view, &$display, $options = NULL) {
+    parent::init($view, $display, $options);
+
+    if (!empty($this->options['aliases'])) {
+      // Prepare a trimmed version of replacement aliases.
+      $this->replacementAliases = array_map('trim', (array) $this->options['aliases']);
+    }
+  }
+
+  /**
+   * Overrides \Drupal\views\Plugin\views\row\RowPluginBase::buildOptionsForm().
+   */
+  protected function defineOptions() {
+    $options = parent::defineOptions();
+    $options['aliases'] = array('default' => array());
+
+    return $options;
+  }
+
+
+  /**
+   * Overrides \Drupal\views\Plugin\views\row\RowPluginBase::buildOptionsForm().
+   */
+  public function buildOptionsForm(&$form, &$form_state) {
+    parent::buildOptionsForm($form, $form_state);
+
+    $form['aliases'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Field ID aliases'),
+      '#description' => t('Rename views default field ID\'s in the output data.'),
+      '#tree' => TRUE,
+    );
+
+    if ($fields = $this->view->display_handler->getOption('fields')) {
+      foreach ($fields as $id => $field) {
+        $form['aliases'][$id] = array(
+          '#type' => 'textfield',
+          '#title' => $id,
+          '#default_value' => isset($this->options['aliases'][$id]) ? $this->options['aliases'][$id] : '',
+        );
+      }
+    }
+  }
+
+  /**
+   * Overrides \Drupal\views\Plugin\views\row\RowPluginBase::validateOptionsForm().
+   */
+  public function validateOptionsForm(&$form, &$form_state) {
+    $aliases = $form_state['values']['row_options']['aliases'];
+    if (array_unique($aliases) !== $aliases) {
+      form_set_error('aliases', t('All field aliases must be unique'));
+    }
+
+  }
+
+  /**
+   * Overrides \Drupal\views\Plugin\views\row\RowPluginBase::render().
+   */
+  public function render($row) {
+    $output = array();
+
+    foreach ($this->view->field as $id => $field) {
+      $output[$this->getFieldKeyAlias($id)] = $row->{$field->field_alias};
+    }
+
+    return $output;
+  }
+
+  /**
+   * Return an alias for a field ID, as set in the options form.
+   *
+   * @param string $id
+   *   The field id to lookup an alias for.
+   *
+   * @return string
+   *   The matches user entered alias, or the original ID if nothing is found.
+   */
+  public function getFieldKeyAlias($id) {
+    if (isset($this->replacementAliases[$id])) {
+      return $this->replacementAliases[$id];
+    }
+    return $id;
+  }
+
+}
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/style/Serialize.php b/core/modules/views/lib/Drupal/views/Plugin/views/style/Serialize.php
new file mode 100644
index 0000000..c8ac3b8
--- /dev/null
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/style/Serialize.php
@@ -0,0 +1,92 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\views\Plugin\views\style\Serialize.
+ */
+
+namespace Drupal\views\Plugin\views\style;
+
+use Drupal\Core\Annotation\Plugin;
+use Drupal\views\ViewExecutable;
+use Drupal\Core\Annotation\Translation;
+
+/**
+ * The style plugin for serialized output formats.
+ *
+ * @ingroup views_style_plugins
+ *
+ * @Plugin(
+ *   id = "serialize",
+ *   title = @Translation("Serializer"),
+ *   help = @Translation("Serializes views row data using the Serializer component."),
+ *   type = "data"
+ * )
+ */
+class Serialize extends StylePluginBase {
+
+  /**
+   * Overrides Drupal\views\Plugin\views\style\StylePluginBase::$usesRowPlugin.
+   */
+  protected $usesRowPlugin = TRUE;
+
+  /**
+   * Overrides Drupal\views\Plugin\views\style\StylePluginBase::$usesFields.
+   */
+  protected $usesGrouping = FALSE;
+
+  /**
+   * The serializer which serializes the views result.
+   *
+   * @var \Symfony\Component\Serializer\Serializer
+   */
+  protected $serializer;
+
+  /**
+   * The current active request object.
+   *
+   * @var \Symfony\Component\HttpFoundation\Request
+   */
+  protected $request;
+
+  /**
+   * The current content negotiation object registered on the container.
+   *
+   * @var \Drupal\Core\ContentNegotiation
+   */
+  protected $negotiation;
+
+  /**
+   * Overrides \Drupal\views\Plugin\views\style\StylePluginBase::init().
+   */
+  public function init(ViewExecutable $view, &$display, $options = NULL) {
+    parent::init($view, $display, $options);
+
+    // Get services for serialization.
+    $container = drupal_container();
+    $this->serializer = $container->get('serializer');
+    $this->request = $container->get('request');
+    $this->negotiation = $container->get('content_negotiation');
+  }
+
+  /**
+   * Overrides Drupal\views\Plugin\views\style\StylePluginBase::render().
+   */
+  public function render() {
+    $rows = array();
+    // If the Data Entity row plugin is used, this will be an array of entities
+    // which will pass through Serializer to one of the registered Normalizers,
+    // which will transform it to arrays/scalars. If the Data field row plugin
+    // is used, $rows will not contain objects and will pass directly to the
+    // Encoder.
+    foreach ($this->view->result as $row) {
+      $rows[] = $this->row_plugin->render($row);
+    }
+
+    $content_type = $this->negotiation->getContentType($this->request);
+    $this->displayHandler->setContentType($this->request->getMimeType($content_type));
+
+    return $this->serializer->serialize($rows, $content_type);
+  }
+
+}
diff --git a/core/modules/views/lib/Drupal/views/Tests/Plugin/StyleSerializeTest.php b/core/modules/views/lib/Drupal/views/Tests/Plugin/StyleSerializeTest.php
new file mode 100644
index 0000000..813510b
--- /dev/null
+++ b/core/modules/views/lib/Drupal/views/Tests/Plugin/StyleSerializeTest.php
@@ -0,0 +1,127 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\views\Tests\Plugin\StyleSerializeTest.
+ */
+
+namespace Drupal\views\Tests\Plugin;
+
+use Drupal\views\Tests\Plugin\PluginTestBase;
+
+/**
+ * Tests the serialize style plugin.
+ *
+ * @see \Drupal\views\Plugin\display\Data
+ * @see \Drupal\views\Plugin\style\Serialize
+ */
+class StyleSerializeTest extends PluginTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('views_ui', 'node');
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Style: Serialize plugin',
+      'description' => 'Tests the serialize style plugin.',
+      'group' => 'Views Plugins',
+    );
+  }
+
+  protected function setUp() {
+    parent::setUp();
+
+    for ($i = 1; $i <= 10; $i++) {
+      $this->drupalCreateNode();
+    }
+
+    $this->enableViewsTestModule();
+
+    $this->adminUser = $this->drupalCreateUser(array('administer views', 'bypass node access', 'access user profiles', 'view revisions'));
+  }
+
+  /**
+   * Checks the behavior of serialize callback paths and row plugins.
+   */
+  public function testSerializeResponses() {
+    // Test the serialize callback.
+    $view = views_get_view('test_serialize_display_field');
+    $view->initDisplay();
+    $this->executeView($view);
+
+    $actual_json = $this->drupalGet('test/serialize/field', array(), array('Content-type: application/json'));
+    $this->assertResponse(200);
+
+    // Test the http Content-type.
+    $headers = $this->drupalGetHeaders();
+    $this->assertEqual($headers['content-type'], 'application/json', 'The header Content-type is correct.');
+
+    $expected = array();
+    foreach ($view->result as $row) {
+      $expected_row = array();
+      foreach ($view->field as $id => $field) {
+        $expected_row[$id] = $row->{$field->field_alias};
+      }
+      $expected[] = $expected_row;
+    }
+
+    $this->assertIdentical($actual_json, json_encode($expected), 'The expected JSON output was found.');
+
+    // Test a 403 callback.
+    $this->drupalGet('test/serialize/denied');
+    $this->assertResponse(403);
+
+    // Test the entity rows.
+
+    $view = views_get_view('test_serialize_display_entity');
+    $view->initDisplay();
+    $this->executeView($view);
+
+    $expected = array();
+    foreach ($view->result as $row) {
+      $expected[] = $row->_entity;
+    }
+
+    $actual_json = $this->drupalGet('test/serialize/entity', array(), array('Content-type: application/json'));
+    $this->assertResponse(200);
+
+    $this->assertIdentical($actual_json, json_encode($expected), 'The expected JSON output was found.');
+  }
+
+  /**
+   * Test the field ID alias functionality of the DataFieldRow plugin.
+   */
+  public function testUIFieldAlias() {
+    $this->drupalLogin($this->adminUser);
+
+    // Test the UI settings for adding field ID aliases.
+    $this->drupalGet('admin/structure/views/view/test_serialize_display_field/edit/data_1');
+    $row_options = 'admin/structure/views/nojs/display/test_serialize_display_field/data_1/row_options';
+    $this->assertLinkByHref($row_options);
+
+    // Add a random alias for the name field and save the view.
+    $random_name = $this->randomName();
+    $this->drupalPost($row_options, array('row_options[aliases][name]' => $random_name), t('Apply'));
+    $this->drupalPost(NULL, array(), t('Save'));
+
+    $view = views_get_view('test_serialize_display_field');
+    $view->setDisplay('data_1');
+    $this->executeView($view);
+
+    $expected = array();
+    foreach ($view->result as $row) {
+      $expected_row = array();
+      foreach ($view->field as $id => $field) {
+        $expected_row[$random_name] = $row->{$field->field_alias};
+      }
+      $expected[] = $expected_row;
+    }
+
+    $this->assertIdentical($this->drupalGet('test/serialize/field', array(), array('Content-type: application/json')), json_encode($expected));
+  }
+
+}
diff --git a/core/modules/views/lib/Drupal/views/ViewExecutable.php b/core/modules/views/lib/Drupal/views/ViewExecutable.php
index 639cd92..e3f2d3d 100644
--- a/core/modules/views/lib/Drupal/views/ViewExecutable.php
+++ b/core/modules/views/lib/Drupal/views/ViewExecutable.php
@@ -1228,9 +1228,6 @@ public function render($display_id = NULL) {
     drupal_theme_initialize();
     $config = config('views.settings');
 
-    // Set the response so other parts can alter it.
-    $this->response = new Response('', 200);
-
     $start = microtime(TRUE);
     if (!empty($this->live_preview) && $config->get('ui.show.additional_queries')) {
       $this->startQueryCapture();
@@ -1261,6 +1258,11 @@ public function render($display_id = NULL) {
       // Initialize the style plugin.
       $this->initStyle();
 
+      if (!isset($this->response)) {
+        // Set the response so other parts can alter it.
+        $this->response = new Response('', 200);
+      }
+
       // Give field handlers the opportunity to perform additional queries
       // using the entire resultset prior to rendering.
       if ($this->style_plugin->usesFields()) {
diff --git a/core/modules/views/tests/views_test_config/config/views.view.test_serialize_display_entity.yml b/core/modules/views/tests/views_test_config/config/views.view.test_serialize_display_entity.yml
new file mode 100644
index 0000000..f9a3836
--- /dev/null
+++ b/core/modules/views/tests/views_test_config/config/views.view.test_serialize_display_entity.yml
@@ -0,0 +1,49 @@
+base_table: node
+name: test_serialize_display_entity
+description: ''
+tag: ''
+human_name: 'Test serialize display entity rows'
+core: 8.x
+api_version: '3.0'
+display:
+  default:
+    display_plugin: default
+    id: default
+    display_title: Master
+    position: ''
+    display_options:
+      access:
+        type: perm
+        options:
+          perm: 'access content'
+      cache:
+        type: none
+      query:
+        type: views_query
+      exposed_form:
+        type: basic
+      style:
+        type: serialize
+      row:
+        type: data_entity
+      sorts:
+        created:
+          id: created
+          table: node
+          field: created
+          order: DESC
+      title: 'Test serialize'
+      arguments: {  }
+  data_1:
+    display_plugin: data
+    id: data_1
+    display_title: serialize
+    position: ''
+    display_options:
+      defaults:
+        access: false
+      path: test/serialize/entity
+base_field: nid
+disabled: '0'
+module: views
+langcode: und
diff --git a/core/modules/views/tests/views_test_config/config/views.view.test_serialize_display_field.yml b/core/modules/views/tests/views_test_config/config/views.view.test_serialize_display_field.yml
new file mode 100644
index 0000000..a3214e5
--- /dev/null
+++ b/core/modules/views/tests/views_test_config/config/views.view.test_serialize_display_field.yml
@@ -0,0 +1,82 @@
+base_table: views_test_data
+name: test_serialize_display_field
+description: ''
+tag: ''
+human_name: 'Test serialize display field rows'
+core: 8.x
+api_version: '3.0'
+display:
+  default:
+    display_plugin: default
+    id: default
+    display_title: Master
+    position: ''
+    display_options:
+      access:
+        type: perm
+        options:
+          perm: 'access content'
+      cache:
+        type: none
+      query:
+        type: views_query
+      exposed_form:
+        type: basic
+      style:
+        type: serialize
+      row:
+        type: data_field
+      fields:
+        name:
+          id: name
+          table: views_test_data
+          field: name
+          label: ''
+      sorts:
+        created:
+          id: created
+          table: views_test_data
+          field: created
+          order: DESC
+      title: 'Test serialize'
+      arguments: {  }
+  data_1:
+    display_plugin: data
+    id: data_1
+    display_title: serialize
+    position: ''
+    display_options:
+      defaults:
+        access: false
+        style: false
+        row: false
+      path: test/serialize/field
+      access:
+        type: none
+      style:
+        type: serialize
+      row:
+        type: data_field
+  data_2:
+    display_plugin: data
+    id: data_2
+    display_title: 'serialize - access denied'
+    position: ''
+    display_options:
+      defaults:
+        access: false
+        style: false
+        row: false
+      path: test/serialize/denied
+      access:
+        type: perm
+        options:
+          perm: 'administer views'
+      style:
+        type: serialize
+      row:
+        type: data_field
+base_field: id
+disabled: '0'
+module: views
+langcode: und
