From 4a8bbfbb73b46332a36ae2ca73027701874a2335 Mon Sep 17 00:00:00 2001
From: webchick <webchick@24967.no-reply.drupal.org>
Date: Fri, 28 Mar 2014 16:07:00 -0700
Subject: [PATCH] Issue #2215961 by tim.plunkett, Berdir: Entity::urlInfo()
 should return \Drupal\Core\Url.

---
 .../Config/Entity/ConfigEntityListBuilder.php |   4 +-
 core/lib/Drupal/Core/Entity/Entity.php        |  48 +++----
 .../Core/Entity/EntityFormController.php      |   4 +-
 .../Drupal/Core/Entity/EntityInterface.php    |   5 +-
 .../Drupal/Core/Entity/EntityListBuilder.php  |   4 +-
 .../UndefinedLinkTemplateException.php        |  15 +++
 .../CustomBlockTypeFormController.php         |   3 +-
 .../CustomBlockTypeListBuilder.php            |   3 +-
 core/modules/comment/comment.module           |  32 +++--
 .../comment/CommentBreadcrumbBuilder.php      |   3 +-
 .../Drupal/comment/CommentFormController.php  |   3 +-
 .../lib/Drupal/comment/CommentInterface.php   |   5 +-
 .../comment/CommentManagerInterface.php       |   3 +-
 .../comment/Controller/CommentController.php  |  16 +--
 .../lib/Drupal/comment/Entity/Comment.php     |   3 +-
 .../comment/Form/CommentAdminOverview.php     |  24 ++--
 .../lib/Drupal/comment/Form/DeleteForm.php    |   4 +-
 .../config/Tests/ConfigEntityListTest.php     |  10 +-
 .../config_translation.module                 |   2 +-
 .../Drupal/contact/CategoryFormController.php |   3 +-
 .../content_translation.module                |   2 +-
 .../EntityReferenceLabelFormatter.php         |   5 +-
 core/modules/field_ui/field_ui.module         |   6 +-
 .../Drupal/forum/Form/ForumFormController.php |   4 +-
 .../Drupal/image/Form/ImageEffectFormBase.php |   5 +-
 .../Drupal/image/ImageStyleListBuilder.php    |   2 +-
 .../Field/FieldFormatter/ImageFormatter.php   |   5 +-
 .../lib/Drupal/menu/MenuFormController.php    |   3 +-
 .../menu/lib/Drupal/menu/MenuListBuilder.php  |   2 +-
 core/modules/menu_link/menu_link.module       |   6 +-
 .../Drupal/node/Controller/NodeController.php |   1 -
 .../lib/Drupal/node/Form/NodeDeleteForm.php   |   4 +-
 .../node/lib/Drupal/node/NodeListBuilder.php  |   8 +-
 core/modules/node/node.module                 |  10 +-
 core/modules/rdf/rdf.module                   |   2 +-
 .../ResponsiveImageMappingListBuilder.php     |   2 +-
 .../shortcut/ShortcutSetListBuilder.php       |   2 +-
 core/modules/system/entity.api.php            |   2 +-
 .../Drupal/taxonomy/Form/OverviewTerms.php    |  11 +-
 .../Field/FieldFormatter/LinkFormatter.php    |   6 +-
 .../taxonomy/VocabularyFormController.php     |   3 +-
 .../Drupal/taxonomy/VocabularyListBuilder.php |   4 +-
 core/modules/taxonomy/taxonomy.module         |  10 +-
 .../lib/Drupal/user/Form/UserCancelForm.php   |   4 +-
 .../lib/Drupal/user/RoleFormController.php    |   3 +-
 .../user/lib/Drupal/user/RoleListBuilder.php  |   2 +-
 core/modules/user/user.module                 |  10 +-
 .../views_ui/Form/Ajax/ReorderDisplays.php    |   2 +-
 .../views_ui/ViewEditFormController.php       |   4 +-
 .../views_ui/ViewFormControllerBase.php       |   2 +-
 .../lib/Drupal/views_ui/ViewListBuilder.php   |   2 +-
 .../views_ui/ViewPreviewFormController.php    |   4 +-
 .../Tests/Core/Entity/EntityUrlTest.php       | 124 +++++++++++-------
 53 files changed, 221 insertions(+), 235 deletions(-)
 create mode 100644 core/lib/Drupal/Core/Entity/Exception/UndefinedLinkTemplateException.php

diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityListBuilder.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityListBuilder.php
index 601de73da187..b42e63ae75fe 100644
--- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityListBuilder.php
+++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityListBuilder.php
@@ -38,13 +38,13 @@ public function getOperations(EntityInterface $entity) {
         $operations['enable'] = array(
           'title' => t('Enable'),
           'weight' => -10,
-        ) + $entity->urlInfo('enable');
+        ) + $entity->urlInfo('enable')->toArray();
       }
       elseif ($entity->hasLinkTemplate('disable')) {
         $operations['disable'] = array(
           'title' => t('Disable'),
           'weight' => 40,
-        ) + $entity->urlInfo('disable');
+        ) + $entity->urlInfo('disable')->toArray();
       }
     }
 
diff --git a/core/lib/Drupal/Core/Entity/Entity.php b/core/lib/Drupal/Core/Entity/Entity.php
index e56bb658845d..2245ad7662e4 100644
--- a/core/lib/Drupal/Core/Entity/Entity.php
+++ b/core/lib/Drupal/Core/Entity/Entity.php
@@ -8,8 +8,11 @@
 namespace Drupal\Core\Entity;
 
 use Drupal\Core\DependencyInjection\DependencySerialization;
+use Drupal\Component\Utility\String;
+use Drupal\Core\Entity\Exception\UndefinedLinkTemplateException;
 use Drupal\Core\Language\Language;
 use Drupal\Core\Session\AccountInterface;
+use Drupal\Core\Url;
 
 /**
  * Defines a base entity class.
@@ -30,13 +33,6 @@ abstract class Entity extends DependencySerialization implements EntityInterface
    */
   protected $enforceIsNew;
 
-  /**
-   * The URL generator.
-   *
-   * @var \Drupal\Core\Routing\UrlGeneratorInterface
-   */
-  protected $urlGenerator;
-
   /**
    * Constructs an Entity object.
    *
@@ -153,8 +149,7 @@ public function urlInfo($rel = 'canonical') {
 
     if (isset($link_templates[$rel])) {
       // If there is a template for the given relationship type, generate the path.
-      $uri['route_name'] = $link_templates[$rel];
-      $uri['route_parameters'] = $this->urlRouteParameters($rel);
+      $uri = new Url($link_templates[$rel], $this->urlRouteParameters($rel));
     }
     else {
       $bundle = $this->bundle();
@@ -174,14 +169,18 @@ public function urlInfo($rel = 'canonical') {
         $uri = call_user_func($uri_callback, $this);
       }
       else {
-        return array();
+        throw new UndefinedLinkTemplateException(String::format('No link template "@rel" found for the "@entity_type" entity type', array(
+          '@rel' => $rel,
+          '@entity_type' => $this->getEntityTypeId(),
+        )));
       }
     }
 
     // Pass the entity data to url() so that alter functions do not need to
     // look up this entity again.
-    $uri['options']['entity_type'] = $this->getEntityTypeId();
-    $uri['options']['entity'] = $this;
+    $uri
+      ->setOption('entity_type', $this->getEntityTypeId())
+      ->setOption('entity', $this);
 
     return $uri;
   }
@@ -190,8 +189,8 @@ public function urlInfo($rel = 'canonical') {
    * {@inheritdoc}
    */
   public function getSystemPath($rel = 'canonical') {
-    if ($uri = $this->urlInfo($rel)) {
-      return $this->urlGenerator()->getPathFromRoute($uri['route_name'], $uri['route_parameters']);
+    if ($this->hasLinkTemplate($rel) && $uri = $this->urlInfo($rel)) {
+      return $uri->getInternalPath();
     }
     return '';
   }
@@ -220,12 +219,14 @@ protected function linkTemplates() {
   public function url($rel = 'canonical', $options = array()) {
     // While self::urlInfo() will throw an exception if the entity is new,
     // the expected result for a URL is always a string.
-    if ($this->isNew() || !$uri = $this->urlInfo($rel)) {
+    if ($this->isNew() || !$this->hasLinkTemplate($rel)) {
       return '';
     }
 
-    $options += $uri['options'];
-    return $this->urlGenerator()->generateFromRoute($uri['route_name'], $uri['route_parameters'], $options);
+    $uri = $this->urlInfo($rel);
+    $options += $uri->getOptions();
+    $uri->setOptions($options);
+    return $uri->toString();
   }
 
   /**
@@ -419,19 +420,6 @@ protected function onUpdateBundleEntity() {
     }
   }
 
-  /**
-   * Wraps the URL generator.
-   *
-   * @return \Drupal\Core\Routing\UrlGeneratorInterface
-   *   The URL generator.
-   */
-  protected function urlGenerator() {
-    if (!$this->urlGenerator) {
-      $this->urlGenerator = \Drupal::urlGenerator();
-    }
-    return $this->urlGenerator;
-  }
-
   /**
    * {@inheritdoc}
    */
diff --git a/core/lib/Drupal/Core/Entity/EntityFormController.php b/core/lib/Drupal/Core/Entity/EntityFormController.php
index 28ace6bca188..ff13761442ec 100644
--- a/core/lib/Drupal/Core/Entity/EntityFormController.php
+++ b/core/lib/Drupal/Core/Entity/EntityFormController.php
@@ -286,7 +286,9 @@ public function delete(array $form, array &$form_state) {
 
       $query = $this->getRequest()->query;
       if ($query->has('destination')) {
-        $form_state['redirect_route']['options']['query']['destination'] = $query->get('destination');
+        $redirect_query = $form_state['redirect_route']->getOption('query') ?: array();
+        $redirect_query['destination'] = $query->get('destination');
+        $form_state['redirect_route']->setOption('query', $redirect_query);
         $query->remove('destination');
       }
     }
diff --git a/core/lib/Drupal/Core/Entity/EntityInterface.php b/core/lib/Drupal/Core/Entity/EntityInterface.php
index e2a5b64cc962..37361d6d90d5 100644
--- a/core/lib/Drupal/Core/Entity/EntityInterface.php
+++ b/core/lib/Drupal/Core/Entity/EntityInterface.php
@@ -120,10 +120,7 @@ public function label();
    * @param string $rel
    *   The link relationship type, for example: canonical or edit-form.
    *
-   * @return mixed[]
-   *   An array containing 'route_name', 'route_parameters' and 'options' keys
-   *   used to build the URI of the entity and matching the signature of
-   *   \Drupal::url().
+   * @return \Drupal\Core\Url
    */
   public function urlInfo($rel = 'canonical');
 
diff --git a/core/lib/Drupal/Core/Entity/EntityListBuilder.php b/core/lib/Drupal/Core/Entity/EntityListBuilder.php
index 53620920686f..33a400883388 100644
--- a/core/lib/Drupal/Core/Entity/EntityListBuilder.php
+++ b/core/lib/Drupal/Core/Entity/EntityListBuilder.php
@@ -98,13 +98,13 @@ public function getOperations(EntityInterface $entity) {
       $operations['edit'] = array(
         'title' => $this->t('Edit'),
         'weight' => 10,
-      ) + $entity->urlInfo('edit-form');
+      ) + $entity->urlInfo('edit-form')->toArray();
     }
     if ($entity->access('delete') && $entity->hasLinkTemplate('delete-form')) {
       $operations['delete'] = array(
         'title' => $this->t('Delete'),
         'weight' => 100,
-      ) + $entity->urlInfo('delete-form');
+      ) + $entity->urlInfo('delete-form')->toArray();
     }
 
     return $operations;
diff --git a/core/lib/Drupal/Core/Entity/Exception/UndefinedLinkTemplateException.php b/core/lib/Drupal/Core/Entity/Exception/UndefinedLinkTemplateException.php
new file mode 100644
index 000000000000..daed648d9832
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/Exception/UndefinedLinkTemplateException.php
@@ -0,0 +1,15 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Entity\Exception\UndefinedLinkTemplateException.
+ */
+
+namespace Drupal\Core\Entity\Exception;
+
+/**
+ * Defines an exception class for undefined link templates.
+ */
+class UndefinedLinkTemplateException extends \RuntimeException {
+
+}
diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeFormController.php b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeFormController.php
index 10dea1c51306..575878852b06 100644
--- a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeFormController.php
+++ b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeFormController.php
@@ -89,8 +89,7 @@ public function save(array $form, array &$form_state) {
     $block_type = $this->entity;
     $status = $block_type->save();
 
-    $uri = $block_type->urlInfo();
-    $edit_link = \Drupal::l($this->t('Edit'), $uri['route_name'], $uri['route_parameters'], $uri['options']);
+    $edit_link = \Drupal::linkGenerator()->generateFromUrl($this->t('Edit'), $this->entity->urlInfo());
     if ($status == SAVED_UPDATED) {
       drupal_set_message(t('Custom block type %label has been updated.', array('%label' => $block_type->label())));
       watchdog('custom_block', 'Custom block type %label has been updated.', array('%label' => $block_type->label()), WATCHDOG_NOTICE, $edit_link);
diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeListBuilder.php b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeListBuilder.php
index 901ef6f698ae..1c09e9f72c30 100644
--- a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeListBuilder.php
+++ b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeListBuilder.php
@@ -43,8 +43,7 @@ public function buildHeader() {
    * {@inheritdoc}
    */
   public function buildRow(EntityInterface $entity) {
-    $uri = $entity->urlInfo();
-    $row['type'] = \Drupal::l($entity->label(), $uri['route_name'], $uri['route_parameters'], $uri['options']);
+    $row['type'] = \Drupal::linkGenerator()->generateFromUrl($entity->label(), $entity->urlInfo());
     $row['description'] = filter_xss_admin($entity->description);
     return $row + parent::buildRow($entity);
   }
diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index 55622b5d26fc..a5e9ec0d0dba 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -14,6 +14,7 @@
 use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
+use Drupal\Core\Url;
 use Drupal\field\FieldInstanceConfigInterface;
 use Drupal\field\FieldConfigInterface;
 use Drupal\file\FileInterface;
@@ -111,12 +112,12 @@ function comment_entity_bundle_info() {
  * Entity URI callback.
  */
 function comment_uri(CommentInterface $comment) {
-  return array(
-    'route_name' => 'comment.permalink',
-    'route_parameters' => array(
+  return new Url(
+    'comment.permalink',
+    array(
       'comment' => $comment->id(),
     ),
-    'options' => array('fragment' => 'comment-' . $comment->id()),
+    array('fragment' => 'comment-' . $comment->id())
   );
 }
 
@@ -442,7 +443,7 @@ function comment_node_links_alter(array &$node_links, NodeInterface $node, array
               'attributes' => array('title' => t('Jump to the first comment of this posting.')),
               'fragment' => 'comments',
               'html' => TRUE,
-            ) + $node->urlInfo();
+            ) + $node->urlInfo()->toArray();
             if (\Drupal::moduleHandler()->moduleExists('history')) {
               $links['comment-new-comments'] = array(
                 'title' => '',
@@ -476,7 +477,7 @@ function comment_node_links_alter(array &$node_links, NodeInterface $node, array
               );
             }
             else {
-              $links['comment-add'] += $node->urlInfo();
+              $links['comment-add'] += $node->urlInfo()->toArray();
             }
           }
           else {
@@ -510,7 +511,7 @@ function comment_node_links_alter(array &$node_links, NodeInterface $node, array
                 );
               }
               else {
-                $links['comment-add'] += $node->urlInfo();
+                $links['comment-add'] += $node->urlInfo()->toArray();
               }
             }
           }
@@ -1354,11 +1355,12 @@ function template_preprocess_comment(&$variables) {
   }
   else {
     $uri = $comment->urlInfo();
-    $uri['options'] += array('attributes' => array('class' => array('permalink'), 'rel' => 'bookmark'));
-    $variables['title'] = \Drupal::l($comment->getSubject(), $uri['route_name'], $uri['route_parameters'], $uri['options']);
+    $attributes = $uri->getOption('attributes') ?: array();
+    $attributes += array('class' => array('permalink'), 'rel' => 'bookmark');
+    $uri->setOption('attributes', $attributes);
+    $variables['title'] = \Drupal::linkGenerator()->generateFromUrl($comment->getSubject(), $uri);
 
-    $permalink_uri = $comment->permalink();
-    $variables['permalink'] = \Drupal::l(t('Permalink'), $permalink_uri['route_name'], $permalink_uri['route_parameters'], $permalink_uri['options']);
+    $variables['permalink'] = \Drupal::linkGenerator()->generateFromUrl(t('Permalink'), $comment->permalink());
   }
 
   $variables['submitted'] = t('Submitted by !username on !datetime', array('!username' => $variables['author'], '!datetime' => $variables['created']));
@@ -1382,9 +1384,11 @@ function template_preprocess_comment(&$variables) {
       $variables['parent_changed'] = format_date($comment_parent->getChangedTime());
     }
     $permalink_uri_parent = $comment_parent->permalink();
-    $permalink_uri_parent['options'] += array('attributes' => array('class' => array('permalink'), 'rel' => 'bookmark'));
-    $variables['parent_title'] = \Drupal::l($comment_parent->getSubject(), $permalink_uri_parent['route_name'], $permalink_uri_parent['route_parameters'], $permalink_uri_parent['options']);
-    $variables['parent_permalink'] = \Drupal::l(t('Parent permalink'), $permalink_uri_parent['route_name'], $permalink_uri_parent['route_parameters'], $permalink_uri_parent['options']);
+    $attributes = $permalink_uri_parent->getOption('attributes') ?: array();
+    $attributes += array('class' => array('permalink'), 'rel' => 'bookmark');
+    $permalink_uri_parent->setOption('attributes', $attributes);
+    $variables['parent_title'] = \Drupal::linkGenerator()->generateFromUrl($comment_parent->getSubject(), $permalink_uri_parent);
+    $variables['parent_permalink'] = \Drupal::linkGenerator()->generateFromUrl(t('Parent permalink'), $permalink_uri_parent);
     $variables['parent'] = t('In reply to !parent_title by !parent_username',
         array('!parent_username' => $variables['parent_author'], '!parent_title' => $variables['parent_title']));
   }
diff --git a/core/modules/comment/lib/Drupal/comment/CommentBreadcrumbBuilder.php b/core/modules/comment/lib/Drupal/comment/CommentBreadcrumbBuilder.php
index 1c84cfacd877..9626963c887f 100644
--- a/core/modules/comment/lib/Drupal/comment/CommentBreadcrumbBuilder.php
+++ b/core/modules/comment/lib/Drupal/comment/CommentBreadcrumbBuilder.php
@@ -53,8 +53,7 @@ public function build(array $attributes) {
     $entity = $this->entityManager
       ->getStorage($attributes['entity_type'])
       ->load($attributes['entity_id']);
-    $uri = $entity->urlInfo();
-    $breadcrumb[] = \Drupal::l($entity->label(), $uri['route_name'], $uri['route_parameters'], $uri['options']);
+    $breadcrumb[] = \Drupal::linkGenerator()->generateFromUrl($entity->label(), $entity->urlInfo());
     return $breadcrumb;
   }
 
diff --git a/core/modules/comment/lib/Drupal/comment/CommentFormController.php b/core/modules/comment/lib/Drupal/comment/CommentFormController.php
index a73ab15754ce..1e9a46017efa 100644
--- a/core/modules/comment/lib/Drupal/comment/CommentFormController.php
+++ b/core/modules/comment/lib/Drupal/comment/CommentFormController.php
@@ -410,7 +410,8 @@ public function save(array $form, array &$form_state) {
         $query['page'] = $page;
       }
       // Redirect to the newly posted comment.
-      $uri['options'] += array('query' => $query, 'fragment' => 'comment-' . $comment->id());
+      $uri->setOption('query', $query);
+      $uri->setOption('fragment', 'comment-' . $comment->id());
     }
     else {
       watchdog('content', 'Comment: unauthorized comment submitted or comment submitted to a closed post %subject.', array('%subject' => $comment->getSubject()), WATCHDOG_WARNING);
diff --git a/core/modules/comment/lib/Drupal/comment/CommentInterface.php b/core/modules/comment/lib/Drupal/comment/CommentInterface.php
index d42b98047a97..48af29455635 100644
--- a/core/modules/comment/lib/Drupal/comment/CommentInterface.php
+++ b/core/modules/comment/lib/Drupal/comment/CommentInterface.php
@@ -254,10 +254,7 @@ public function setThread($thread);
   /**
    * Returns the permalink URL for this comment.
    *
-   * @return array
-   *   An array containing the 'path' and 'options' keys used to build the URI
-   *   of the comment, and matching the signature of
-   *   UrlGenerator::generateFromPath().
+   * @return \Drupal\Core\Url
    */
   public function permalink();
 
diff --git a/core/modules/comment/lib/Drupal/comment/CommentManagerInterface.php b/core/modules/comment/lib/Drupal/comment/CommentManagerInterface.php
index 723d173145e2..52de70864b22 100644
--- a/core/modules/comment/lib/Drupal/comment/CommentManagerInterface.php
+++ b/core/modules/comment/lib/Drupal/comment/CommentManagerInterface.php
@@ -21,8 +21,7 @@ interface CommentManagerInterface {
    * @param \Drupal\comment\CommentInterface $comment
    *   The comment entity.
    *
-   * @return array
-   *   An array returned by \Drupal\Core\Entity\EntityInterface::uri().
+   * @return \Drupal\Core\Url
    */
   public function getParentEntityUri(CommentInterface $comment);
 
diff --git a/core/modules/comment/lib/Drupal/comment/Controller/CommentController.php b/core/modules/comment/lib/Drupal/comment/Controller/CommentController.php
index 07917693871b..782995066771 100644
--- a/core/modules/comment/lib/Drupal/comment/Controller/CommentController.php
+++ b/core/modules/comment/lib/Drupal/comment/Controller/CommentController.php
@@ -91,9 +91,8 @@ public function commentApprove(CommentInterface $comment) {
 
     drupal_set_message($this->t('Comment approved.'));
     $permalink_uri = $comment->permalink();
-    $permalink_uri['options']['absolute'] = TRUE;
-    $url = $this->urlGenerator()->generateFromRoute($permalink_uri['route_name'], $permalink_uri['route_parameters'], $permalink_uri['options']);
-    return new RedirectResponse($url);
+    $permalink_uri->setAbsolute();
+    return new RedirectResponse($permalink_uri->toString());
   }
 
   /**
@@ -213,14 +212,13 @@ public function getReplyForm(Request $request, $entity_type, $entity_id, $field_
     }
 
     $account = $this->currentUser();
-    $uri = $entity->urlInfo();
-    $path = $entity->getSystemPath();
+    $uri = $entity->urlInfo()->setAbsolute();
     $build = array();
 
     // Check if the user has the proper permissions.
     if (!$account->hasPermission('post comments')) {
       drupal_set_message($this->t('You are not authorized to post comments.'), 'error');
-      return $this->redirect($uri['route_name'], $uri['route_parameters']);
+      return new RedirectResponse($uri->toString());
     }
 
     // The user is not just previewing a comment.
@@ -228,7 +226,7 @@ public function getReplyForm(Request $request, $entity_type, $entity_id, $field_
       $status = $entity->{$field_name}->status;
       if ($status != CommentItemInterface::OPEN) {
         drupal_set_message($this->t("This discussion is closed: you can't post new comments."), 'error');
-        return $this->redirect($uri['route_name'], $uri['route_parameters']);
+        return new RedirectResponse($uri->toString());
       }
 
       // $pid indicates that this is a reply to a comment.
@@ -236,14 +234,14 @@ public function getReplyForm(Request $request, $entity_type, $entity_id, $field_
         // Check if the user has the proper permissions.
         if (!$account->hasPermission('access comments')) {
           drupal_set_message($this->t('You are not authorized to view comments.'), 'error');
-          return $this->redirect($uri['route_name'], $uri['route_parameters']);
+          return new RedirectResponse($uri->toString());
         }
         // Load the parent comment.
         $comment = $this->entityManager()->getStorage('comment')->load($pid);
         // Check if the parent comment is published and belongs to the entity.
         if (!$comment->isPublished() || ($comment->getCommentedEntityId() != $entity->id())) {
           drupal_set_message($this->t('The comment you are replying to does not exist.'), 'error');
-          return $this->redirect($uri['route_name'], $uri['route_parameters']);
+          return new RedirectResponse($uri->toString());
         }
         // Display the parent comment.
         $build['comment_parent'] = $this->entityManager()->getViewBuilder('comment')->view($comment);
diff --git a/core/modules/comment/lib/Drupal/comment/Entity/Comment.php b/core/modules/comment/lib/Drupal/comment/Entity/Comment.php
index c5e3432a9ba2..69adba843e7c 100644
--- a/core/modules/comment/lib/Drupal/comment/Entity/Comment.php
+++ b/core/modules/comment/lib/Drupal/comment/Entity/Comment.php
@@ -199,8 +199,7 @@ public function referencedEntities() {
   public function permalink() {
     $entity = $this->getCommentedEntity();
     $uri = $entity->urlInfo();
-    $uri['options'] = array('fragment' => 'comment-' . $this->id());
-
+    $uri->setOption('fragment', 'comment-' . $this->id());
     return $uri;
   }
 
diff --git a/core/modules/comment/lib/Drupal/comment/Form/CommentAdminOverview.php b/core/modules/comment/lib/Drupal/comment/Form/CommentAdminOverview.php
index 9b54bf183ad4..efac3aa73383 100644
--- a/core/modules/comment/lib/Drupal/comment/Form/CommentAdminOverview.php
+++ b/core/modules/comment/lib/Drupal/comment/Form/CommentAdminOverview.php
@@ -182,7 +182,6 @@ public function buildForm(array $form, array &$form_state, $type = 'new') {
     foreach ($comments as $comment) {
       /** @var $commented_entity \Drupal\Core\Entity\EntityInterface */
       $commented_entity = $commented_entities[$comment->getCommentedEntityTypeId()][$comment->getCommentedEntityId()];
-      $commented_entity_uri = $commented_entity->urlInfo();
       $username = array(
         '#theme' => 'username',
         '#account' => comment_prepare_author($comment),
@@ -192,41 +191,34 @@ public function buildForm(array $form, array &$form_state, $type = 'new') {
         $body = $comment->comment_body->value;
       }
       $comment_permalink = $comment->permalink();
+      $attributes = $comment_permalink->getOption('attributes') ?: array();
+      $attributes += array('title' => Unicode::truncate($body, 128));
+      $comment_permalink->setOption('attributes', $attributes);
       $options[$comment->id()] = array(
         'title' => array('data' => array('#title' => $comment->getSubject() ?: $comment->id())),
         'subject' => array(
           'data' => array(
             '#type' => 'link',
             '#title' => $comment->getSubject(),
-            '#route_name' => $comment_permalink['route_name'],
-            '#route_parameters' => $comment_permalink['route_parameters'],
-            '#options' => $comment_permalink['options'] + array(
-              'attributes' => array(
-                'title' => Unicode::truncate($body, 128),
-              ),
-            ),
-          ),
+          ) + $comment_permalink->toRenderArray(),
         ),
         'author' => drupal_render($username),
         'posted_in' => array(
           'data' => array(
             '#type' => 'link',
             '#title' => $commented_entity->label(),
-            '#route_name' => $commented_entity_uri['route_name'],
-            '#route_parameters' => $commented_entity_uri['route_parameters'],
-            '#options' => $commented_entity_uri['options'],
             '#access' => $commented_entity->access('view'),
-          ),
+          ) + $commented_entity->urlInfo()->toRenderArray(),
         ),
         'changed' => $this->date->format($comment->getChangedTime(), 'short'),
       );
-      $comment_uri = $comment->urlInfo();
+      $comment_uri_options = $comment->urlInfo()->getOptions();
       $links = array();
       $links['edit'] = array(
         'title' => $this->t('edit'),
         'route_name' => 'comment.edit_page',
         'route_parameters' => array('comment' => $comment->id()),
-        'options' => $comment_uri['options'],
+        'options' => $comment_uri_options,
         'query' => $destination,
       );
       if ($this->moduleHandler->invoke('content_translation', 'translate_access', array($comment))) {
@@ -234,7 +226,7 @@ public function buildForm(array $form, array &$form_state, $type = 'new') {
           'title' => $this->t('translate'),
           'route_name' => 'content_translation.translation_overview_comment',
           'route_parameters' => array('comment' => $comment->id()),
-          'options' => $comment_uri['options'],
+          'options' => $comment_uri_options,
           'query' => $destination,
         );
       }
diff --git a/core/modules/comment/lib/Drupal/comment/Form/DeleteForm.php b/core/modules/comment/lib/Drupal/comment/Form/DeleteForm.php
index f2263053c014..b2687f12c91e 100644
--- a/core/modules/comment/lib/Drupal/comment/Form/DeleteForm.php
+++ b/core/modules/comment/lib/Drupal/comment/Form/DeleteForm.php
@@ -62,9 +62,7 @@ protected function actions(array $form, array &$form_state) {
     $actions = parent::actions($form, $form_state);
 
     // @todo Convert to getCancelRoute() after http://drupal.org/node/1987778.
-    $uri = $this->commentManager->getParentEntityUri($this->entity);
-    $actions['cancel']['#route_name'] = $uri['route_name'];
-    $actions['cancel']['#route_parameters'] = $uri['route_parameters'];
+    $actions['cancel'] += $this->commentManager->getParentEntityUri($this->entity)->toRenderArray();
 
     return $actions;
   }
diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigEntityListTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigEntityListTest.php
index 33ec8caa9374..71b7a4d27410 100644
--- a/core/modules/config/lib/Drupal/config/Tests/ConfigEntityListTest.php
+++ b/core/modules/config/lib/Drupal/config/Tests/ConfigEntityListTest.php
@@ -54,15 +54,15 @@ function testList() {
       'edit' => array (
         'title' => t('Edit'),
         'weight' => 10,
-      ) + $entity->urlInfo(),
+      ) + $entity->urlInfo()->toArray(),
       'disable' => array(
         'title' => t('Disable'),
         'weight' => 40,
-      ) + $entity->urlInfo('disable'),
+      ) + $entity->urlInfo('disable')->toArray(),
       'delete' => array (
         'title' => t('Delete'),
         'weight' => 100,
-      ) + $entity->urlInfo('delete-form'),
+      ) + $entity->urlInfo('delete-form')->toArray(),
     );
 
     $actual_operations = $controller->getOperations($entity);
@@ -126,11 +126,11 @@ function testList() {
       'edit' => array(
         'title' => t('Edit'),
         'weight' => 10,
-      ) + $entity->urlInfo(),
+      ) + $entity->urlInfo()->toArray(),
       'delete' => array(
         'title' => t('Delete'),
         'weight' => 100,
-      ) + $entity->urlInfo('delete-form'),
+      ) + $entity->urlInfo('delete-form')->toArray(),
     );
 
     $actual_operations = $controller->getOperations($entity);
diff --git a/core/modules/config_translation/config_translation.module b/core/modules/config_translation/config_translation.module
index e6f808150d6d..99bb8628b87d 100644
--- a/core/modules/config_translation/config_translation.module
+++ b/core/modules/config_translation/config_translation.module
@@ -166,7 +166,7 @@ function config_translation_entity_operation_alter(array &$operations, EntityInt
     $operations['translate'] = array(
       'title' => t('Translate'),
       'weight' => 50,
-    ) + $entity->urlInfo('drupal:config-translation-overview');
+    ) + $entity->urlInfo('drupal:config-translation-overview')->toArray();
   }
 }
 
diff --git a/core/modules/contact/lib/Drupal/contact/CategoryFormController.php b/core/modules/contact/lib/Drupal/contact/CategoryFormController.php
index 50b52030dd1e..58c71955d730 100644
--- a/core/modules/contact/lib/Drupal/contact/CategoryFormController.php
+++ b/core/modules/contact/lib/Drupal/contact/CategoryFormController.php
@@ -97,8 +97,7 @@ public function save(array $form, array &$form_state) {
     $category = $this->entity;
     $status = $category->save();
 
-    $uri = $category->urlInfo();
-    $edit_link = \Drupal::l($this->t('Edit'), $uri['route_name'], $uri['route_parameters'], $uri['options']);
+    $edit_link = \Drupal::linkGenerator()->generateFromUrl($this->t('Edit'), $this->entity->urlInfo());
 
     if ($status == SAVED_UPDATED) {
       drupal_set_message(t('Category %label has been updated.', array('%label' => $category->label())));
diff --git a/core/modules/content_translation/content_translation.module b/core/modules/content_translation/content_translation.module
index 0741231f7d8c..bf2461b2090e 100644
--- a/core/modules/content_translation/content_translation.module
+++ b/core/modules/content_translation/content_translation.module
@@ -195,7 +195,7 @@ function content_translation_entity_operation_alter(array &$operations, \Drupal\
   if ($entity instanceof NodeInterface && $entity->isTranslatable()) {
     $operations['translate'] = array(
       'title' => t('Translate'),
-    ) + $entity->urlInfo('drupal:content-translation-overview');
+    ) + $entity->urlInfo('drupal:content-translation-overview')->toArray();
   }
 }
 
diff --git a/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/Field/FieldFormatter/EntityReferenceLabelFormatter.php b/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/Field/FieldFormatter/EntityReferenceLabelFormatter.php
index a062f0bb8607..7cdac189ec60 100644
--- a/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/Field/FieldFormatter/EntityReferenceLabelFormatter.php
+++ b/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/Field/FieldFormatter/EntityReferenceLabelFormatter.php
@@ -74,10 +74,7 @@ public function viewElements(FieldItemListInterface $items) {
           $elements[$delta] = array(
             '#type' => 'link',
             '#title' => $label,
-            '#route_name' => $uri['route_name'],
-            '#route_parameters' => $uri['route_parameters'],
-            '#options' => $uri['options'],
-          );
+          ) + $uri->toRenderArray();
         }
         else {
           $elements[$delta] = array('#markup' => check_plain($label));
diff --git a/core/modules/field_ui/field_ui.module b/core/modules/field_ui/field_ui.module
index 40c8f286d192..5a111f87e583 100644
--- a/core/modules/field_ui/field_ui.module
+++ b/core/modules/field_ui/field_ui.module
@@ -183,19 +183,19 @@ function field_ui_entity_operation_alter(array &$operations, EntityInterface $en
       $operations['manage-fields'] = array(
         'title' => t('Manage fields'),
         'weight' => 15,
-      ) + $entity->urlInfo('field_ui-fields');
+      ) + $entity->urlInfo('field_ui-fields')->toArray();
     }
     if (user_access('administer '. $bundle_of . ' form display')) {
       $operations['manage-form-display'] = array(
         'title' => t('Manage form display'),
         'weight' => 20,
-      ) + $entity->urlInfo('field_ui-form-display');
+      ) + $entity->urlInfo('field_ui-form-display')->toArray();
     }
     if (user_access('administer '. $bundle_of . ' display')) {
       $operations['manage-display'] = array(
         'title' => t('Manage display'),
         'weight' => 25,
-      ) + $entity->urlInfo('field_ui-display');
+      ) + $entity->urlInfo('field_ui-display')->toArray();
     }
   }
 }
diff --git a/core/modules/forum/lib/Drupal/forum/Form/ForumFormController.php b/core/modules/forum/lib/Drupal/forum/Form/ForumFormController.php
index fc122253f6c9..17abb17fbde3 100644
--- a/core/modules/forum/lib/Drupal/forum/Form/ForumFormController.php
+++ b/core/modules/forum/lib/Drupal/forum/Form/ForumFormController.php
@@ -106,7 +106,9 @@ public function delete(array $form, array &$form_state) {
 
     $query = $this->getRequest()->query;
     if ($query->has('destination')) {
-      $form_state['redirect_route']['options']['query']['destination'] = $query->get('destination');
+      $redirect_query = $form_state['redirect_route']->getOption('query') ?: array();
+      $redirect_query['destination'] = $query->get('destination');
+      $form_state['redirect_route']->setOption('query', $redirect_query);
       $query->remove('destination');
     }
   }
diff --git a/core/modules/image/lib/Drupal/image/Form/ImageEffectFormBase.php b/core/modules/image/lib/Drupal/image/Form/ImageEffectFormBase.php
index 9525f35ae7b9..d4ee29b90d9d 100644
--- a/core/modules/image/lib/Drupal/image/Form/ImageEffectFormBase.php
+++ b/core/modules/image/lib/Drupal/image/Form/ImageEffectFormBase.php
@@ -86,7 +86,6 @@ public function buildForm(array $form, array &$form_state, ImageStyleInterface $
       '#value' => $request->query->has('weight') ? (int) $request->query->get('weight') : $this->imageEffect->getWeight(),
     );
 
-    $image_style_uri = $this->imageStyle->urlInfo('edit-form');
     $form['actions'] = array('#type' => 'actions');
     $form['actions']['submit'] = array(
       '#type' => 'submit',
@@ -95,9 +94,7 @@ public function buildForm(array $form, array &$form_state, ImageStyleInterface $
     $form['actions']['cancel'] = array(
       '#type' => 'link',
       '#title' => $this->t('Cancel'),
-      '#route_name' => $image_style_uri['route_name'],
-      '#route_parameters' => $image_style_uri['route_parameters'],
-    );
+    ) + $this->imageStyle->urlInfo('edit-form')->toRenderArray();
     return $form;
   }
 
diff --git a/core/modules/image/lib/Drupal/image/ImageStyleListBuilder.php b/core/modules/image/lib/Drupal/image/ImageStyleListBuilder.php
index 2b98b074983e..26642dd22c8d 100644
--- a/core/modules/image/lib/Drupal/image/ImageStyleListBuilder.php
+++ b/core/modules/image/lib/Drupal/image/ImageStyleListBuilder.php
@@ -78,7 +78,7 @@ public function getOperations(EntityInterface $entity) {
     $flush = array(
       'title' => t('Flush'),
       'weight' => 200,
-    ) + $entity->urlInfo('flush-form');
+    ) + $entity->urlInfo('flush-form')->toArray();
 
     return parent::getOperations($entity) + array('flush' => $flush);
   }
diff --git a/core/modules/image/lib/Drupal/image/Plugin/Field/FieldFormatter/ImageFormatter.php b/core/modules/image/lib/Drupal/image/Plugin/Field/FieldFormatter/ImageFormatter.php
index 69bf5f5d6dbc..28afbd19126d 100644
--- a/core/modules/image/lib/Drupal/image/Plugin/Field/FieldFormatter/ImageFormatter.php
+++ b/core/modules/image/lib/Drupal/image/Plugin/Field/FieldFormatter/ImageFormatter.php
@@ -101,9 +101,10 @@ public function viewElements(FieldItemListInterface $items) {
     $image_link_setting = $this->getSetting('image_link');
     // Check if the formatter involves a link.
     if ($image_link_setting == 'content') {
-      $uri = $items->getEntity()->urlInfo();
+      $entity = $items->getEntity();
       // @todo Remove when theme_image_formatter() has support for route name.
-      $uri['path'] = $items->getEntity()->getSystemPath();
+      $uri['path'] = $entity->getSystemPath();
+      $uri['options'] = $entity->urlInfo()->getOptions();
     }
     elseif ($image_link_setting == 'file') {
       $link_file = TRUE;
diff --git a/core/modules/menu/lib/Drupal/menu/MenuFormController.php b/core/modules/menu/lib/Drupal/menu/MenuFormController.php
index 9e0cfa924c2c..720d43553ad3 100644
--- a/core/modules/menu/lib/Drupal/menu/MenuFormController.php
+++ b/core/modules/menu/lib/Drupal/menu/MenuFormController.php
@@ -218,8 +218,7 @@ public function save(array $form, array &$form_state) {
 
     $status = $menu->save();
 
-    $uri = $menu->urlInfo();
-    $edit_link = \Drupal::l($this->t('Edit'), $uri['route_name'], $uri['route_parameters'], $uri['options']);
+    $edit_link = \Drupal::linkGenerator()->generateFromUrl($this->t('Edit'), $this->entity->urlInfo());
     if ($status == SAVED_UPDATED) {
       drupal_set_message(t('Menu %label has been updated.', array('%label' => $menu->label())));
       watchdog('menu', 'Menu %label has been updated.', array('%label' => $menu->label()), WATCHDOG_NOTICE, $edit_link);
diff --git a/core/modules/menu/lib/Drupal/menu/MenuListBuilder.php b/core/modules/menu/lib/Drupal/menu/MenuListBuilder.php
index 282ce008a955..31f5db447be9 100644
--- a/core/modules/menu/lib/Drupal/menu/MenuListBuilder.php
+++ b/core/modules/menu/lib/Drupal/menu/MenuListBuilder.php
@@ -53,7 +53,7 @@ public function getOperations(EntityInterface $entity) {
       $operations['add'] = array(
         'title' => t('Add link'),
         'weight' => 20,
-      ) + $entity->urlInfo('add-form');
+      ) + $entity->urlInfo('add-form')->toArray();
     }
     if (isset($operations['delete'])) {
       $operations['delete']['title'] = t('Delete menu');
diff --git a/core/modules/menu_link/menu_link.module b/core/modules/menu_link/menu_link.module
index 2c63de0ccf8e..ea3bb1f34c60 100644
--- a/core/modules/menu_link/menu_link.module
+++ b/core/modules/menu_link/menu_link.module
@@ -5,6 +5,7 @@
  * Enables users to create menu links.
  */
 
+use Drupal\Core\Url;
 use Drupal\menu_link\Entity\MenuLink;
 use Drupal\menu_link\MenuLinkInterface;
 use Symfony\Cmf\Component\Routing\RouteObjectInterface;
@@ -26,10 +27,7 @@ function menu_link_help($path, $arg) {
  *   A menu link entity.
  */
 function menu_link_uri(MenuLink $menu_link) {
-  return array(
-    'route_name' => $menu_link->route_name,
-    'route_parameters' => $menu_link->route_parameters,
-  );
+  return new Url($menu_link->route_name, $menu_link->route_parameters);
 }
 
 /**
diff --git a/core/modules/node/lib/Drupal/node/Controller/NodeController.php b/core/modules/node/lib/Drupal/node/Controller/NodeController.php
index f9e4d36532fc..b16b93d8b8ec 100644
--- a/core/modules/node/lib/Drupal/node/Controller/NodeController.php
+++ b/core/modules/node/lib/Drupal/node/Controller/NodeController.php
@@ -129,7 +129,6 @@ public function page(NodeInterface $node) {
     $build = $this->buildPage($node);
 
     foreach ($node->uriRelationships() as $rel) {
-      $uri = $node->urlInfo($rel);
       // Set the node path as the canonical URL to prevent duplicate content.
       $build['#attached']['drupal_add_html_head_link'][] = array(
         array(
diff --git a/core/modules/node/lib/Drupal/node/Form/NodeDeleteForm.php b/core/modules/node/lib/Drupal/node/Form/NodeDeleteForm.php
index a543f137a707..164ac5f420ca 100644
--- a/core/modules/node/lib/Drupal/node/Form/NodeDeleteForm.php
+++ b/core/modules/node/lib/Drupal/node/Form/NodeDeleteForm.php
@@ -62,9 +62,7 @@ protected function actions(array $form, array &$form_state) {
     $actions = parent::actions($form, $form_state);
 
     // @todo Convert to getCancelRoute() after http://drupal.org/node/1987778.
-    $uri = $this->entity->urlInfo();
-    $actions['cancel']['#route_name'] = $uri['route_name'];
-    $actions['cancel']['#route_parameters'] = $uri['route_parameters'];
+    $actions['cancel'] += $this->entity->urlInfo()->toRenderArray();
 
     return $actions;
   }
diff --git a/core/modules/node/lib/Drupal/node/NodeListBuilder.php b/core/modules/node/lib/Drupal/node/NodeListBuilder.php
index 7aa104cc8db2..c888155c7a01 100644
--- a/core/modules/node/lib/Drupal/node/NodeListBuilder.php
+++ b/core/modules/node/lib/Drupal/node/NodeListBuilder.php
@@ -98,14 +98,14 @@ public function buildRow(EntityInterface $entity) {
     );
     $langcode = $entity->language()->id;
     $uri = $entity->urlInfo();
+    $options = $uri->getOptions();
+    $options += ($langcode != Language::LANGCODE_NOT_SPECIFIED && isset($languages[$langcode]) ? array('language' => $languages[$langcode]) : array());
+    $uri->setOptions($options);
     $row['title']['data'] = array(
       '#type' => 'link',
       '#title' => $entity->label(),
-      '#route_name' => $uri['route_name'],
-      '#route_parameters' => $uri['route_parameters'],
-      '#options' => $uri['options'] + ($langcode != Language::LANGCODE_NOT_SPECIFIED && isset($languages[$langcode]) ? array('language' => $languages[$langcode]) : array()),
       '#suffix' => ' ' . drupal_render($mark),
-    );
+    ) + $uri->toRenderArray();
     $row['type'] = String::checkPlain(node_get_type_label($entity));
     $row['author']['data'] = array(
       '#theme' => 'username',
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index 7c429aeacdbe..21e88dd35471 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -9,6 +9,7 @@
  */
 
 use Drupal\Core\Language\Language;
+use Drupal\Core\Url;
 use Symfony\Component\HttpFoundation\Response;
 use Drupal\Core\Cache\Cache;
 use Drupal\Core\Database\Query\AlterableInterface;
@@ -230,12 +231,9 @@ function node_entity_form_display_alter(EntityFormDisplayInterface $form_display
  *   An array with 'path' as the key and the path to the node as its value.
  */
 function node_uri(NodeInterface $node) {
-  return array(
-    'route_name' => 'node.view',
-    'route_parameters' => array(
-      'node' => $node->id(),
-    ),
-  );
+  return new Url('node.view', array(
+    'node' => $node->id(),
+  ));
 }
 
 /**
diff --git a/core/modules/rdf/rdf.module b/core/modules/rdf/rdf.module
index 6bf0e106b619..bf8c60e606a9 100644
--- a/core/modules/rdf/rdf.module
+++ b/core/modules/rdf/rdf.module
@@ -351,7 +351,7 @@ function rdf_preprocess_user(&$variables) {
   }
   // If we are on the user account page, add the relationship between the
   // sioc:UserAccount and the foaf:Person who holds the account.
-  if (\Drupal::request()->attributes->get(RouteObjectInterface::ROUTE_NAME) == $uri['route_name']) {
+  if (\Drupal::request()->attributes->get(RouteObjectInterface::ROUTE_NAME) == $uri->getRouteName()) {
     // Adds the markup for username as language neutral literal, see
     // rdf_preprocess_username().
     $name_mapping = $mapping->getPreparedFieldMapping('name');
diff --git a/core/modules/responsive_image/lib/Drupal/responsive_image/ResponsiveImageMappingListBuilder.php b/core/modules/responsive_image/lib/Drupal/responsive_image/ResponsiveImageMappingListBuilder.php
index 1de736bf1b05..ce1f56d73400 100644
--- a/core/modules/responsive_image/lib/Drupal/responsive_image/ResponsiveImageMappingListBuilder.php
+++ b/core/modules/responsive_image/lib/Drupal/responsive_image/ResponsiveImageMappingListBuilder.php
@@ -41,7 +41,7 @@ public function getOperations(EntityInterface $entity) {
     $operations['duplicate'] = array(
       'title' => t('Duplicate'),
       'weight' => 15,
-    ) + $entity->urlInfo('duplicate-form');
+    ) + $entity->urlInfo('duplicate-form')->toArray();
     return $operations;
   }
 
diff --git a/core/modules/shortcut/lib/Drupal/shortcut/ShortcutSetListBuilder.php b/core/modules/shortcut/lib/Drupal/shortcut/ShortcutSetListBuilder.php
index 45b6a5f963af..fcdfb97a0eaa 100644
--- a/core/modules/shortcut/lib/Drupal/shortcut/ShortcutSetListBuilder.php
+++ b/core/modules/shortcut/lib/Drupal/shortcut/ShortcutSetListBuilder.php
@@ -37,7 +37,7 @@ public function getOperations(EntityInterface $entity) {
 
     $operations['list'] = array(
       'title' => t('List links'),
-    ) + $entity->urlInfo('customize-form');
+    ) + $entity->urlInfo('customize-form')->toArray();
     return $operations;
   }
 
diff --git a/core/modules/system/entity.api.php b/core/modules/system/entity.api.php
index 203b9cefc95e..315d55da3d71 100644
--- a/core/modules/system/entity.api.php
+++ b/core/modules/system/entity.api.php
@@ -768,7 +768,7 @@ function hook_entity_operation_alter(array &$operations, \Drupal\Core\Entity\Ent
   $operations['translate'] = array(
     'title' => t('Translate'),
     'weight' => 50,
-  ) + $entity->urlInfo('my-custom-link-template');
+  ) + $entity->urlInfo('my-custom-link-template')->toArray();
 }
 
 /**
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Form/OverviewTerms.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Form/OverviewTerms.php
index 13c8d2e43ec5..9187a65b1efe 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/Form/OverviewTerms.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Form/OverviewTerms.php
@@ -200,7 +200,6 @@ public function buildForm(array $form, array &$form_state, VocabularyInterface $
     );
     foreach ($current_page as $key => $term) {
       /** @var $term \Drupal\Core\Entity\EntityInterface */
-      $uri = $term->urlInfo();
       $form['terms'][$key]['#term'] = $term;
       $indentation = array();
       if (isset($term->depth) && $term->depth > 0) {
@@ -213,9 +212,7 @@ public function buildForm(array $form, array &$form_state, VocabularyInterface $
         '#prefix' => !empty($indentation) ? drupal_render($indentation) : '',
         '#type' => 'link',
         '#title' => $term->getName(),
-        '#route_name' => $uri['route_name'],
-        '#route_parameters' => $uri['route_parameters'],
-      );
+      ) + $term->urlInfo()->toRenderArray();
       if ($taxonomy_vocabulary->hierarchy != TAXONOMY_HIERARCHY_MULTIPLE && count($tree) > 1) {
         $parent_fields = TRUE;
         $form['terms'][$key]['term']['tid'] = array(
@@ -258,17 +255,17 @@ public function buildForm(array $form, array &$form_state, VocabularyInterface $
         'edit' => array(
           'title' => $this->t('edit'),
           'query' => $destination,
-        ) + $term->urlInfo('edit-form'),
+        ) + $term->urlInfo('edit-form')->toArray(),
         'delete' => array(
           'title' => $this->t('delete'),
           'query' => $destination,
-        ) + $term->urlInfo('delete-form'),
+        ) + $term->urlInfo('delete-form')->toArray(),
       );
       if ($this->moduleHandler->moduleExists('content_translation') && content_translation_translate_access($term)) {
         $operations['translate'] = array(
           'title' => $this->t('translate'),
           'query' => $destination,
-        ) + $term->urlInfo('drupal:content-translation-overview');
+        ) + $term->urlInfo('drupal:content-translation-overview')->toArray();
       }
       $form['terms'][$key]['operations'] = array(
         '#type' => 'operations',
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Field/FieldFormatter/LinkFormatter.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Field/FieldFormatter/LinkFormatter.php
index 6848c775ab80..eb0515c92fcc 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Field/FieldFormatter/LinkFormatter.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/Field/FieldFormatter/LinkFormatter.php
@@ -39,14 +39,10 @@ public function viewElements(FieldItemListInterface $items) {
       else {
         /** @var $term \Drupal\taxonomy\TermInterface */
         $term = $item->entity;
-        $uri = $term->urlInfo();
         $elements[$delta] = array(
           '#type' => 'link',
           '#title' => $term->getName(),
-          '#route_name' => $uri['route_name'],
-          '#route_parameters' => $uri['route_parameters'],
-          '#options' => $uri['options'],
-        );
+        ) + $term->urlInfo()->toRenderArray();
 
         if (!empty($item->_attributes)) {
           $elements[$delta]['#options'] += array('attributes' => array());
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyFormController.php b/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyFormController.php
index b6243516985f..3474bfbcddef 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyFormController.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyFormController.php
@@ -136,8 +136,7 @@ public function save(array $form, array &$form_state) {
     $vocabulary->name = trim($vocabulary->name);
 
     $status = $vocabulary->save();
-    $uri = $vocabulary->urlInfo();
-    $edit_link = \Drupal::l($this->t('edit'), $uri['route_name'], $uri['route_parameters'], $uri['options']);
+    $edit_link = \Drupal::linkGenerator()->generateFromUrl($this->t('edit'), $this->entity->urlInfo());
     switch ($status) {
       case SAVED_NEW:
         drupal_set_message($this->t('Created new vocabulary %name.', array('%name' => $vocabulary->name)));
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyListBuilder.php b/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyListBuilder.php
index 282355190558..f760aa50de26 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyListBuilder.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyListBuilder.php
@@ -42,11 +42,11 @@ public function getOperations(EntityInterface $entity) {
     $operations['list'] = array(
       'title' => t('list terms'),
       'weight' => 0,
-    ) + $entity->urlInfo('overview-form');
+    ) + $entity->urlInfo('overview-form')->toArray();
     $operations['add'] = array(
       'title' => t('add terms'),
       'weight' => 10,
-    ) + $entity->urlInfo('add-form');
+    ) + $entity->urlInfo('add-form')->toArray();
     unset($operations['delete']);
 
     return $operations;
diff --git a/core/modules/taxonomy/taxonomy.module b/core/modules/taxonomy/taxonomy.module
index b7046b4342fd..20060cbab802 100644
--- a/core/modules/taxonomy/taxonomy.module
+++ b/core/modules/taxonomy/taxonomy.module
@@ -8,6 +8,7 @@
 use Drupal\Component\Utility\Tags;
 use Drupal\Core\Entity\ContentEntityDatabaseStorage;
 use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Url;
 use Drupal\file\FileInterface;
 use Drupal\node\Entity\Node;
 use Drupal\taxonomy\Entity\Term;
@@ -126,12 +127,9 @@ function taxonomy_entity_bundle_info() {
  * Entity URI callback.
  */
 function taxonomy_term_uri($term) {
-  return array(
-    'route_name' => 'taxonomy.term_page',
-    'route_parameters' => array(
-      'taxonomy_term' => $term->id(),
-    ),
-  );
+  return new Url('taxonomy.term_page', array(
+    'taxonomy_term' => $term->id(),
+  ));
 }
 
 /**
diff --git a/core/modules/user/lib/Drupal/user/Form/UserCancelForm.php b/core/modules/user/lib/Drupal/user/Form/UserCancelForm.php
index cc31d1b5072d..eb05ee157c70 100644
--- a/core/modules/user/lib/Drupal/user/Form/UserCancelForm.php
+++ b/core/modules/user/lib/Drupal/user/Form/UserCancelForm.php
@@ -144,9 +144,7 @@ public function buildForm(array $form, array &$form_state) {
     $form = parent::buildForm($form, $form_state);
 
     // @todo Convert to getCancelRoute() after https://drupal.org/node/1987896.
-    $uri = $this->entity->urlInfo();
-    $form['actions']['cancel']['#route_name'] = $uri['route_name'];
-    $form['actions']['cancel']['#route_parameters'] = $uri['route_parameters'];
+    $form['actions']['cancel'] += $this->entity->urlInfo()->toRenderArray();
     return $form;
   }
 
diff --git a/core/modules/user/lib/Drupal/user/RoleFormController.php b/core/modules/user/lib/Drupal/user/RoleFormController.php
index 0cf8cd4ed3a9..873214f900b4 100644
--- a/core/modules/user/lib/Drupal/user/RoleFormController.php
+++ b/core/modules/user/lib/Drupal/user/RoleFormController.php
@@ -68,8 +68,7 @@ public function save(array $form, array &$form_state) {
     $entity->set('label', trim($entity->label()));
     $status = $entity->save();
 
-    $uri = $entity->urlInfo();
-    $edit_link = \Drupal::l($this->t('Edit'), $uri['route_name'], $uri['route_parameters'], $uri['options']);
+    $edit_link = \Drupal::linkGenerator()->generateFromUrl($this->t('Edit'), $this->entity->urlInfo());
     if ($status == SAVED_UPDATED) {
       drupal_set_message($this->t('Role %label has been updated.', array('%label' => $entity->label())));
       watchdog('user', 'Role %label has been updated.', array('%label' => $entity->label()), WATCHDOG_NOTICE, $edit_link);
diff --git a/core/modules/user/lib/Drupal/user/RoleListBuilder.php b/core/modules/user/lib/Drupal/user/RoleListBuilder.php
index 2d2b9be99d8f..0d557c7330a4 100644
--- a/core/modules/user/lib/Drupal/user/RoleListBuilder.php
+++ b/core/modules/user/lib/Drupal/user/RoleListBuilder.php
@@ -50,7 +50,7 @@ public function getOperations(EntityInterface $entity) {
       $operations['permissions'] = array(
         'title' => t('Edit permissions'),
         'weight' => 20,
-      ) + $entity->urlInfo('edit-permissions-form');
+      ) + $entity->urlInfo('edit-permissions-form')->toArray();
     }
     return $operations;
   }
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index 22d24c25a689..238f83707280 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -6,6 +6,7 @@
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Session\AnonymousUserSession;
 use \Drupal\Core\Entity\Display\EntityViewDisplayInterface;
+use Drupal\Core\Url;
 use Drupal\file\Entity\File;
 use Drupal\user\Entity\User;
 use Drupal\user\UserInterface;
@@ -156,12 +157,9 @@ function user_entity_bundle_info() {
  * Entity URI callback.
  */
 function user_uri($user) {
-  return array(
-    'route_name' => 'user.view',
-    'route_parameters' => array(
-      'user' => $user->id(),
-    ),
-  );
+  return new Url('user.view', array(
+    'user' => $user->id(),
+  ));
 }
 
 /**
diff --git a/core/modules/views_ui/lib/Drupal/views_ui/Form/Ajax/ReorderDisplays.php b/core/modules/views_ui/lib/Drupal/views_ui/Form/Ajax/ReorderDisplays.php
index 82be91c44556..61e5693956d4 100644
--- a/core/modules/views_ui/lib/Drupal/views_ui/Form/Ajax/ReorderDisplays.php
+++ b/core/modules/views_ui/lib/Drupal/views_ui/Form/Ajax/ReorderDisplays.php
@@ -193,7 +193,7 @@ public function submitForm(array &$form, array &$form_state) {
     // Store in cache.
     $view->cacheSet();
     $form_state['redirect_route'] = $view->urlInfo('edit-form');
-    $form_state['redirect_route']['options']['fragment'] = 'views-tab-default';
+    $form_state['redirect_route']->setOption('fragment', 'views-tab-default');
   }
 
 }
diff --git a/core/modules/views_ui/lib/Drupal/views_ui/ViewEditFormController.php b/core/modules/views_ui/lib/Drupal/views_ui/ViewEditFormController.php
index a4ca74e023dd..cfa791d6b7ea 100644
--- a/core/modules/views_ui/lib/Drupal/views_ui/ViewEditFormController.php
+++ b/core/modules/views_ui/lib/Drupal/views_ui/ViewEditFormController.php
@@ -689,7 +689,7 @@ public function renderDisplayTop(ViewUI $view) {
         ),
         'clone' => array(
           'title' => $this->t('Clone view'),
-        ) + $view->urlInfo('clone'),
+        ) + $view->urlInfo('clone')->toArray(),
         'reorder' => array(
           'title' => $this->t('Reorder displays'),
           'href' => "admin/structure/views/nojs/reorder-displays/{$view->id()}/$display_id",
@@ -701,7 +701,7 @@ public function renderDisplayTop(ViewUI $view) {
     if ($view->access('delete')) {
       $element['extra_actions']['#links']['delete'] = array(
         'title' => $this->t('Delete view'),
-      ) + $view->urlInfo('delete-form');
+      ) + $view->urlInfo('delete-form')->toArray();
     }
 
     // Let other modules add additional links here.
diff --git a/core/modules/views_ui/lib/Drupal/views_ui/ViewFormControllerBase.php b/core/modules/views_ui/lib/Drupal/views_ui/ViewFormControllerBase.php
index 38e81500ab4b..9c96b48e662b 100644
--- a/core/modules/views_ui/lib/Drupal/views_ui/ViewFormControllerBase.php
+++ b/core/modules/views_ui/lib/Drupal/views_ui/ViewFormControllerBase.php
@@ -121,7 +121,7 @@ public function getDisplayTabs(ViewUI $view) {
         '#link' => array(
           'title' => $this->getDisplayLabel($view, $id),
           'localized_options' => array(),
-        ) + $view->urlInfo('edit-display-form'),
+        ) + $view->urlInfo('edit-display-form')->toArray(),
       );
       $tabs[$id]['#link']['route_parameters']['display_id'] = $id;
       if (!empty($display['deleted'])) {
diff --git a/core/modules/views_ui/lib/Drupal/views_ui/ViewListBuilder.php b/core/modules/views_ui/lib/Drupal/views_ui/ViewListBuilder.php
index 6501c6323b9f..2adf662d404b 100644
--- a/core/modules/views_ui/lib/Drupal/views_ui/ViewListBuilder.php
+++ b/core/modules/views_ui/lib/Drupal/views_ui/ViewListBuilder.php
@@ -142,7 +142,7 @@ public function getOperations(EntityInterface $entity) {
       $operations['clone'] = array(
         'title' => $this->t('Clone'),
         'weight' => 15,
-      ) + $entity->urlInfo('clone');
+      ) + $entity->urlInfo('clone')->toArray();
     }
 
     // Add AJAX functionality to enable/disable operations.
diff --git a/core/modules/views_ui/lib/Drupal/views_ui/ViewPreviewFormController.php b/core/modules/views_ui/lib/Drupal/views_ui/ViewPreviewFormController.php
index ae9f4da0ee90..c0be8ee713ff 100644
--- a/core/modules/views_ui/lib/Drupal/views_ui/ViewPreviewFormController.php
+++ b/core/modules/views_ui/lib/Drupal/views_ui/ViewPreviewFormController.php
@@ -91,8 +91,8 @@ public function form(array $form, array &$form_state) {
       );
     }
     $uri = $view->urlInfo('preview-form');
-    $uri['route_parameters']['display_id'] = $this->displayID;
-    $form['#action'] = \Drupal::url($uri['route_name'], $uri['route_parameters'], $uri['options']);
+    $uri->setRouteParameter('display_id', $this->displayID);
+    $form['#action'] = $uri->toString();
 
     return $form;
   }
diff --git a/core/tests/Drupal/Tests/Core/Entity/EntityUrlTest.php b/core/tests/Drupal/Tests/Core/Entity/EntityUrlTest.php
index 96f482da7e52..c25be2091a63 100644
--- a/core/tests/Drupal/Tests/Core/Entity/EntityUrlTest.php
+++ b/core/tests/Drupal/Tests/Core/Entity/EntityUrlTest.php
@@ -10,7 +10,7 @@
 use Drupal\Core\Config\Entity\ConfigEntityBase;
 use Drupal\Core\DependencyInjection\ContainerBuilder;
 use Drupal\Core\Entity\Entity;
-use Drupal\Core\Routing\UrlGeneratorInterface;
+use Drupal\Core\Entity\EntityInterface;
 use Drupal\Tests\UnitTestCase;
 
 /**
@@ -30,6 +30,11 @@ class EntityUrlTest extends UnitTestCase {
    */
   protected $entityManager;
 
+  /**
+   * @var \Drupal\Core\Routing\UrlGeneratorInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $urlGenerator;
+
   /**
    * {@inheritdoc}
    */
@@ -48,9 +53,11 @@ protected function setUp() {
     parent::setUp();
 
     $this->entityManager = $this->getMock('Drupal\Core\Entity\EntityManagerInterface');
+    $this->urlGenerator = $this->getMock('Drupal\Core\Routing\UrlGeneratorInterface');
 
     $container = new ContainerBuilder();
     $container->set('entity.manager', $this->entityManager);
+    $container->set('url_generator', $this->urlGenerator);
     \Drupal::setContainer($container);
   }
 
@@ -64,7 +71,65 @@ protected function setUp() {
   public function testUrlInfo($entity_class, $link_template, $expected) {
     /** @var $entity \Drupal\Core\Entity\EntityInterface */
     $entity = new $entity_class(array('id' => 'test_entity_id'), 'test_entity_type');
+    $uri = $this->getTestUrlInfo($entity, $link_template);
+
+    $this->assertSame($expected, $uri->getRouteName());
+    $this->assertSame($entity, $uri->getOption('entity'));
+  }
+
+  /**
+   * Provides test data for testUrlInfo().
+   */
+  public function providerTestUrlInfo() {
+    return array(
+      array('Drupal\Tests\Core\Entity\TestEntity', 'edit-form', 'test_entity_type.edit'),
+      array('Drupal\Tests\Core\Entity\TestConfigEntity', 'edit-form', 'test_entity_type.edit'),
+      // Test that overriding the default $rel parameter works.
+      array('Drupal\Tests\Core\Entity\TestConfigEntity', FALSE, 'test_entity_type.edit'),
+    );
+  }
+
+  /**
+   * Tests the urlInfo() method with an invalid link template.
+   *
+   * @covers ::urlInfo()
+   *
+   * @expectedException \Drupal\Core\Entity\Exception\UndefinedLinkTemplateException
+   * @expectedExceptionMessage No link template "canonical" found for the "test_entity_type" entity type
+   *
+   * @dataProvider providerTestUrlInfoForInvalidLinkTemplate
+   */
+  public function testUrlInfoForInvalidLinkTemplate($entity_class, $link_template) {
+    /** @var $entity \Drupal\Core\Entity\EntityInterface */
+    $entity = new $entity_class(array('id' => 'test_entity_id'), 'test_entity_type');
+    $uri = $this->getTestUrlInfo($entity, $link_template);
+
+    $this->assertEmpty($uri);
+  }
+
+  /**
+   * Provides test data for testUrlInfoForInvalidLinkTemplate().
+   */
+  public function providerTestUrlInfoForInvalidLinkTemplate() {
+    return array(
+      array('Drupal\Tests\Core\Entity\TestEntity', 'canonical'),
+      array('Drupal\Tests\Core\Entity\TestEntity', FALSE),
+      array('Drupal\Tests\Core\Entity\TestConfigEntity', 'canonical'),
+    );
+  }
 
+  /**
+   * Creates a \Drupal\Core\Url object based on the entity and link template.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The test entity.
+   * @param string $link_template
+   *   The link template.
+   *
+   * @return \Drupal\Core\Url
+   *   The URL for this entity's link template.
+   */
+  protected function getTestUrlInfo(EntityInterface $entity, $link_template) {
     $entity_type = $this->getMock('Drupal\Core\Entity\EntityTypeInterface');
     $entity_type->expects($this->once())
       ->method('getLinkTemplates')
@@ -86,28 +151,7 @@ public function testUrlInfo($entity_class, $link_template, $expected) {
       $uri = $entity->urlInfo();
     }
 
-    if ($expected) {
-      $this->assertSame($expected, $uri['route_name']);
-      $this->assertSame($entity, $uri['options']['entity']);
-    }
-    else {
-      $this->assertEmpty($uri);
-    }
-  }
-
-  /**
-   * Provides test data for testUrlInfo().
-   */
-  public function providerTestUrlInfo() {
-    return array(
-      array('Drupal\Tests\Core\Entity\TestEntity', 'canonical', FALSE),
-      array('Drupal\Tests\Core\Entity\TestEntity', 'edit-form', 'test_entity_type.edit'),
-      array('Drupal\Tests\Core\Entity\TestEntity', FALSE, FALSE),
-      array('Drupal\Tests\Core\Entity\TestConfigEntity', 'canonical', FALSE),
-      array('Drupal\Tests\Core\Entity\TestConfigEntity', 'edit-form', 'test_entity_type.edit'),
-      // Test that overriding the default $rel parameter works.
-      array('Drupal\Tests\Core\Entity\TestConfigEntity', FALSE, 'test_entity_type.edit'),
-    );
+    return $uri;
   }
 
   /**
@@ -131,14 +175,14 @@ public function testUrlInfoForNewEntity() {
    */
   public function testUrl() {
     $entity_type = $this->getMock('Drupal\Core\Entity\EntityTypeInterface');
-    $entity_type->expects($this->exactly(3))
+    $entity_type->expects($this->exactly(5))
       ->method('getLinkTemplates')
       ->will($this->returnValue(array(
         'canonical' => 'test_entity_type.view',
       )));
 
     $this->entityManager
-      ->expects($this->exactly(4))
+      ->expects($this->exactly(5))
       ->method('getDefinition')
       ->with('test_entity_type')
       ->will($this->returnValue($entity_type));
@@ -150,9 +194,7 @@ public function testUrl() {
     $this->assertSame('', $no_link_entity->url('banana'));
 
     $valid_entity = new TestEntity(array('id' => 'test_entity_id'), 'test_entity_type');
-    $url_generator = $this->getMock('Drupal\Core\Routing\UrlGeneratorInterface');
-    $valid_entity->setUrlGenerator($url_generator);
-    $url_generator->expects($this->exactly(2))
+    $this->urlGenerator->expects($this->exactly(2))
       ->method('generateFromRoute')
       ->will($this->returnValueMap(array(
         array(
@@ -180,7 +222,7 @@ public function testUrl() {
    */
   public function testUrlForAdminForm() {
     $entity_type = $this->getMock('Drupal\Core\Entity\EntityTypeInterface');
-    $entity_type->expects($this->once())
+    $entity_type->expects($this->exactly(2))
       ->method('getLinkTemplates')
       ->will($this->returnValue(array(
         'admin-form' => 'test_entity_type.admin_form',
@@ -190,13 +232,12 @@ public function testUrlForAdminForm() {
       ->will($this->returnValue('test_entity_type_bundle'));
 
     $this->entityManager
-      ->expects($this->exactly(3))
+      ->expects($this->exactly(4))
       ->method('getDefinition')
       ->with('test_entity_type')
       ->will($this->returnValue($entity_type));
 
-    $url_generator = $this->getMock('Drupal\Core\Routing\UrlGeneratorInterface');
-    $url_generator->expects($this->once())
+    $this->urlGenerator->expects($this->once())
       ->method('generateFromRoute')
       ->with('test_entity_type.admin_form', array(
         'test_entity_type_bundle' => 'test_entity_bundle',
@@ -205,7 +246,6 @@ public function testUrlForAdminForm() {
       ->will($this->returnValue('entity/test_entity_type/test_entity_bundle/test_entity_id'));
 
     $entity = new TestEntityWithBundle(array('id' => 'test_entity_id', 'bundle' => 'test_entity_bundle'), 'test_entity_type');
-    $entity->setUrlGenerator($url_generator);
 
     $this->assertSame('entity/test_entity_type/test_entity_bundle/test_entity_id', $entity->url('admin-form'));
   }
@@ -217,7 +257,7 @@ public function testUrlForAdminForm() {
    */
   public function testGetSystemPath() {
     $entity_type = $this->getMock('Drupal\Core\Entity\EntityTypeInterface');
-    $entity_type->expects($this->exactly(2))
+    $entity_type->expects($this->exactly(3))
       ->method('getLinkTemplates')
       ->will($this->returnValue(array(
         'canonical' => 'test_entity_type.view',
@@ -232,14 +272,12 @@ public function testGetSystemPath() {
     $no_link_entity = new TestEntity(array('id' => 'test_entity_id'), 'test_entity_type');
     $this->assertSame('', $no_link_entity->getSystemPath('banana'));
 
-    $url_generator = $this->getMock('Drupal\Core\Routing\UrlGeneratorInterface');
-    $url_generator->expects($this->once())
+    $this->urlGenerator->expects($this->once())
       ->method('getPathFromRoute')
       ->with('test_entity_type.view', array('test_entity_type' => 'test_entity_id'))
       ->will($this->returnValue('entity/test_entity_type/test_entity_id'));
 
     $valid_entity = new TestEntity(array('id' => 'test_entity_id'), 'test_entity_type');
-    $valid_entity->setUrlGenerator($url_generator);
 
     $this->assertSame('entity/test_entity_type/test_entity_id', $valid_entity->getSystemPath());
   }
@@ -294,18 +332,6 @@ class TestConfigEntity extends ConfigEntityBase {
 
 class TestEntity extends Entity {
 
-  /**
-   * Sets the URL generator.
-   *
-   * @param \Drupal\Core\Routing\UrlGeneratorInterface $url_generator
-   *
-   * @return $this
-   */
-  public function setUrlGenerator(UrlGeneratorInterface $url_generator) {
-    $this->urlGenerator = $url_generator;
-    return $this;
-  }
-
 }
 
 class TestEntityWithTemplates extends TestEntity {
-- 
GitLab