← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] ~cjwatson/launchpad:py3-declarations into launchpad:master

 

Colin Watson has proposed merging ~cjwatson/launchpad:py3-declarations into launchpad:master.

Commit message:
Use new lazr.restful decorators

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/385643

zope.interface's class advice system no longer works on Python 3, so lazr.restful 0.22.0 adds equivalent class decorators.

This is very long, but it consists entirely of a single logical change: anywhere export_as_webservice_{collection,entry} was used within an interface declaration, transform it into an equivalent @exported_as_webservice_{collection,entry} decorator on the interface instead.
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:py3-declarations into launchpad:master.
diff --git a/lib/lp/answers/interfaces/faq.py b/lib/lp/answers/interfaces/faq.py
index 6f1ba18..f8bc3ae 100644
--- a/lib/lp/answers/interfaces/faq.py
+++ b/lib/lp/answers/interfaces/faq.py
@@ -13,9 +13,9 @@ __all__ = [
 
 from lazr.restful.declarations import (
     error_status,
-    export_as_webservice_entry,
     export_destructor_operation,
     exported,
+    exported_as_webservice_entry,
     operation_for_version,
     )
 from lazr.restful.fields import Reference
@@ -89,6 +89,7 @@ class IFAQPublic(IHasOwner):
         _('The set of questions linked to this FAQ.'))
 
 
+@exported_as_webservice_entry('faq', as_of='beta')
 class IFAQ(IFAQPublic):
     """A document containing the answer to a commonly asked question.
 
@@ -96,8 +97,6 @@ class IFAQ(IFAQPublic):
     web site and referred to by URL.
     """
 
-    export_as_webservice_entry('faq', as_of='beta')
-
     @export_destructor_operation()
     @operation_for_version('devel')
     def destroySelf():
diff --git a/lib/lp/answers/interfaces/faqtarget.py b/lib/lp/answers/interfaces/faqtarget.py
index 8b5ae5f..19c726c 100644
--- a/lib/lp/answers/interfaces/faqtarget.py
+++ b/lib/lp/answers/interfaces/faqtarget.py
@@ -10,16 +10,15 @@ __all__ = [
     ]
 
 
-from lazr.restful.declarations import export_as_webservice_entry
+from lazr.restful.declarations import exported_as_webservice_entry
 
 from lp.answers.interfaces.faqcollection import IFAQCollection
 
 
+@exported_as_webservice_entry('faq_target', as_of='beta')
 class IFAQTarget(IFAQCollection):
     """An object that can contain a FAQ document."""
 
-    export_as_webservice_entry('faq_target', as_of='beta')
-
     def newFAQ(owner, title, content, keywords=None, date_created=None):
         """Create a new FAQ hosted in this target.
 
diff --git a/lib/lp/answers/interfaces/question.py b/lib/lp/answers/interfaces/question.py
index da7cdbb..9b894c8 100644
--- a/lib/lp/answers/interfaces/question.py
+++ b/lib/lp/answers/interfaces/question.py
@@ -15,10 +15,10 @@ __all__ = [
 
 from lazr.restful.declarations import (
     call_with,
-    export_as_webservice_entry,
     export_factory_operation,
     export_write_operation,
     exported,
+    exported_as_webservice_entry,
     operation_for_version,
     operation_parameters,
     REQUEST_USER,
@@ -56,11 +56,10 @@ from lp.services.fields import PublicPersonChoice
 from lp.services.worlddata.interfaces.language import ILanguage
 
 
+@exported_as_webservice_entry(as_of='beta')
 class IQuestion(IHasOwner):
     """A single question, often a support request."""
 
-    export_as_webservice_entry(as_of='beta')
-
     id = exported(Int(
         title=_('Question Number'), required=True, readonly=True,
         description=_("The tracking number for this question.")),
diff --git a/lib/lp/answers/interfaces/questioncollection.py b/lib/lp/answers/interfaces/questioncollection.py
index cc6b291..f773fb6 100644
--- a/lib/lp/answers/interfaces/questioncollection.py
+++ b/lib/lp/answers/interfaces/questioncollection.py
@@ -13,9 +13,9 @@ __all__ = [
 
 from lazr.restful.declarations import (
     collection_default_content,
-    export_as_webservice_collection,
     export_operation_as,
     export_read_operation,
+    exported_as_webservice_collection,
     operation_for_version,
     operation_parameters,
     operation_returns_collection_of,
@@ -140,11 +140,10 @@ class ISearchableByQuestionOwner(IQuestionCollection):
         """
 
 
+@exported_as_webservice_collection(Interface)
 class IQuestionSet(IQuestionCollection):
     """A utility that contain all the questions published in Launchpad."""
 
-    export_as_webservice_collection(Interface)
-
     title = Attribute('Title')
 
     @operation_parameters(
diff --git a/lib/lp/answers/interfaces/questionmessage.py b/lib/lp/answers/interfaces/questionmessage.py
index 358824a..176ddf8 100644
--- a/lib/lp/answers/interfaces/questionmessage.py
+++ b/lib/lp/answers/interfaces/questionmessage.py
@@ -10,8 +10,8 @@ __all__ = [
     ]
 
 from lazr.restful.declarations import (
-    export_as_webservice_entry,
     exported,
+    exported_as_webservice_entry,
     )
 from lazr.restful.fields import Reference
 from zope.interface import Interface
@@ -29,13 +29,12 @@ from lp.answers.enums import (
 from lp.services.messages.interfaces.message import IMessage
 
 
+@exported_as_webservice_entry(as_of='devel')
 class IQuestionMessage(IMessage):
     """A message part of a question.
 
     It adds attributes to the IMessage interface.
     """
-    export_as_webservice_entry(as_of='devel')
-
     # This is really an Object field with schema=IQuestion, but that
     # would create a circular dependency between IQuestion
     # and IQuestionMessage
diff --git a/lib/lp/answers/interfaces/questionsubscription.py b/lib/lp/answers/interfaces/questionsubscription.py
index dc07fd3..52119a0 100644
--- a/lib/lp/answers/interfaces/questionsubscription.py
+++ b/lib/lp/answers/interfaces/questionsubscription.py
@@ -10,8 +10,8 @@ __all__ = [
     ]
 
 from lazr.restful.declarations import (
-    export_as_webservice_entry,
     exported,
+    exported_as_webservice_entry,
     )
 from lazr.restful.fields import Reference
 from zope.interface import Interface
@@ -24,11 +24,10 @@ from lp import _
 from lp.services.fields import PersonChoice
 
 
+@exported_as_webservice_entry(publish_web_link=False, as_of='devel')
 class IQuestionSubscription(Interface):
     """A subscription for a person to a question."""
 
-    export_as_webservice_entry(publish_web_link=False, as_of='devel')
-
     id = Int(title=_('ID'), readonly=True, required=True)
     person = exported(PersonChoice(
         title=_('Person'), required=True, vocabulary='ValidPersonOrTeam',
diff --git a/lib/lp/answers/interfaces/questiontarget.py b/lib/lp/answers/interfaces/questiontarget.py
index cef83c5..fd90bdf 100644
--- a/lib/lp/answers/interfaces/questiontarget.py
+++ b/lib/lp/answers/interfaces/questiontarget.py
@@ -13,9 +13,9 @@ __all__ = [
 
 from lazr.restful.declarations import (
     call_with,
-    export_as_webservice_entry,
     export_read_operation,
     export_write_operation,
+    exported_as_webservice_entry,
     operation_for_version,
     operation_parameters,
     operation_returns_collection_of,
@@ -213,9 +213,9 @@ class IQuestionTargetView(Interface):
         """
 
 
+@exported_as_webservice_entry(as_of='devel')
 class IQuestionTarget(IQuestionTargetPublic, IQuestionTargetView):
     """An object that can have a new question asked about it."""
-    export_as_webservice_entry(as_of='devel')
 
 
 # These schemas are only used by browser/questiontarget.py and should really
diff --git a/lib/lp/app/interfaces/services.py b/lib/lp/app/interfaces/services.py
index bc29dc5..15ddefe 100644
--- a/lib/lp/app/interfaces/services.py
+++ b/lib/lp/app/interfaces/services.py
@@ -12,8 +12,8 @@ __all__ = [
     ]
 
 from lazr.restful.declarations import (
-    export_as_webservice_entry,
     exported,
+    exported_as_webservice_entry,
     )
 from zope.interface import Interface
 from zope.schema import TextLine
@@ -31,7 +31,6 @@ class IService(Interface):
                 'The name of the service, used to generate the url.')))
 
 
+@exported_as_webservice_entry(publish_web_link=False, as_of='beta')
 class IServiceFactory(Interface):
     """Interface representing a factory used to access named services."""
-
-    export_as_webservice_entry(publish_web_link=False, as_of='beta')
diff --git a/lib/lp/blueprints/interfaces/specification.py b/lib/lp/blueprints/interfaces/specification.py
index ef6dfdc..d56a7de 100644
--- a/lib/lp/blueprints/interfaces/specification.py
+++ b/lib/lp/blueprints/interfaces/specification.py
@@ -18,12 +18,12 @@ from lazr.restful.declarations import (
     call_with,
     collection_default_content,
     error_status,
-    export_as_webservice_collection,
-    export_as_webservice_entry,
     export_factory_operation,
     export_operation_as,
     export_write_operation,
     exported,
+    exported_as_webservice_collection,
+    exported_as_webservice_entry,
     mutator_for,
     operation_for_version,
     operation_parameters,
@@ -684,13 +684,12 @@ class ISpecificationDriverRestricted(Interface):
         """
 
 
+@exported_as_webservice_entry(as_of="beta")
 class ISpecification(ISpecificationPublic, ISpecificationView,
                      ISpecificationEditRestricted,
                      ISpecificationDriverRestricted, IBugLinkTarget):
     """A Specification."""
 
-    export_as_webservice_entry(as_of="beta")
-
     @mutator_for(ISpecificationView['workitems_text'])
     @operation_parameters(new_work_items=WorkItemsText())
     @export_write_operation()
@@ -724,9 +723,9 @@ class ISpecification(ISpecificationPublic, ISpecificationView,
         """
 
 
+@exported_as_webservice_collection(ISpecification)
 class ISpecificationSet(IHasSpecifications):
     """A container for specifications."""
-    export_as_webservice_collection(ISpecification)
 
     @collection_default_content()
     def empty_list():
diff --git a/lib/lp/blueprints/interfaces/specificationbranch.py b/lib/lp/blueprints/interfaces/specificationbranch.py
index 3f7ef1b..e6ca7de 100644
--- a/lib/lp/blueprints/interfaces/specificationbranch.py
+++ b/lib/lp/blueprints/interfaces/specificationbranch.py
@@ -11,10 +11,10 @@ __all__ = [
     ]
 
 from lazr.restful.declarations import (
-    export_as_webservice_entry,
     export_operation_as,
     export_write_operation,
     exported,
+    exported_as_webservice_entry,
     operation_for_version,
     )
 from lazr.restful.fields import (
@@ -33,11 +33,10 @@ from lp.code.interfaces.branch import IBranch
 from lp.registry.interfaces.person import IPerson
 
 
+@exported_as_webservice_entry(as_of="beta")
 class ISpecificationBranch(Interface):
     """A branch linked to a specification."""
 
-    export_as_webservice_entry(as_of="beta")
-
     id = Int(title=_("Specification Branch #"))
     specification = exported(
         ReferenceChoice(
diff --git a/lib/lp/blueprints/interfaces/specificationsubscription.py b/lib/lp/blueprints/interfaces/specificationsubscription.py
index 161b4e4..a69d82d 100644
--- a/lib/lp/blueprints/interfaces/specificationsubscription.py
+++ b/lib/lp/blueprints/interfaces/specificationsubscription.py
@@ -11,8 +11,8 @@ __all__ = [
 
 from lazr.restful.declarations import (
     call_with,
-    export_as_webservice_entry,
     export_read_operation,
+    exported_as_webservice_entry,
     operation_for_version,
     REQUEST_USER,
     )
@@ -29,11 +29,10 @@ from lp import _
 from lp.services.fields import PersonChoice
 
 
+@exported_as_webservice_entry(publish_web_link=False, as_of='devel')
 class ISpecificationSubscription(Interface):
     """A subscription for a person to a specification."""
 
-    export_as_webservice_entry(publish_web_link=False, as_of='devel')
-
     id = Int(
         title=_('ID'), required=True, readonly=True)
     person = PersonChoice(
diff --git a/lib/lp/blueprints/interfaces/specificationtarget.py b/lib/lp/blueprints/interfaces/specificationtarget.py
index 81b7290..4d10b71 100644
--- a/lib/lp/blueprints/interfaces/specificationtarget.py
+++ b/lib/lp/blueprints/interfaces/specificationtarget.py
@@ -13,9 +13,9 @@ __all__ = [
 
 from lazr.lifecycle.snapshot import doNotSnapshot
 from lazr.restful.declarations import (
-    export_as_webservice_entry,
     export_read_operation,
     exported,
+    exported_as_webservice_entry,
     operation_for_version,
     operation_parameters,
     operation_returns_entry,
@@ -86,13 +86,12 @@ class IHasSpecifications(Interface):
         """
 
 
+@exported_as_webservice_entry(as_of="devel")
 class ISpecificationTarget(IHasSpecifications):
     """An interface for the objects which actually have unique
     specifications directly attached to them.
     """
 
-    export_as_webservice_entry(as_of="devel")
-
     @operation_parameters(
         name=TextLine(title=_('The name of the specification')))
     @operation_returns_entry(Interface)  # really ISpecification
diff --git a/lib/lp/bugs/interfaces/bug.py b/lib/lp/bugs/interfaces/bug.py
index 79397ef..dab809d 100644
--- a/lib/lp/bugs/interfaces/bug.py
+++ b/lib/lp/bugs/interfaces/bug.py
@@ -26,11 +26,11 @@ from lazr.lifecycle.snapshot import doNotSnapshot
 from lazr.restful.declarations import (
     accessor_for,
     call_with,
-    export_as_webservice_entry,
     export_factory_operation,
     export_read_operation,
     export_write_operation,
     exported,
+    exported_as_webservice_entry,
     mutator_for,
     operation_for_version,
     operation_parameters,
@@ -1009,9 +1009,9 @@ class IBugAppend(Interface):
         """
 
 
+@exported_as_webservice_entry()
 class IBug(IBugPublic, IBugView, IBugAppend, IHasLinkedBranches):
     """The core bug entry."""
-    export_as_webservice_entry()
 
     linked_bugbranches = exported(
         CollectionField(
diff --git a/lib/lp/bugs/interfaces/bugactivity.py b/lib/lp/bugs/interfaces/bugactivity.py
index 6e8b862..54e4137 100644
--- a/lib/lp/bugs/interfaces/bugactivity.py
+++ b/lib/lp/bugs/interfaces/bugactivity.py
@@ -11,8 +11,8 @@ __all__ = [
     ]
 
 from lazr.restful.declarations import (
-    export_as_webservice_entry,
     exported,
+    exported_as_webservice_entry,
     )
 from zope.interface import (
     Attribute,
@@ -31,9 +31,9 @@ from lp.services.fields import (
     )
 
 
+@exported_as_webservice_entry()
 class IBugActivity(Interface):
     """A log of all things that have happened to a bug."""
-    export_as_webservice_entry()
 
     bug = exported(
         BugField(title=_('Bug'), readonly=True))
diff --git a/lib/lp/bugs/interfaces/bugattachment.py b/lib/lp/bugs/interfaces/bugattachment.py
index 7616fd6..3aa7b7c 100644
--- a/lib/lp/bugs/interfaces/bugattachment.py
+++ b/lib/lp/bugs/interfaces/bugattachment.py
@@ -19,9 +19,9 @@ from lazr.enum import (
     )
 from lazr.restful.declarations import (
     call_with,
-    export_as_webservice_entry,
     export_write_operation,
     exported,
+    exported_as_webservice_entry,
     REQUEST_USER,
     )
 from lazr.restful.fields import Reference
@@ -121,6 +121,7 @@ class IBugAttachmentEdit(Interface):
         """Remove the attachment from the bug."""
 
 
+@exported_as_webservice_entry()
 class IBugAttachment(IBugAttachmentView, IBugAttachmentEdit):
     """A file attachment to an IBug.
 
@@ -150,7 +151,6 @@ class IBugAttachment(IBugAttachmentView, IBugAttachmentEdit):
             print "owner:", message.owner.display_name.encode('utf-8')
             print "created:", message.date_created
     """
-    export_as_webservice_entry()
 
 
 # Need to do this here because of circular imports.
diff --git a/lib/lp/bugs/interfaces/bugbranch.py b/lib/lp/bugs/interfaces/bugbranch.py
index 97a558b..8f7e6a9 100644
--- a/lib/lp/bugs/interfaces/bugbranch.py
+++ b/lib/lp/bugs/interfaces/bugbranch.py
@@ -11,8 +11,8 @@ __all__ = [
     ]
 
 from lazr.restful.declarations import (
-    export_as_webservice_entry,
     exported,
+    exported_as_webservice_entry,
     )
 from lazr.restful.fields import ReferenceChoice
 from zope.interface import (
@@ -28,11 +28,10 @@ from lp.registry.interfaces.person import IPerson
 from lp.services.fields import BugField
 
 
+@exported_as_webservice_entry()
 class IBugBranch(IHasBug):
     """A branch linked to a bug."""
 
-    export_as_webservice_entry()
-
     bug = exported(
         BugField(
             title=_("Bug #"),
diff --git a/lib/lp/bugs/interfaces/buglink.py b/lib/lp/bugs/interfaces/buglink.py
index 2d13047..19c5201 100644
--- a/lib/lp/bugs/interfaces/buglink.py
+++ b/lib/lp/bugs/interfaces/buglink.py
@@ -14,8 +14,8 @@ __all__ = [
     ]
 
 from lazr.restful.declarations import (
-    export_as_webservice_entry,
     exported,
+    exported_as_webservice_entry,
     )
 from lazr.restful.fields import (
     CollectionField,
@@ -57,12 +57,12 @@ class IObjectUnlinkedEvent(IObjectEvent):
     user = Attribute("The user who unlinked the object.")
 
 
+@exported_as_webservice_entry(as_of="beta")
 class IBugLinkTarget(Interface):
     """An entity which can be linked to bugs.
 
     Examples include an ISpecification.
     """
-    export_as_webservice_entry(as_of="beta")
 
     bugs = exported(
         CollectionField(title=_("Bugs related to this object."),
diff --git a/lib/lp/bugs/interfaces/bugnomination.py b/lib/lp/bugs/interfaces/bugnomination.py
index 7bb6618..c8ab348 100644
--- a/lib/lp/bugs/interfaces/bugnomination.py
+++ b/lib/lp/bugs/interfaces/bugnomination.py
@@ -21,10 +21,10 @@ from lazr.enum import (
 from lazr.restful.declarations import (
     call_with,
     error_status,
-    export_as_webservice_entry,
     export_read_operation,
     export_write_operation,
     exported,
+    exported_as_webservice_entry,
     REQUEST_USER,
     )
 from lazr.restful.fields import (
@@ -97,12 +97,12 @@ class BugNominationStatus(DBEnumeratedType):
         """)
 
 
+@exported_as_webservice_entry(publish_web_link=False)
 class IBugNomination(IHasBug, IHasOwner):
     """A nomination for a bug to be fixed in a specific series.
 
     A nomination can apply to an IDistroSeries or an IProductSeries.
     """
-    export_as_webservice_entry(publish_web_link=False)
 
     # We want to customize the titles and descriptions of some of the
     # attributes of our parent interfaces, so we redefine those specific
diff --git a/lib/lp/bugs/interfaces/bugsubscription.py b/lib/lp/bugs/interfaces/bugsubscription.py
index 28345f1..f0241d4 100644
--- a/lib/lp/bugs/interfaces/bugsubscription.py
+++ b/lib/lp/bugs/interfaces/bugsubscription.py
@@ -12,9 +12,9 @@ __all__ = [
 from lazr.lifecycle.snapshot import doNotSnapshot
 from lazr.restful.declarations import (
     call_with,
-    export_as_webservice_entry,
     export_read_operation,
     exported,
+    exported_as_webservice_entry,
     operation_for_version,
     REQUEST_USER,
     )
@@ -35,11 +35,10 @@ from lp.services.fields import PersonChoice
 from lp.services.webservice.apihelpers import patch_reference_property
 
 
+@exported_as_webservice_entry(publish_web_link=False, as_of="beta")
 class IBugSubscription(Interface):
     """The relationship between a person and a bug."""
 
-    export_as_webservice_entry(publish_web_link=False, as_of="beta")
-
     id = Int(title=_('ID'), readonly=True, required=True)
     person = exported(PersonChoice(
         title=_('Person'), required=True, vocabulary='ValidPersonOrTeam',
diff --git a/lib/lp/bugs/interfaces/bugsubscriptionfilter.py b/lib/lp/bugs/interfaces/bugsubscriptionfilter.py
index 3aca1cb..9d58906 100644
--- a/lib/lp/bugs/interfaces/bugsubscriptionfilter.py
+++ b/lib/lp/bugs/interfaces/bugsubscriptionfilter.py
@@ -11,11 +11,11 @@ __all__ = [
 
 from lazr.restful.declarations import (
     call_with,
-    export_as_webservice_entry,
     export_destructor_operation,
     export_read_operation,
     export_write_operation,
     exported,
+    exported_as_webservice_entry,
     operation_for_version,
     REQUEST_USER,
     )
@@ -149,11 +149,11 @@ class IBugSubscriptionFilterMethodsProtected(Interface):
         structural subscription."""
 
 
+@exported_as_webservice_entry()
 class IBugSubscriptionFilter(
     IBugSubscriptionFilterAttributes, IBugSubscriptionFilterMethodsProtected,
     IBugSubscriptionFilterMethodsPublic):
     """A bug subscription filter."""
-    export_as_webservice_entry()
 
 
 class IBugSubscriptionFilterMute(Interface):
diff --git a/lib/lp/bugs/interfaces/bugtarget.py b/lib/lp/bugs/interfaces/bugtarget.py
index e969b0d..f944788 100644
--- a/lib/lp/bugs/interfaces/bugtarget.py
+++ b/lib/lp/bugs/interfaces/bugtarget.py
@@ -23,10 +23,10 @@ __all__ = [
 from lazr.enum import DBEnumeratedType
 from lazr.restful.declarations import (
     call_with,
-    export_as_webservice_entry,
     export_read_operation,
     export_write_operation,
     exported,
+    exported_as_webservice_entry,
     operation_for_version,
     operation_parameters,
     operation_removed_in_version,
@@ -223,11 +223,10 @@ BUG_POLICY_DEFAULT_TYPES = {
     }
 
 
+@exported_as_webservice_entry()
 class IHasBugs(Interface):
     """An entity which has a collection of bug tasks."""
 
-    export_as_webservice_entry()
-
     # searchTasks devel API declaration.
     @call_with(search_params=None, user=REQUEST_USER)
     @operation_parameters(**search_tasks_params_for_api_devel)
@@ -298,6 +297,7 @@ class IHasExpirableBugs(Interface):
     """Marker interface for entities supporting querying expirable bugs"""
 
 
+@exported_as_webservice_entry()
 class IBugTarget(IHasBugs):
     """An entity on which a bug can be reported.
 
@@ -305,8 +305,6 @@ class IBugTarget(IHasBugs):
     IProduct.
     """
 
-    export_as_webservice_entry()
-
     # XXX Brad Bollenbach 2006-08-02 bug=54974: This attribute name smells.
     bugtargetdisplayname = Attribute("A display name for this bug target")
     bugtargetname = Attribute("The target as shown in mail notifications.")
diff --git a/lib/lp/bugs/interfaces/bugtask.py b/lib/lp/bugs/interfaces/bugtask.py
index 387c7f1..f7c1600 100644
--- a/lib/lp/bugs/interfaces/bugtask.py
+++ b/lib/lp/bugs/interfaces/bugtask.py
@@ -42,11 +42,11 @@ from lazr.enum import (
 from lazr.restful.declarations import (
     call_with,
     error_status,
-    export_as_webservice_entry,
     export_destructor_operation,
     export_read_operation,
     export_write_operation,
     exported,
+    exported_as_webservice_entry,
     mutator_for,
     operation_for_version,
     operation_parameters,
@@ -388,9 +388,9 @@ class IBugTaskDelete(Interface):
         """
 
 
+@exported_as_webservice_entry()
 class IBugTask(IHasBug, IBugTaskDelete):
     """A bug needing fixing in a particular product or package."""
-    export_as_webservice_entry()
 
     id = Int(title=_("Bug Task #"))
     bug = exported(
diff --git a/lib/lp/bugs/interfaces/bugtracker.py b/lib/lp/bugs/interfaces/bugtracker.py
index b0e06fa..586c646 100644
--- a/lib/lp/bugs/interfaces/bugtracker.py
+++ b/lib/lp/bugs/interfaces/bugtracker.py
@@ -26,12 +26,12 @@ from lazr.lifecycle.snapshot import doNotSnapshot
 from lazr.restful.declarations import (
     call_with,
     collection_default_content,
-    export_as_webservice_collection,
-    export_as_webservice_entry,
     export_factory_operation,
     export_read_operation,
     export_write_operation,
     exported,
+    exported_as_webservice_collection,
+    exported_as_webservice_entry,
     operation_for_version,
     operation_parameters,
     operation_returns_collection_of,
@@ -216,6 +216,7 @@ SINGLE_PRODUCT_BUGTRACKERTYPES = [
     ]
 
 
+@exported_as_webservice_entry()
 class IBugTracker(Interface):
     """A remote bug system.
 
@@ -235,7 +236,6 @@ class IBugTracker(Interface):
             print "%s at %s" %(tracker.bug_tracker_type, tracker.base_url)
 
     """
-    export_as_webservice_entry()
 
     id = Int(title=_('ID'))
     bugtrackertype = exported(
@@ -438,13 +438,13 @@ class IBugTracker(Interface):
         """
 
 
+@exported_as_webservice_collection(IBugTracker)
 class IBugTrackerSet(Interface):
     """A set of IBugTracker's.
 
     Each BugTracker is a distinct instance of a bug tracking tool. For
     example, bugzilla.mozilla.org is distinct from bugzilla.gnome.org.
     """
-    export_as_webservice_collection(IBugTracker)
 
     title = Attribute('Title')
 
@@ -549,6 +549,7 @@ class IBugTrackerAliasSet(Interface):
         """Query IBugTrackerAliases by BugTracker."""
 
 
+@exported_as_webservice_entry()
 class IBugTrackerComponent(Interface):
     """The software component in the remote bug tracker.
 
@@ -556,7 +557,6 @@ class IBugTrackerComponent(Interface):
     they affect.  This class provides a mapping of this upstream component
     to the corresponding source package in the distro.
     """
-    export_as_webservice_entry()
 
     id = Int(title=_('ID'), required=True, readonly=True)
     is_visible = exported(Bool(
@@ -593,13 +593,13 @@ class IBugTrackerComponent(Interface):
         Reference(title=_('Component Group'), schema=Interface))
 
 
+@exported_as_webservice_entry()
 class IBugTrackerComponentGroup(Interface):
     """A collection of components in a remote bug tracker.
 
     Some bug trackers organize sets of components into higher level groups,
     such as Bugzilla's 'product'.
     """
-    export_as_webservice_entry()
 
     id = Int(title=_('ID'))
     name = exported(
diff --git a/lib/lp/bugs/interfaces/bugwatch.py b/lib/lp/bugs/interfaces/bugwatch.py
index 71003d0..2398381 100644
--- a/lib/lp/bugs/interfaces/bugwatch.py
+++ b/lib/lp/bugs/interfaces/bugwatch.py
@@ -21,8 +21,8 @@ from lazr.enum import (
     DBItem,
     )
 from lazr.restful.declarations import (
-    export_as_webservice_entry,
     exported,
+    exported_as_webservice_entry,
     )
 from lazr.restful.fields import (
     CollectionField,
@@ -148,9 +148,9 @@ BUG_WATCH_ACTIVITY_SUCCESS_STATUSES = [
     ]
 
 
+@exported_as_webservice_entry()
 class IBugWatch(IHasBug):
     """A bug on a remote system."""
-    export_as_webservice_entry()
 
     id = Int(title=_('ID'), required=True, readonly=True)
 
diff --git a/lib/lp/bugs/interfaces/cve.py b/lib/lp/bugs/interfaces/cve.py
index 078ef61..c564cac 100644
--- a/lib/lp/bugs/interfaces/cve.py
+++ b/lib/lp/bugs/interfaces/cve.py
@@ -17,9 +17,9 @@ from lazr.enum import (
     )
 from lazr.restful.declarations import (
     collection_default_content,
-    export_as_webservice_collection,
-    export_as_webservice_entry,
     exported,
+    exported_as_webservice_collection,
+    exported_as_webservice_entry,
     )
 from lazr.restful.fields import (
     CollectionField,
@@ -74,11 +74,10 @@ class CveStatus(DBEnumeratedType):
         """)
 
 
+@exported_as_webservice_entry()
 class ICve(Interface):
     """A single CVE database entry."""
 
-    export_as_webservice_entry()
-
     id = Int(title=_('ID'), required=True, readonly=True)
     sequence = exported(
         TextLine(title=_('CVE Sequence Number'),
@@ -131,11 +130,10 @@ class ICve(Interface):
         """Remove a CveReference."""
 
 
+@exported_as_webservice_collection(ICve)
 class ICveSet(Interface):
     """The set of ICve objects."""
 
-    export_as_webservice_collection(ICve)
-
     title = Attribute('Title')
 
     def __getitem__(key):
diff --git a/lib/lp/bugs/interfaces/malone.py b/lib/lp/bugs/interfaces/malone.py
index 60dc795..83c8d9c 100644
--- a/lib/lp/bugs/interfaces/malone.py
+++ b/lib/lp/bugs/interfaces/malone.py
@@ -8,9 +8,9 @@ __metaclass__ = type
 from lazr.restful.declarations import (
     call_with,
     collection_default_content,
-    export_as_webservice_collection,
     export_factory_operation,
     export_read_operation,
+    exported_as_webservice_collection,
     operation_for_version,
     operation_parameters,
     REQUEST_USER,
@@ -33,9 +33,9 @@ __all__ = [
     ]
 
 
+@exported_as_webservice_collection(IBug)
 class IMaloneApplication(ILaunchpadApplication, IHasBugs):
     """Application root for malone."""
-    export_as_webservice_collection(IBug)
 
     @call_with(user=REQUEST_USER)
     @operation_parameters(
diff --git a/lib/lp/bugs/interfaces/structuralsubscription.py b/lib/lp/bugs/interfaces/structuralsubscription.py
index da37c2f..a253aa7 100644
--- a/lib/lp/bugs/interfaces/structuralsubscription.py
+++ b/lib/lp/bugs/interfaces/structuralsubscription.py
@@ -14,12 +14,12 @@ __all__ = [
 
 from lazr.restful.declarations import (
     call_with,
-    export_as_webservice_entry,
     export_destructor_operation,
     export_factory_operation,
     export_read_operation,
     export_write_operation,
     exported,
+    exported_as_webservice_entry,
     operation_for_version,
     operation_parameters,
     operation_returns_collection_of,
@@ -99,12 +99,11 @@ class IStructuralSubscriptionRestricted(Interface):
         """Delete this structural subscription filter."""
 
 
+@exported_as_webservice_entry(publish_web_link=False)
 class IStructuralSubscription(
     IStructuralSubscriptionPublic, IStructuralSubscriptionRestricted):
     """A subscription to a Launchpad structure."""
 
-    export_as_webservice_entry(publish_web_link=False)
-
 
 class IStructuralSubscriptionTargetRead(Interface):
     """A Launchpad Structure allowing users to subscribe to it.
@@ -233,10 +232,10 @@ class IStructuralSubscriptionTargetWrite(Interface):
         """
 
 
+@exported_as_webservice_entry()
 class IStructuralSubscriptionTarget(IStructuralSubscriptionTargetRead,
                                     IStructuralSubscriptionTargetWrite):
     """A Launchpad Structure allowing users to subscribe to it."""
-    export_as_webservice_entry()
 
 
 class IStructuralSubscriptionTargetHelper(Interface):
diff --git a/lib/lp/buildmaster/interfaces/builder.py b/lib/lp/buildmaster/interfaces/builder.py
index ac798a5..6be226f 100644
--- a/lib/lp/buildmaster/interfaces/builder.py
+++ b/lib/lp/buildmaster/interfaces/builder.py
@@ -19,12 +19,12 @@ __all__ = [
 from lazr.restful.declarations import (
     call_with,
     collection_default_content,
-    export_as_webservice_collection,
-    export_as_webservice_entry,
     export_factory_operation,
     export_read_operation,
     export_write_operation,
     exported,
+    exported_as_webservice_collection,
+    exported_as_webservice_entry,
     mutator_for,
     operation_for_version,
     operation_parameters,
@@ -219,6 +219,7 @@ class IBuilderEdit(Interface):
         """Update the clean status."""
 
 
+@exported_as_webservice_entry()
 class IBuilder(IBuilderEdit, IBuilderView):
     """Build-slave information and state.
 
@@ -231,7 +232,6 @@ class IBuilder(IBuilderEdit, IBuilderView):
     representation, including the field/properties: virtualized, builderok,
     status, failnotes and currentjob.
     """
-    export_as_webservice_entry()
 
 
 class IBuilderSetAdmin(Interface):
@@ -252,6 +252,7 @@ class IBuilderSetAdmin(Interface):
         """
 
 
+@exported_as_webservice_collection(IBuilder)
 class IBuilderSet(IBuilderSetAdmin):
     """Collections of builders.
 
@@ -260,7 +261,6 @@ class IBuilderSet(IBuilderSetAdmin):
     Methods on this interface should deal with the set of Builders:
     methods that affect a single Builder should be on IBuilder.
     """
-    export_as_webservice_collection(IBuilder)
     title = Attribute('Title')
 
     def __iter__():
diff --git a/lib/lp/buildmaster/interfaces/buildfarmjob.py b/lib/lp/buildmaster/interfaces/buildfarmjob.py
index 79a948f..aaba8b2 100644
--- a/lib/lp/buildmaster/interfaces/buildfarmjob.py
+++ b/lib/lp/buildmaster/interfaces/buildfarmjob.py
@@ -15,8 +15,8 @@ __all__ = [
     ]
 
 from lazr.restful.declarations import (
-    export_as_webservice_entry,
     exported,
+    exported_as_webservice_entry,
     )
 from lazr.restful.fields import Reference
 from zope.interface import (
@@ -65,11 +65,10 @@ class IBuildFarmJobDB(Interface):
         description=_("The specific type of job."))
 
 
+@exported_as_webservice_entry(as_of='beta')
 class IBuildFarmJob(Interface):
     """Operations that jobs for the build farm must implement."""
 
-    export_as_webservice_entry(as_of='beta')
-
     id = Attribute('The build farm job ID.')
 
     build_farm_job = Attribute('Generic build farm job record')
diff --git a/lib/lp/buildmaster/interfaces/processor.py b/lib/lp/buildmaster/interfaces/processor.py
index fba6e1f..f80b5bc 100644
--- a/lib/lp/buildmaster/interfaces/processor.py
+++ b/lib/lp/buildmaster/interfaces/processor.py
@@ -13,10 +13,10 @@ __all__ = [
 
 from lazr.restful.declarations import (
     collection_default_content,
-    export_as_webservice_collection,
-    export_as_webservice_entry,
     export_read_operation,
     exported,
+    exported_as_webservice_collection,
+    exported_as_webservice_entry,
     operation_for_version,
     operation_parameters,
     operation_returns_entry,
@@ -40,16 +40,16 @@ class ProcessorNotFound(NameLookupFailed):
     _message_prefix = 'No such processor'
 
 
+# XXX: BradCrittenden 2011-06-20 bug=760849: The following use of 'beta'
+# is a work-around to allow the WADL to be generated.  It is a bald-faced
+# lie, though.  The class is being exported in 'devel' but in order to get
+# the WADL generation work it must be back-dated to the earliest version.
+# Note that individual attributes and methods can and must truthfully set
+# 'devel' as their version.
+@exported_as_webservice_entry(publish_web_link=False, as_of='beta')
 class IProcessor(Interface):
     """The SQLObject Processor Interface"""
 
-    # XXX: BradCrittenden 2011-06-20 bug=760849: The following use of 'beta'
-    # is a work-around to allow the WADL to be generated.  It is a bald-faced
-    # lie, though.  The class is being exported in 'devel' but in order to get
-    # the WADL generation work it must be back-dated to the earliest version.
-    # Note that individual attributes and methods can and must truthfully set
-    # 'devel' as their version.
-    export_as_webservice_entry(publish_web_link=False, as_of='beta')
     id = Attribute("The Processor ID")
     name = exported(
         TextLine(title=_("Name"),
@@ -88,9 +88,9 @@ class IProcessor(Interface):
         as_of='devel', readonly=True)
 
 
+@exported_as_webservice_collection(IProcessor)
 class IProcessorSet(Interface):
     """Operations related to Processor instances."""
-    export_as_webservice_collection(IProcessor)
 
     @operation_parameters(
         name=TextLine(required=True))
diff --git a/lib/lp/code/interfaces/branch.py b/lib/lp/code/interfaces/branch.py
index 766d397..45c8086 100644
--- a/lib/lp/code/interfaces/branch.py
+++ b/lib/lp/code/interfaces/branch.py
@@ -28,14 +28,14 @@ from lazr.restful.declarations import (
     call_with,
     collection_default_content,
     error_status,
-    export_as_webservice_collection,
-    export_as_webservice_entry,
     export_destructor_operation,
     export_factory_operation,
     export_operation_as,
     export_read_operation,
     export_write_operation,
     exported,
+    exported_as_webservice_collection,
+    exported_as_webservice_entry,
     mutator_for,
     operation_for_version,
     operation_parameters,
@@ -1248,14 +1248,12 @@ class IBranchEdit(IWebhookTarget):
         """
 
 
+@exported_as_webservice_entry(plural_name='branches')
 class IBranch(IBranchPublic, IBranchView, IBranchEdit,
               IBranchEditableAttributes, IBranchModerate,
               IBranchModerateAttributes, IBranchAnyone):
     """A Bazaar branch."""
 
-    # Mark branches as exported entries for the Launchpad API.
-    export_as_webservice_entry(plural_name='branches')
-
     # This is redefined from IPrivacy.private and is read only. This attribute
     # is true if this branch is explicitly private or any of its stacked on
     # branches are private.
@@ -1276,11 +1274,10 @@ class IBranch(IBranchPublic, IBranchView, IBranchEdit,
         """Set the branch privacy for this branch."""
 
 
+@exported_as_webservice_collection(IBranch)
 class IBranchSet(Interface):
     """Interface representing the set of branches."""
 
-    export_as_webservice_collection(IBranch)
-
     def getRecentlyChangedBranches(
         branch_count=None,
         lifecycle_statuses=DEFAULT_BRANCH_STATUS_IN_LISTING,
diff --git a/lib/lp/code/interfaces/branchmergeproposal.py b/lib/lp/code/interfaces/branchmergeproposal.py
index fa37faf..2a6626d 100644
--- a/lib/lp/code/interfaces/branchmergeproposal.py
+++ b/lib/lp/code/interfaces/branchmergeproposal.py
@@ -30,11 +30,11 @@ __all__ = [
 
 from lazr.restful.declarations import (
     call_with,
-    export_as_webservice_entry,
     export_factory_operation,
     export_read_operation,
     export_write_operation,
     exported,
+    exported_as_webservice_entry,
     operation_for_version,
     operation_parameters,
     operation_returns_collection_of,
@@ -767,13 +767,12 @@ class IBranchMergeProposalAnyAllowedPerson(IBugLinkTarget):
         """Unlink a bug from this merge proposal."""
 
 
+@exported_as_webservice_entry()
 class IBranchMergeProposal(IBranchMergeProposalPublic,
                            IBranchMergeProposalView, IBranchMergeProposalEdit,
                            IBranchMergeProposalAnyAllowedPerson):
     """Branch merge proposals show intent of landing one branch on another."""
 
-    export_as_webservice_entry()
-
 
 class IBranchMergeProposalJob(Interface):
     """A Job related to a Branch Merge Proposal."""
diff --git a/lib/lp/code/interfaces/branchsubscription.py b/lib/lp/code/interfaces/branchsubscription.py
index e5a8861..d3536fb 100644
--- a/lib/lp/code/interfaces/branchsubscription.py
+++ b/lib/lp/code/interfaces/branchsubscription.py
@@ -11,9 +11,9 @@ __all__ = [
 
 from lazr.restful.declarations import (
     call_with,
-    export_as_webservice_entry,
     export_read_operation,
     exported,
+    exported_as_webservice_entry,
     REQUEST_USER,
     )
 from lazr.restful.fields import Reference
@@ -33,9 +33,9 @@ from lp.code.interfaces.branch import IBranch
 from lp.services.fields import PersonChoice
 
 
+@exported_as_webservice_entry()
 class IBranchSubscription(Interface):
     """The relationship between a person and a branch."""
-    export_as_webservice_entry()
 
     id = Int(title=_('ID'), readonly=True, required=True)
     person_id = Int(title=_('Person ID'), required=True, readonly=True)
diff --git a/lib/lp/code/interfaces/codeimport.py b/lib/lp/code/interfaces/codeimport.py
index bddf51a..7386e6b 100644
--- a/lib/lp/code/interfaces/codeimport.py
+++ b/lib/lp/code/interfaces/codeimport.py
@@ -18,9 +18,9 @@ from CVS.protocol import (
     )
 from lazr.restful.declarations import (
     call_with,
-    export_as_webservice_entry,
     export_write_operation,
     exported,
+    exported_as_webservice_entry,
     REQUEST_USER,
     )
 from lazr.restful.fields import ReferenceChoice
@@ -77,11 +77,10 @@ def validate_cvs_module(cvsmodule):
     return True
 
 
+@exported_as_webservice_entry()
 class ICodeImport(Interface):
     """A code import to a Bazaar Branch."""
 
-    export_as_webservice_entry()
-
     id = Int(readonly=True, required=True)
     date_created = Datetime(
         title=_("Date Created"), required=True, readonly=True)
diff --git a/lib/lp/code/interfaces/codereviewcomment.py b/lib/lp/code/interfaces/codereviewcomment.py
index a61cd94..f17e9a9 100644
--- a/lib/lp/code/interfaces/codereviewcomment.py
+++ b/lib/lp/code/interfaces/codereviewcomment.py
@@ -10,8 +10,8 @@ __all__ = [
     ]
 
 from lazr.restful.declarations import (
-    export_as_webservice_entry,
     exported,
+    exported_as_webservice_entry,
     )
 from lazr.restful.fields import Reference
 from zope.interface import Interface
@@ -31,9 +31,9 @@ from lp.registry.interfaces.person import IPerson
 from lp.services.messages.interfaces.message import IMessage
 
 
+@exported_as_webservice_entry()
 class ICodeReviewComment(Interface):
     """A link between a merge proposal and a message."""
-    export_as_webservice_entry()
 
     id = exported(
         Int(
diff --git a/lib/lp/code/interfaces/codereviewvote.py b/lib/lp/code/interfaces/codereviewvote.py
index 10d4d2c..bcd870c 100644
--- a/lib/lp/code/interfaces/codereviewvote.py
+++ b/lib/lp/code/interfaces/codereviewvote.py
@@ -10,10 +10,10 @@ __all__ = [
 
 from lazr.restful.declarations import (
     call_with,
-    export_as_webservice_entry,
     export_destructor_operation,
     export_write_operation,
     exported,
+    exported_as_webservice_entry,
     operation_parameters,
     REQUEST_USER,
     )
@@ -140,6 +140,7 @@ class ICodeReviewVoteReferenceEdit(Interface):
         """
 
 
+@exported_as_webservice_entry()
 class ICodeReviewVoteReference(ICodeReviewVoteReferencePublic,
                                ICodeReviewVoteReferenceEdit):
     """A reference to a vote on a IBranchMergeProposal.
@@ -147,5 +148,3 @@ class ICodeReviewVoteReference(ICodeReviewVoteReferencePublic,
     There is at most one reference to a vote for each reviewer on a given
     branch merge proposal.
     """
-
-    export_as_webservice_entry()
diff --git a/lib/lp/code/interfaces/diff.py b/lib/lp/code/interfaces/diff.py
index c1f8552..9e0e27c 100644
--- a/lib/lp/code/interfaces/diff.py
+++ b/lib/lp/code/interfaces/diff.py
@@ -12,8 +12,8 @@ __all__ = [
     ]
 
 from lazr.restful.declarations import (
-    export_as_webservice_entry,
     exported,
+    exported_as_webservice_entry,
     )
 from lazr.restful.fields import Reference
 from zope.interface import Interface
@@ -84,6 +84,7 @@ class IIncrementalDiff(Interface):
         IRevision, readonly=True, title=_('The new revision of the diff.'))
 
 
+@exported_as_webservice_entry()
 class IPreviewDiff(IDiff):
     """A diff generated to show actual diff between two branches.
 
@@ -91,7 +92,6 @@ class IPreviewDiff(IDiff):
     trying to determine the effective changes of landing the source branch on
     the target branch.
     """
-    export_as_webservice_entry()
 
     source_revision_id = exported(
         TextLine(
diff --git a/lib/lp/code/interfaces/gitref.py b/lib/lp/code/interfaces/gitref.py
index 6c84be5..ef51d99 100644
--- a/lib/lp/code/interfaces/gitref.py
+++ b/lib/lp/code/interfaces/gitref.py
@@ -16,11 +16,11 @@ from textwrap import dedent
 
 from lazr.restful.declarations import (
     call_with,
-    export_as_webservice_entry,
     export_factory_operation,
     export_read_operation,
     export_write_operation,
     exported,
+    exported_as_webservice_entry,
     operation_for_version,
     operation_parameters,
     operation_returns_collection_of,
@@ -460,14 +460,13 @@ class IGitRefEdit(Interface):
         """
 
 
+# XXX cjwatson 2015-01-19 bug=760849: "beta" is a lie to get WADL
+# generation working.  Individual attributes must set their version to
+# "devel".
+@exported_as_webservice_entry(as_of="beta")
 class IGitRef(IGitRefView, IGitRefEdit):
     """A reference in a Git repository."""
 
-    # XXX cjwatson 2015-01-19 bug=760849: "beta" is a lie to get WADL
-    # generation working.  Individual attributes must set their version to
-    # "devel".
-    export_as_webservice_entry(as_of="beta")
-
 
 class IGitRefSet(Interface):
     def findByReposAndPaths(repos_and_paths):
diff --git a/lib/lp/code/interfaces/gitrepository.py b/lib/lp/code/interfaces/gitrepository.py
index 3f636cc..62a11f5 100644
--- a/lib/lp/code/interfaces/gitrepository.py
+++ b/lib/lp/code/interfaces/gitrepository.py
@@ -22,14 +22,14 @@ from lazr.lifecycle.snapshot import doNotSnapshot
 from lazr.restful.declarations import (
     call_with,
     collection_default_content,
-    export_as_webservice_collection,
-    export_as_webservice_entry,
     export_destructor_operation,
     export_factory_operation,
     export_operation_as,
     export_read_operation,
     export_write_operation,
     exported,
+    exported_as_webservice_collection,
+    exported_as_webservice_entry,
     mutator_for,
     operation_for_version,
     operation_parameters,
@@ -913,27 +913,24 @@ class IGitRepositoryEdit(IWebhookTarget):
         """
 
 
+# XXX cjwatson 2015-01-19 bug=760849: "beta" is a lie to get WADL
+# generation working.  Individual attributes must set their version to
+# "devel".
+@exported_as_webservice_entry(plural_name="git_repositories", as_of="beta")
 class IGitRepository(IGitRepositoryView, IGitRepositoryModerateAttributes,
                      IGitRepositoryModerate, IGitRepositoryEditableAttributes,
                      IGitRepositoryEdit):
     """A Git repository."""
 
-    # Mark repositories as exported entries for the Launchpad API.
-    # XXX cjwatson 2015-01-19 bug=760849: "beta" is a lie to get WADL
-    # generation working.  Individual attributes must set their version to
-    # "devel".
-    export_as_webservice_entry(plural_name="git_repositories", as_of="beta")
-
     private = exported(Bool(
         title=_("Private"), required=False, readonly=True,
         description=_("This repository is visible only to its subscribers.")))
 
 
+@exported_as_webservice_collection(IGitRepository)
 class IGitRepositorySet(Interface):
     """Interface representing the set of Git repositories."""
 
-    export_as_webservice_collection(IGitRepository)
-
     @call_with(
         repository_type=GitRepositoryType.HOSTED,
         registrant=REQUEST_USER,
diff --git a/lib/lp/code/interfaces/gitsubscription.py b/lib/lp/code/interfaces/gitsubscription.py
index 94929db..ea015c0 100644
--- a/lib/lp/code/interfaces/gitsubscription.py
+++ b/lib/lp/code/interfaces/gitsubscription.py
@@ -11,9 +11,9 @@ __all__ = [
 
 from lazr.restful.declarations import (
     call_with,
-    export_as_webservice_entry,
     export_read_operation,
     exported,
+    exported_as_webservice_entry,
     operation_for_version,
     REQUEST_USER,
     )
@@ -34,14 +34,13 @@ from lp.code.interfaces.gitrepository import IGitRepository
 from lp.services.fields import PersonChoice
 
 
+# XXX cjwatson 2015-01-19 bug=760849: "beta" is a lie to get WADL
+# generation working.  Individual attributes must set their version to
+# "devel".
+@exported_as_webservice_entry(as_of="beta")
 class IGitSubscription(Interface):
     """The relationship between a person and a Git repository."""
 
-    # XXX cjwatson 2015-01-19 bug=760849: "beta" is a lie to get WADL
-    # generation working.  Individual attributes must set their version to
-    # "devel".
-    export_as_webservice_entry(as_of="beta")
-
     id = Int(title=_("ID"), readonly=True, required=True)
     person_id = Int(title=_("Person ID"), required=True, readonly=True)
     person = exported(
diff --git a/lib/lp/code/interfaces/hasgitrepositories.py b/lib/lp/code/interfaces/hasgitrepositories.py
index 9f78bf9..89bc4c0 100644
--- a/lib/lp/code/interfaces/hasgitrepositories.py
+++ b/lib/lp/code/interfaces/hasgitrepositories.py
@@ -9,10 +9,12 @@ __all__ = [
     'IHasGitRepositories',
     ]
 
-from lazr.restful.declarations import export_as_webservice_entry
+from lazr.restful.declarations import exported_as_webservice_entry
 from zope.interface import Interface
 
 
+@exported_as_webservice_entry(
+    singular_name="git_target", plural_name="git_targets", as_of="devel")
 class IHasGitRepositories(Interface):
     """An object that has related Git repositories.
 
@@ -20,6 +22,3 @@ class IHasGitRepositories(Interface):
     contains Git repositories, and a person contains "personal" Git
     repositories.
     """
-
-    export_as_webservice_entry(
-        singular_name="git_target", plural_name="git_targets", as_of="devel")
diff --git a/lib/lp/code/interfaces/sourcepackagerecipe.py b/lib/lp/code/interfaces/sourcepackagerecipe.py
index 1e5e6d9..b499ccd 100644
--- a/lib/lp/code/interfaces/sourcepackagerecipe.py
+++ b/lib/lp/code/interfaces/sourcepackagerecipe.py
@@ -28,10 +28,10 @@ from lazr.enum import (
 from lazr.lifecycle.snapshot import doNotSnapshot
 from lazr.restful.declarations import (
     call_with,
-    export_as_webservice_entry,
     export_read_operation,
     export_write_operation,
     exported,
+    exported_as_webservice_entry,
     mutator_for,
     operation_for_version,
     operation_parameters,
@@ -312,6 +312,7 @@ class ISourcePackageRecipeDelete(Interface):
         """
 
 
+@exported_as_webservice_entry()
 class ISourcePackageRecipe(ISourcePackageRecipeData,
     ISourcePackageRecipeEdit, ISourcePackageRecipeEditableAttributes,
     ISourcePackageRecipeView):
@@ -320,7 +321,6 @@ class ISourcePackageRecipe(ISourcePackageRecipeData,
     More precisely, it describes how to combine a number of branches into a
     debianized source tree.
     """
-    export_as_webservice_entry()
 
 
 class ISourcePackageRecipeSource(Interface):
diff --git a/lib/lp/code/interfaces/sourcepackagerecipebuild.py b/lib/lp/code/interfaces/sourcepackagerecipebuild.py
index a3d43b3..a4fc9b0 100644
--- a/lib/lp/code/interfaces/sourcepackagerecipebuild.py
+++ b/lib/lp/code/interfaces/sourcepackagerecipebuild.py
@@ -10,9 +10,9 @@ __all__ = [
     ]
 
 from lazr.restful.declarations import (
-    export_as_webservice_entry,
     export_write_operation,
     exported,
+    exported_as_webservice_entry,
     operation_for_version,
     )
 from lazr.restful.fields import (
@@ -105,12 +105,11 @@ class ISourcePackageRecipeBuildEdit(Interface):
         """Delete the build itself."""
 
 
+@exported_as_webservice_entry()
 class ISourcePackageRecipeBuild(ISourcePackageRecipeBuildView,
                                 ISourcePackageRecipeBuildEdit):
     """A build of a source package."""
 
-    export_as_webservice_entry()
-
 
 class ISourcePackageRecipeBuildSource(ISpecificBuildFarmJobSource):
     """A utility of this interface be used to create source package builds."""
diff --git a/lib/lp/hardwaredb/interfaces/hwdb.py b/lib/lp/hardwaredb/interfaces/hwdb.py
index ca76b86..e418abd 100644
--- a/lib/lp/hardwaredb/interfaces/hwdb.py
+++ b/lib/lp/hardwaredb/interfaces/hwdb.py
@@ -49,11 +49,11 @@ from lazr.enum import (
 from lazr.restful.declarations import (
     call_with,
     error_status,
-    export_as_webservice_entry,
     export_destructor_operation,
     export_read_operation,
     export_write_operation,
     exported,
+    exported_as_webservice_entry,
     operation_parameters,
     operation_returns_collection_of,
     operation_returns_entry,
@@ -171,12 +171,12 @@ class HWSubmissionFormat(DBEnumeratedType):
     VERSION_1 = DBItem(1, "Version 1")
 
 
+@exported_as_webservice_entry(publish_web_link=False)
 class IHWSubmission(Interface, IPrivacy):
     """Raw submission data for the hardware database.
 
     See doc/hwdb.txt for details about the attributes.
     """
-    export_as_webservice_entry(publish_web_link=False)
 
     date_created = exported(
         Datetime(
@@ -462,9 +462,9 @@ class IHWSystemFingerprintSet(Interface):
         Return the new entry."""
 
 
+@exported_as_webservice_entry(publish_web_link=False)
 class IHWDriver(Interface):
     """Information about a device driver."""
-    export_as_webservice_entry(publish_web_link=False)
 
     id = exported(
         Int(title=u'Driver ID', required=True, readonly=True))
@@ -589,10 +589,10 @@ class IHWDriverSet(Interface):
         """Return all known distinct package names appearing in HWDriver."""
 
 
+@exported_as_webservice_entry(publish_web_link=False)
 class IHWDriverName(Interface):
     """A driver name as appearing in `IHWDriver`.
     """
-    export_as_webservice_entry(publish_web_link=False)
 
     name = exported(
         TextLine(
@@ -601,10 +601,10 @@ class IHWDriverName(Interface):
                           "IHWDriver.")))
 
 
+@exported_as_webservice_entry(publish_web_link=False)
 class IHWDriverPackageName(Interface):
     """A driver name as appearing in `IHWDriver`.
     """
-    export_as_webservice_entry(publish_web_link=False)
 
     package_name = exported(
         TextLine(
@@ -688,10 +688,10 @@ class IHWVendorNameSet(Interface):
         """
 
 
+@exported_as_webservice_entry(publish_web_link=False)
 class IHWVendorID(Interface):
     """A list of vendor IDs for different busses associated with vendor names.
     """
-    export_as_webservice_entry(publish_web_link=False)
     id = exported(
         Int(title=u'The Database ID', required=True, readonly=True))
 
@@ -744,9 +744,9 @@ class IHWVendorIDSet(Interface):
         """
 
 
+@exported_as_webservice_entry(publish_web_link=False)
 class IHWDeviceClass(Interface):
     """The capabilities of a device."""
-    export_as_webservice_entry(publish_web_link=False)
 
     id = Int(title=u'Device class ID', required=True, readonly=True)
     device = Reference(schema=Interface)
@@ -804,9 +804,9 @@ IDs for other buses may be arbitrary strings.
 """
 
 
+@exported_as_webservice_entry(publish_web_link=False)
 class IHWDevice(Interface):
     """Core information to identify a device."""
-    export_as_webservice_entry(publish_web_link=False)
 
     id = exported(
         Int(title=u'Device ID', required=True, readonly=True))
@@ -1068,9 +1068,9 @@ class IHWDeviceDriverLinkSet(Interface):
         """
 
 
+@exported_as_webservice_entry(publish_web_link=False)
 class IHWSubmissionDevice(Interface):
     """Link a submission to a IHWDeviceDriver row."""
-    export_as_webservice_entry(publish_web_link=False)
 
     id = exported(
         Int(title=u'HWSubmissionDevice ID', required=True, readonly=True))
@@ -1198,11 +1198,10 @@ class IHWSubmissionBugSet(Interface):
         """
 
 
+@exported_as_webservice_entry('hwdb', publish_web_link=False)
 class IHWDBApplication(ILaunchpadApplication):
     """Hardware database application application root."""
 
-    export_as_webservice_entry('hwdb', publish_web_link=False)
-
     @operation_parameters(
         bus=Choice(
             title=u'The device bus', vocabulary=HWBus, required=True),
diff --git a/lib/lp/oci/interfaces/ocipushrule.py b/lib/lp/oci/interfaces/ocipushrule.py
index 5b43f25..b889cdd 100644
--- a/lib/lp/oci/interfaces/ocipushrule.py
+++ b/lib/lp/oci/interfaces/ocipushrule.py
@@ -14,10 +14,10 @@ __all__ = [
 
 from lazr.restful.declarations import (
     error_status,
-    export_as_webservice_entry,
     export_destructor_operation,
     export_write_operation,
     exported,
+    exported_as_webservice_entry,
     mutator_for,
     operation_for_version,
     operation_parameters,
@@ -114,13 +114,12 @@ class IOCIPushRuleEdit(Interface):
         """Destroy this push rule."""
 
 
+@exported_as_webservice_entry(
+    publish_web_link=True, as_of="devel", singular_name="oci_push_rule")
 class IOCIPushRule(IOCIPushRuleEdit, IOCIPushRuleEditableAttributes,
                    IOCIPushRuleView):
     """A rule for pushing builds of an OCI recipe to a registry."""
 
-    export_as_webservice_entry(
-        publish_web_link=True, as_of="devel", singular_name="oci_push_rule")
-
 
 class IOCIPushRuleSet(Interface):
     """A utility to create and access OCI Push Rules."""
diff --git a/lib/lp/oci/interfaces/ocirecipe.py b/lib/lp/oci/interfaces/ocirecipe.py
index 4b2b06d..57eb1df 100644
--- a/lib/lp/oci/interfaces/ocirecipe.py
+++ b/lib/lp/oci/interfaces/ocirecipe.py
@@ -28,10 +28,10 @@ from lazr.lifecycle.snapshot import doNotSnapshot
 from lazr.restful.declarations import (
     call_with,
     error_status,
-    export_as_webservice_entry,
     export_factory_operation,
     export_write_operation,
     exported,
+    exported_as_webservice_entry,
     operation_for_version,
     operation_parameters,
     REQUEST_USER,
@@ -137,11 +137,11 @@ class CannotModifyOCIRecipeProcessor(Exception):
             self._fmt % {'processor': processor.name})
 
 
+@exported_as_webservice_entry(
+    publish_web_link=True, as_of="devel",
+    singular_name="oci_recipe_build_request")
 class IOCIRecipeBuildRequest(Interface):
     """A request to build an OCI Recipe."""
-    export_as_webservice_entry(
-        publish_web_link=True, as_of="devel",
-        singular_name="oci_recipe_build_request")
 
     id = Int(title=_("ID"), required=True, readonly=True)
 
@@ -407,13 +407,12 @@ class IOCIRecipeAdminAttributes(Interface):
         readonly=False))
 
 
+@exported_as_webservice_entry(
+    publish_web_link=True, as_of="devel", singular_name="oci_recipe")
 class IOCIRecipe(IOCIRecipeView, IOCIRecipeEdit, IOCIRecipeEditableAttributes,
                  IOCIRecipeAdminAttributes):
     """A recipe for building Open Container Initiative images."""
 
-    export_as_webservice_entry(
-        publish_web_link=True, as_of="devel", singular_name="oci_recipe")
-
 
 class IOCIRecipeSet(Interface):
     """A utility to create and access OCI Recipes."""
diff --git a/lib/lp/oci/interfaces/ocirecipebuild.py b/lib/lp/oci/interfaces/ocirecipebuild.py
index 5fe56a9..1e521b8 100644
--- a/lib/lp/oci/interfaces/ocirecipebuild.py
+++ b/lib/lp/oci/interfaces/ocirecipebuild.py
@@ -21,9 +21,9 @@ from lazr.enum import (
     )
 from lazr.restful.declarations import (
     error_status,
-    export_as_webservice_entry,
     export_write_operation,
     exported,
+    exported_as_webservice_entry,
     operation_for_version,
     )
 from lazr.restful.fields import (
@@ -257,11 +257,11 @@ class IOCIRecipeBuildAdmin(Interface):
         """Change the build's score."""
 
 
+@exported_as_webservice_entry(
+    publish_web_link=True, as_of="devel", singular_name="oci_recipe_build")
 class IOCIRecipeBuild(IOCIRecipeBuildAdmin, IOCIRecipeBuildEdit,
                       IOCIRecipeBuildView):
     """A build record for an OCI recipe."""
-    export_as_webservice_entry(
-        publish_web_link=True, as_of="devel", singular_name="oci_recipe_build")
 
 
 class IOCIRecipeBuildSet(ISpecificBuildFarmJobSource):
diff --git a/lib/lp/registry/interfaces/commercialsubscription.py b/lib/lp/registry/interfaces/commercialsubscription.py
index 52e9783..e2f619b 100644
--- a/lib/lp/registry/interfaces/commercialsubscription.py
+++ b/lib/lp/registry/interfaces/commercialsubscription.py
@@ -10,8 +10,8 @@ __all__ = [
     ]
 
 from lazr.restful.declarations import (
-    export_as_webservice_entry,
     exported,
+    exported_as_webservice_entry,
     )
 from lazr.restful.fields import ReferenceChoice
 from zope.interface import Interface
@@ -27,14 +27,13 @@ from lp import _
 from lp.services.fields import PublicPersonChoice
 
 
+@exported_as_webservice_entry()
 class ICommercialSubscription(Interface):
     """A Commercial Subscription for a Product.
 
     If the product has a licence which does not qualify for free
     hosting, a subscription needs to be purchased.
     """
-    # Mark commercial subscriptions as exported entries for the Launchpad API.
-    export_as_webservice_entry()
 
     id = Int(title=_('ID'), readonly=True, required=True)
 
diff --git a/lib/lp/registry/interfaces/distribution.py b/lib/lp/registry/interfaces/distribution.py
index fe94cda..ecd6c49 100644
--- a/lib/lp/registry/interfaces/distribution.py
+++ b/lib/lp/registry/interfaces/distribution.py
@@ -20,12 +20,12 @@ from lazr.lifecycle.snapshot import doNotSnapshot
 from lazr.restful.declarations import (
     call_with,
     collection_default_content,
-    export_as_webservice_collection,
-    export_as_webservice_entry,
     export_factory_operation,
     export_operation_as,
     export_read_operation,
     exported,
+    exported_as_webservice_collection,
+    exported_as_webservice_entry,
     operation_for_version,
     operation_parameters,
     operation_returns_collection_of,
@@ -703,6 +703,7 @@ class IDistributionPublic(
         """Create an `IOCIProject` for this distro."""
 
 
+@exported_as_webservice_entry(as_of="beta")
 class IDistribution(
     IDistributionEditRestricted, IDistributionPublic, IHasBugSupervisor,
     IFAQTarget, IQuestionTarget, IStructuralSubscriptionTarget):
@@ -720,12 +721,11 @@ class IDistribution(
             source_name="apport",
             distro_series=series)[0].source_package_version
     """
-    export_as_webservice_entry(as_of="beta")
 
 
+@exported_as_webservice_collection(IDistribution)
 class IDistributionSet(Interface):
     """Interface for DistrosSet"""
-    export_as_webservice_collection(IDistribution)
 
     title = Attribute('Title')
 
diff --git a/lib/lp/registry/interfaces/distributionmirror.py b/lib/lp/registry/interfaces/distributionmirror.py
index d258482..494fe6c 100644
--- a/lib/lp/registry/interfaces/distributionmirror.py
+++ b/lib/lp/registry/interfaces/distributionmirror.py
@@ -23,10 +23,10 @@ from lazr.enum import (
     DBItem,
     )
 from lazr.restful.declarations import (
-    export_as_webservice_entry,
     export_read_operation,
     export_write_operation,
     exported,
+    exported_as_webservice_entry,
     mutator_for,
     operation_parameters,
     )
@@ -320,9 +320,9 @@ class DistroMirrorRsyncURIField(DistroMirrorURIField):
         return getUtility(IDistributionMirrorSet).getByRsyncUrl(url)
 
 
+@exported_as_webservice_entry()
 class IDistributionMirror(Interface):
     """A mirror of a given distribution."""
-    export_as_webservice_entry()
 
     id = Int(title=_('The unique id'), required=True, readonly=True)
     owner = exported(PublicPersonChoice(
diff --git a/lib/lp/registry/interfaces/distributionsourcepackage.py b/lib/lp/registry/interfaces/distributionsourcepackage.py
index 318f4f1..60f75b1 100644
--- a/lib/lp/registry/interfaces/distributionsourcepackage.py
+++ b/lib/lp/registry/interfaces/distributionsourcepackage.py
@@ -10,8 +10,8 @@ __all__ = [
     ]
 
 from lazr.restful.declarations import (
-    export_as_webservice_entry,
     exported,
+    exported_as_webservice_entry,
     )
 from lazr.restful.fields import Reference
 from zope.interface import (
@@ -41,6 +41,7 @@ from lp.registry.interfaces.role import IHasDrivers
 from lp.soyuz.enums import ArchivePurpose
 
 
+@exported_as_webservice_entry()
 class IDistributionSourcePackage(IHeadingContext, IBugTarget, IHasBranches,
                                  IHasMergeProposals, IHasOfficialBugTags,
                                  IStructuralSubscriptionTarget,
@@ -52,8 +53,6 @@ class IDistributionSourcePackage(IHeadingContext, IBugTarget, IHasBranches,
     `IDistribution.getSourcePackage()`.
     """
 
-    export_as_webservice_entry()
-
     distribution = exported(
         Reference(IDistribution, title=_("The distribution.")))
     sourcepackagename = Attribute("The source package name.")
diff --git a/lib/lp/registry/interfaces/distroseries.py b/lib/lp/registry/interfaces/distroseries.py
index 42704d0..aee712f 100644
--- a/lib/lp/registry/interfaces/distroseries.py
+++ b/lib/lp/registry/interfaces/distroseries.py
@@ -18,11 +18,11 @@ from lazr.lifecycle.snapshot import doNotSnapshot
 from lazr.restful.declarations import (
     call_with,
     error_status,
-    export_as_webservice_entry,
     export_factory_operation,
     export_read_operation,
     export_write_operation,
     exported,
+    exported_as_webservice_entry,
     operation_for_version,
     operation_parameters,
     operation_returns_collection_of,
@@ -974,10 +974,10 @@ class IDistroSeriesEditRestricted(Interface):
         """
 
 
+@exported_as_webservice_entry()
 class IDistroSeries(IDistroSeriesEditRestricted, IDistroSeriesPublic,
                     IStructuralSubscriptionTarget):
     """A series of an operating system distribution."""
-    export_as_webservice_entry()
 
 
 # We assign the schema for an `IHasBugs` method argument here
diff --git a/lib/lp/registry/interfaces/distroseriesdifference.py b/lib/lp/registry/interfaces/distroseriesdifference.py
index 0f6ed33..9b85ae5 100644
--- a/lib/lp/registry/interfaces/distroseriesdifference.py
+++ b/lib/lp/registry/interfaces/distroseriesdifference.py
@@ -16,9 +16,9 @@ __all__ = [
 
 from lazr.restful.declarations import (
     call_with,
-    export_as_webservice_entry,
     export_write_operation,
     exported,
+    exported_as_webservice_entry,
     operation_parameters,
     REQUEST_USER,
     )
@@ -282,11 +282,11 @@ class IDistroSeriesDifferenceAdmin(Interface):
         """
 
 
+@exported_as_webservice_entry()
 class IDistroSeriesDifference(IDistroSeriesDifferencePublic,
                               IDistroSeriesDifferenceEdit,
                               IDistroSeriesDifferenceAdmin):
     """An interface for a package difference between two distroseries."""
-    export_as_webservice_entry()
 
 
 class IDistroSeriesDifferenceSource(Interface):
diff --git a/lib/lp/registry/interfaces/distroseriesdifferencecomment.py b/lib/lp/registry/interfaces/distroseriesdifferencecomment.py
index 1d5af23..2502a04 100644
--- a/lib/lp/registry/interfaces/distroseriesdifferencecomment.py
+++ b/lib/lp/registry/interfaces/distroseriesdifferencecomment.py
@@ -11,8 +11,8 @@ __all__ = [
 
 
 from lazr.restful.declarations import (
-    export_as_webservice_entry,
     exported,
+    exported_as_webservice_entry,
     )
 from lazr.restful.fields import Reference
 from zope.interface import Interface
@@ -30,9 +30,9 @@ from lp.registry.interfaces.distroseriesdifference import (
 from lp.services.messages.interfaces.message import IMessage
 
 
+@exported_as_webservice_entry()
 class IDistroSeriesDifferenceComment(Interface):
     """A comment for a distroseries difference record."""
-    export_as_webservice_entry()
 
     id = Int(title=_('ID'), required=True, readonly=True)
 
diff --git a/lib/lp/registry/interfaces/gpg.py b/lib/lp/registry/interfaces/gpg.py
index 32e8a2c..2ae0226 100644
--- a/lib/lp/registry/interfaces/gpg.py
+++ b/lib/lp/registry/interfaces/gpg.py
@@ -12,8 +12,8 @@ __all__ = [
 
 
 from lazr.restful.declarations import (
-    export_as_webservice_entry,
     exported,
+    exported_as_webservice_entry,
     )
 from zope.interface import (
     Attribute,
@@ -34,11 +34,10 @@ from lp.services.gpg.interfaces import (
     )
 
 
+@exported_as_webservice_entry('gpg_key')
 class IGPGKey(IHasOwner):
     """OpenPGP support"""
 
-    export_as_webservice_entry('gpg_key')
-
     keysize = Int(title=_("Keysize"), required=True)
     algorithm = Choice(title=_("Algorithm"), required=True,
             vocabulary='GpgAlgorithm')
diff --git a/lib/lp/registry/interfaces/irc.py b/lib/lp/registry/interfaces/irc.py
index 196cdff..63c4514 100644
--- a/lib/lp/registry/interfaces/irc.py
+++ b/lib/lp/registry/interfaces/irc.py
@@ -11,8 +11,8 @@ __all__ = [
     ]
 
 from lazr.restful.declarations import (
-    export_as_webservice_entry,
     exported,
+    exported_as_webservice_entry,
     )
 from lazr.restful.fields import Reference
 from zope.interface import Interface
@@ -25,9 +25,9 @@ from lp import _
 from lp.registry.interfaces.role import IHasOwner
 
 
+@exported_as_webservice_entry('irc_id')
 class IIrcID(IHasOwner):
     """A person's nickname on an IRC network."""
-    export_as_webservice_entry('irc_id')
     id = Int(title=_("Database ID"), required=True, readonly=True)
     # schema=Interface will be overridden in person.py because of circular
     # dependencies.
diff --git a/lib/lp/registry/interfaces/jabber.py b/lib/lp/registry/interfaces/jabber.py
index abc9e18..df1d8fb 100644
--- a/lib/lp/registry/interfaces/jabber.py
+++ b/lib/lp/registry/interfaces/jabber.py
@@ -11,8 +11,8 @@ __all__ = [
     ]
 
 from lazr.restful.declarations import (
-    export_as_webservice_entry,
     exported,
+    exported_as_webservice_entry,
     )
 from lazr.restful.fields import Reference
 from zope.interface import Interface
@@ -25,9 +25,9 @@ from lp import _
 from lp.registry.interfaces.role import IHasOwner
 
 
+@exported_as_webservice_entry('jabber_id')
 class IJabberID(IHasOwner):
     """Jabber specific user ID """
-    export_as_webservice_entry('jabber_id')
     id = Int(title=_("Database ID"), required=True, readonly=True)
     # schema=Interface will be overridden in person.py because of circular
     # dependencies.
diff --git a/lib/lp/registry/interfaces/milestone.py b/lib/lp/registry/interfaces/milestone.py
index 7548285..2ed580f 100644
--- a/lib/lp/registry/interfaces/milestone.py
+++ b/lib/lp/registry/interfaces/milestone.py
@@ -18,13 +18,13 @@ __all__ = [
 from lazr.lifecycle.snapshot import doNotSnapshot
 from lazr.restful.declarations import (
     call_with,
-    export_as_webservice_entry,
     export_destructor_operation,
     export_factory_operation,
     export_operation_as,
     export_read_operation,
     export_write_operation,
     exported,
+    exported_as_webservice_entry,
     operation_for_version,
     operation_parameters,
     operation_returns_entry,
@@ -231,11 +231,10 @@ class IAbstractMilestone(IMilestoneData):
         """
 
 
+@exported_as_webservice_entry()
 class IMilestone(IAbstractMilestone):
     """Actual interface for milestones."""
 
-    export_as_webservice_entry()
-
     @operation_parameters(
         tags=List(
             title=_("Tags for this milestone"),
@@ -315,14 +314,14 @@ class IMilestoneSet(Interface):
         """Return all visible milestones."""
 
 
+@exported_as_webservice_entry(as_of="beta")
 class IProjectGroupMilestone(IAbstractMilestone):
     """A marker interface for milestones related to a project"""
-    export_as_webservice_entry(as_of="beta")
 
 
+@exported_as_webservice_entry()
 class IHasMilestones(Interface):
     """An interface for classes providing milestones."""
-    export_as_webservice_entry()
 
     has_milestones = Bool(title=_("Whether the object has any milestones."))
 
diff --git a/lib/lp/registry/interfaces/ociproject.py b/lib/lp/registry/interfaces/ociproject.py
index 8e66f5d..59d6775 100644
--- a/lib/lp/registry/interfaces/ociproject.py
+++ b/lib/lp/registry/interfaces/ociproject.py
@@ -16,9 +16,9 @@ __all__ = [
 from lazr.restful.declarations import (
     call_with,
     error_status,
-    export_as_webservice_entry,
     export_factory_operation,
     exported,
+    exported_as_webservice_entry,
     operation_for_version,
     operation_parameters,
     REQUEST_USER,
@@ -173,13 +173,12 @@ class IOCIProjectLegitimate(Interface):
         """Create an IOCIRecipe for this project."""
 
 
+@exported_as_webservice_entry(
+    publish_web_link=True, as_of="devel", singular_name="oci_project")
 class IOCIProject(IOCIProjectView, IOCIProjectEdit,
                   IOCIProjectEditableAttributes, IOCIProjectLegitimate):
     """A project containing Open Container Initiative recipes."""
 
-    export_as_webservice_entry(
-        publish_web_link=True, as_of="devel", singular_name="oci_project")
-
 
 class IOCIProjectSet(Interface):
     """A utility to create and access OCI Projects."""
diff --git a/lib/lp/registry/interfaces/ociprojectseries.py b/lib/lp/registry/interfaces/ociprojectseries.py
index 274fc4f..d51eebd 100644
--- a/lib/lp/registry/interfaces/ociprojectseries.py
+++ b/lib/lp/registry/interfaces/ociprojectseries.py
@@ -13,8 +13,8 @@ __all__ = [
     ]
 
 from lazr.restful.declarations import (
-    export_as_webservice_entry,
     exported,
+    exported_as_webservice_entry,
     )
 from lazr.restful.fields import Reference
 from zope.interface import Interface
@@ -78,13 +78,11 @@ class IOCIProjectSeriesEdit(Interface):
     """IOCIProjectSeries attributes that require launchpad.Edit permission."""
 
 
+@exported_as_webservice_entry(
+    publish_web_link=True, as_of="devel", singular_name="oci_project_series")
 class IOCIProjectSeries(IOCIProjectSeriesView, IOCIProjectSeriesEdit,
                         IOCIProjectSeriesEditableAttributes):
     """A series of an Open Container Initiative project.
 
     This is used to allow tracking bugs against multiple versions of images.
     """
-
-    export_as_webservice_entry(
-        publish_web_link=True, as_of="devel",
-        singular_name="oci_project_series")
diff --git a/lib/lp/registry/interfaces/person.py b/lib/lp/registry/interfaces/person.py
index 6ce09b1..273b50b 100644
--- a/lib/lp/registry/interfaces/person.py
+++ b/lib/lp/registry/interfaces/person.py
@@ -49,12 +49,12 @@ from lazr.restful.declarations import (
     call_with,
     collection_default_content,
     error_status,
-    export_as_webservice_collection,
-    export_as_webservice_entry,
     export_factory_operation,
     export_read_operation,
     export_write_operation,
     exported,
+    exported_as_webservice_collection,
+    exported_as_webservice_entry,
     mutator_for,
     operation_for_version,
     operation_parameters,
@@ -1895,12 +1895,12 @@ class IPersonSettings(IPersonSettingsViewRestricted, IPersonSettingsModerate):
     """A person's settings."""
 
 
+@exported_as_webservice_entry(plural_name='people')
 class IPerson(IPersonPublic, IPersonLimitedView, IPersonViewRestricted,
               IPersonEditRestricted, IPersonModerate,
               IPersonModerateRestricted, IPersonSpecialRestricted,
               IPersonSettings, IHasStanding, ISetLocation, IHeadingContext):
     """A Person."""
-    export_as_webservice_entry(plural_name='people')
 
 
 # Set the schemas to the newly defined interface for classes that deferred
@@ -2027,6 +2027,7 @@ class ITeamPublic(Interface):
         """
 
 
+@exported_as_webservice_entry('team')
 class ITeam(IPerson, ITeamPublic):
     """A group of people and other teams.
 
@@ -2045,7 +2046,6 @@ class ITeam(IPerson, ITeamPublic):
     - ITeam extends IPerson.
     - The teamowner should never be None.
     """
-    export_as_webservice_entry('team')
 
     # Logo, Mugshot and display_name are here so that they can have a
     # description on a Team which is different to the description they have on
@@ -2072,9 +2072,9 @@ class ITeam(IPerson, ITeamPublic):
             "Launchpad."))
 
 
+@exported_as_webservice_collection(IPerson)
 class IPersonSet(Interface):
     """The set of Persons."""
-    export_as_webservice_collection(IPerson)
 
     title = Attribute('Title')
 
diff --git a/lib/lp/registry/interfaces/pillar.py b/lib/lp/registry/interfaces/pillar.py
index 41149c4..25ef03f 100644
--- a/lib/lp/registry/interfaces/pillar.py
+++ b/lib/lp/registry/interfaces/pillar.py
@@ -10,9 +10,9 @@ __metaclass__ = type
 
 from lazr.restful.declarations import (
     call_with,
-    export_as_webservice_entry,
     export_read_operation,
     exported,
+    exported_as_webservice_entry,
     operation_parameters,
     operation_returns_collection_of,
     REQUEST_USER,
@@ -53,13 +53,13 @@ __all__ = [
     ]
 
 
+@exported_as_webservice_entry()
 class IPillar(IHeadingContext):
     """An object that might be a project, a project group, or a distribution.
 
     This is a polymorphic object served by the pillar set. Check the
     individual object to see what type it is.
     """
-    export_as_webservice_entry()
     active = exported(
         Bool(title=_('Active'),
              description=_("Whether or not this item is active.")))
@@ -124,6 +124,7 @@ class IPillarName(Interface):
     pillar = Attribute('The pillar object')
 
 
+@exported_as_webservice_entry('pillars')
 class IPillarNameSet(Interface):
     """An object for searching across projects, project groups, and distros.
 
@@ -132,7 +133,6 @@ class IPillarNameSet(Interface):
     types of pillars. It also gives you access to pillars that have
     been flagged by administrators as "featured" pillars.
     """
-    export_as_webservice_entry('pillars')
 
     def __contains__(name):
         """True if the given name is an active Pillar or an alias to one."""
diff --git a/lib/lp/registry/interfaces/product.py b/lib/lp/registry/interfaces/product.py
index 6b3df06..c15a8b3 100644
--- a/lib/lp/registry/interfaces/product.py
+++ b/lib/lp/registry/interfaces/product.py
@@ -33,13 +33,13 @@ from lazr.lifecycle.snapshot import doNotSnapshot
 from lazr.restful.declarations import (
     call_with,
     collection_default_content,
-    export_as_webservice_collection,
-    export_as_webservice_entry,
     export_factory_operation,
     export_operation_as,
     export_read_operation,
     export_write_operation,
     exported,
+    exported_as_webservice_collection,
+    exported_as_webservice_entry,
     mutator_for,
     operation_for_version,
     operation_parameters,
@@ -891,6 +891,7 @@ class IProductEditRestricted(IOfficialBugTagTargetRestricted):
         """
 
 
+@exported_as_webservice_entry('project')
 class IProduct(
     IBugTarget, IHasBugSupervisor, IHasDrivers, IProductEditRestricted,
     IProductModerateRestricted, IProductDriverRestricted, IProductView,
@@ -905,8 +906,6 @@ class IProduct(
     Mozilla App Suite as Products, among others.
     """
 
-    export_as_webservice_entry('project')
-
     drivers = Attribute(
         "Presents the drivers of this project as a list. A list is "
         "required because there might be a project driver and also a "
@@ -918,8 +917,8 @@ patch_collection_property(IProjectGroup, 'products', IProduct)
 patch_reference_property(IProductRelease, 'product', IProduct)
 
 
+@exported_as_webservice_collection(IProduct)
 class IProductSet(Interface):
-    export_as_webservice_collection(IProduct)
 
     title = Attribute("The set of Products registered in the Launchpad")
 
diff --git a/lib/lp/registry/interfaces/productrelease.py b/lib/lp/registry/interfaces/productrelease.py
index c5aef3e..ff55907 100644
--- a/lib/lp/registry/interfaces/productrelease.py
+++ b/lib/lp/registry/interfaces/productrelease.py
@@ -23,11 +23,11 @@ from lazr.enum import (
     )
 from lazr.restful.declarations import (
     call_with,
-    export_as_webservice_entry,
     export_factory_operation,
     export_operation_as,
     export_write_operation,
     exported,
+    exported_as_webservice_entry,
     operation_parameters,
     REQUEST_USER,
     )
@@ -216,10 +216,10 @@ class IProductReleaseFilePublic(Interface):
                  required=True, readonly=True))
 
 
+@exported_as_webservice_entry("project_release_file", publish_web_link=False)
 class IProductReleaseFile(IProductReleaseFileEditRestricted,
                           IProductReleaseFilePublic):
     """A file associated with a ProductRelease."""
-    export_as_webservice_entry("project_release_file", publish_web_link=False)
 
 
 class IProductReleaseEditRestricted(Interface):
@@ -376,6 +376,7 @@ class IProductReleaseView(Interface):
         """Does the release have a file that matches the name?"""
 
 
+@exported_as_webservice_entry('project_release')
 class IProductRelease(IProductReleaseEditRestricted, IProductReleaseView,
                       IProductReleasePublic):
     """A specific release (i.e. version) of a product.
@@ -383,8 +384,6 @@ class IProductRelease(IProductReleaseEditRestricted, IProductReleaseView,
     For example: Mozilla 1.7.2 or Apache 2.0.48.
     """
 
-    export_as_webservice_entry('project_release')
-
 
 # Set the schema for IProductReleaseFile now that IProductRelease is defined.
 patch_reference_property(
diff --git a/lib/lp/registry/interfaces/productseries.py b/lib/lp/registry/interfaces/productseries.py
index 4de9b23..ee91924 100644
--- a/lib/lp/registry/interfaces/productseries.py
+++ b/lib/lp/registry/interfaces/productseries.py
@@ -18,11 +18,11 @@ __all__ = [
 
 from lazr.lifecycle.snapshot import doNotSnapshot
 from lazr.restful.declarations import (
-    export_as_webservice_entry,
     export_factory_operation,
     export_operation_as,
     export_read_operation,
     exported,
+    exported_as_webservice_entry,
     operation_parameters,
     rename_parameters_as,
     )
@@ -336,21 +336,20 @@ class IProductSeriesView(
         """
 
 
+@exported_as_webservice_entry('project_series')
 class IProductSeries(IProductSeriesEditRestricted, IProductSeriesPublic,
                      IProductSeriesView, IProductSeriesLimitedView,
                      IStructuralSubscriptionTarget, IBugTarget):
     """A series of releases. For example '2.0' or '1.3' or 'dev'."""
-    export_as_webservice_entry('project_series')
 
 
+# XXX: EdwinGrubbs 2010-11-18 bug=677671
+# lazr.restful can't batch a DecoratedResultSet returning basic
+# python types such as dicts, so this interface is necessary.
+@exported_as_webservice_entry('timeline_project_series')
 class ITimelineProductSeries(Interface):
     """Minimal product series info for the timeline."""
 
-    # XXX: EdwinGrubbs 2010-11-18 bug=677671
-    # lazr.restful can't batch a DecoratedResultSet returning basic
-    # python types such as dicts, so this interface is necessary.
-    export_as_webservice_entry('timeline_project_series')
-
     name = IProductSeries['name']
 
     status = IProductSeries['status']
diff --git a/lib/lp/registry/interfaces/projectgroup.py b/lib/lp/registry/interfaces/projectgroup.py
index 5a4004e..f8f0708 100644
--- a/lib/lp/registry/interfaces/projectgroup.py
+++ b/lib/lp/registry/interfaces/projectgroup.py
@@ -14,10 +14,10 @@ __all__ = [
 
 from lazr.restful.declarations import (
     collection_default_content,
-    export_as_webservice_collection,
-    export_as_webservice_entry,
     export_read_operation,
     exported,
+    exported_as_webservice_collection,
+    exported_as_webservice_entry,
     operation_parameters,
     operation_returns_collection_of,
     )
@@ -352,22 +352,20 @@ class IProjectGroupPublic(
     product_milestones = Attribute('all the milestones for all the products.')
 
 
+@exported_as_webservice_entry('project_group')
 class IProjectGroup(IProjectGroupPublic,
                     IProjectGroupModerate,
                     IStructuralSubscriptionTarget,
                     ITranslationPolicy):
     """A ProjectGroup."""
 
-    export_as_webservice_entry('project_group')
-
 
 # Interfaces for set
 
+@exported_as_webservice_collection(IProjectGroup)
 class IProjectGroupSet(Interface):
     """The collection of projects."""
 
-    export_as_webservice_collection(IProjectGroup)
-
     title = Attribute('Title')
 
     def __iter__():
diff --git a/lib/lp/registry/interfaces/sharingservice.py b/lib/lp/registry/interfaces/sharingservice.py
index a6ea66a..386fef4 100644
--- a/lib/lp/registry/interfaces/sharingservice.py
+++ b/lib/lp/registry/interfaces/sharingservice.py
@@ -12,9 +12,9 @@ __all__ = [
 
 from lazr.restful.declarations import (
     call_with,
-    export_as_webservice_entry,
     export_read_operation,
     export_write_operation,
+    exported_as_webservice_entry,
     operation_for_version,
     operation_parameters,
     operation_returns_collection_of,
@@ -47,13 +47,12 @@ from lp.registry.interfaces.pillar import IPillar
 from lp.registry.interfaces.product import IProduct
 
 
+# XXX 2012-02-24 wallyworld bug 939910
+# Need to export for version 'beta' even though we only want to use it in
+# version 'devel'
+@exported_as_webservice_entry(publish_web_link=False, as_of='beta')
 class ISharingService(IService):
 
-    # XXX 2012-02-24 wallyworld bug 939910
-    # Need to export for version 'beta' even though we only want to use it in
-    # version 'devel'
-    export_as_webservice_entry(publish_web_link=False, as_of='beta')
-
     def checkPillarAccess(pillars, information_type, person):
         """Check the person's access to the given pillars and information type.
 
diff --git a/lib/lp/registry/interfaces/sourcepackage.py b/lib/lp/registry/interfaces/sourcepackage.py
index d80dd7e..9699c32 100644
--- a/lib/lp/registry/interfaces/sourcepackage.py
+++ b/lib/lp/registry/interfaces/sourcepackage.py
@@ -21,10 +21,10 @@ from lazr.enum import (
     )
 from lazr.restful.declarations import (
     call_with,
-    export_as_webservice_entry,
     export_read_operation,
     export_write_operation,
     exported,
+    exported_as_webservice_entry,
     operation_for_version,
     operation_parameters,
     operation_returns_entry,
@@ -323,9 +323,9 @@ class ISourcePackageEdit(Interface):
         """
 
 
+@exported_as_webservice_entry()
 class ISourcePackage(ISourcePackagePublic, ISourcePackageEdit):
     """A source package associated to a particular distribution series."""
-    export_as_webservice_entry()
 
 
 class ISourcePackageFactory(Interface):
diff --git a/lib/lp/registry/interfaces/ssh.py b/lib/lp/registry/interfaces/ssh.py
index 7d78030..bec3496 100644
--- a/lib/lp/registry/interfaces/ssh.py
+++ b/lib/lp/registry/interfaces/ssh.py
@@ -19,8 +19,8 @@ from lazr.enum import (
     )
 from lazr.restful.declarations import (
     error_status,
-    export_as_webservice_entry,
     exported,
+    exported_as_webservice_entry,
     )
 import six
 from six.moves import http_client
@@ -69,11 +69,10 @@ SSH_TEXT_TO_KEY_TYPE = {
     }
 
 
+@exported_as_webservice_entry('ssh_key')
 class ISSHKey(Interface):
     """SSH public key"""
 
-    export_as_webservice_entry('ssh_key')
-
     id = Int(title=_("Database ID"), required=True, readonly=True)
     person = Int(title=_("Owner"), required=True, readonly=True)
     personID = Int(title=_('Owner ID'), required=True, readonly=True)
diff --git a/lib/lp/registry/interfaces/suitesourcepackage.py b/lib/lp/registry/interfaces/suitesourcepackage.py
index d80403c..a3274d4 100644
--- a/lib/lp/registry/interfaces/suitesourcepackage.py
+++ b/lib/lp/registry/interfaces/suitesourcepackage.py
@@ -9,8 +9,8 @@ __all__ = [
     ]
 
 from lazr.restful.declarations import (
-    export_as_webservice_entry,
     exported,
+    exported_as_webservice_entry,
     )
 from lazr.restful.fields import Reference
 from zope.interface import Interface
@@ -26,11 +26,10 @@ from lp.registry.interfaces.pocket import PackagePublishingPocket
 from lp.registry.interfaces.sourcepackage import ISourcePackage
 
 
+@exported_as_webservice_entry()
 class ISuiteSourcePackage(Interface):
     """A source package that's on a pocket."""
 
-    export_as_webservice_entry()
-
     displayname = exported(
         TextLine(
             title=_("Display name"),
diff --git a/lib/lp/registry/interfaces/teammembership.py b/lib/lp/registry/interfaces/teammembership.py
index 482095f..3da9f23 100644
--- a/lib/lp/registry/interfaces/teammembership.py
+++ b/lib/lp/registry/interfaces/teammembership.py
@@ -23,9 +23,9 @@ from lazr.enum import (
     )
 from lazr.restful.declarations import (
     call_with,
-    export_as_webservice_entry,
     export_write_operation,
     exported,
+    exported_as_webservice_entry,
     operation_parameters,
     REQUEST_USER,
     )
@@ -115,13 +115,13 @@ class TeamMembershipStatus(DBEnumeratedType):
 ACTIVE_STATES = [TeamMembershipStatus.ADMIN, TeamMembershipStatus.APPROVED]
 
 
+@exported_as_webservice_entry()
 class ITeamMembership(Interface):
     """TeamMembership for Users.
 
     This table includes *direct* team members only.  Indirect memberships are
     handled by the TeamParticipation table.
     """
-    export_as_webservice_entry()
 
     id = Int(title=_('ID'), required=True, readonly=True)
     team = exported(
diff --git a/lib/lp/registry/interfaces/wikiname.py b/lib/lp/registry/interfaces/wikiname.py
index b1b53a8..015d1b9 100644
--- a/lib/lp/registry/interfaces/wikiname.py
+++ b/lib/lp/registry/interfaces/wikiname.py
@@ -7,8 +7,8 @@ __all__ = [
     ]
 
 from lazr.restful.declarations import (
-    export_as_webservice_entry,
     exported,
+    exported_as_webservice_entry,
     )
 from lazr.restful.fields import Reference
 from zope.interface import Interface
@@ -22,9 +22,9 @@ from lp.registry.interfaces.role import IHasOwner
 from lp.services.fields import URIField
 
 
+@exported_as_webservice_entry(publish_web_link=False)
 class IWikiName(IHasOwner):
     """Wiki for Users"""
-    export_as_webservice_entry(publish_web_link=False)
     id = Int(title=_("Database ID"), required=True, readonly=True)
     # schema=Interface will be overridden in person.py because of circular
     # dependencies.
diff --git a/lib/lp/services/identity/interfaces/emailaddress.py b/lib/lp/services/identity/interfaces/emailaddress.py
index 3af3a22..89391da 100644
--- a/lib/lp/services/identity/interfaces/emailaddress.py
+++ b/lib/lp/services/identity/interfaces/emailaddress.py
@@ -18,8 +18,8 @@ from lazr.enum import (
     )
 from lazr.restful.declarations import (
     error_status,
-    export_as_webservice_entry,
     exported,
+    exported_as_webservice_entry,
     )
 from lazr.restful.fields import Reference
 from six.moves import http_client
@@ -93,9 +93,9 @@ VALID_EMAIL_STATUSES = (
     EmailAddressStatus.PREFERRED)
 
 
+@exported_as_webservice_entry(plural_name='email_addresses')
 class IEmailAddress(IHasOwner):
     """The object that stores the `IPerson`'s emails."""
-    export_as_webservice_entry(plural_name='email_addresses')
 
     id = Int(title=_('ID'), required=True, readonly=True)
     email = exported(
diff --git a/lib/lp/services/messages/interfaces/message.py b/lib/lp/services/messages/interfaces/message.py
index 944bcbe..f105300 100644
--- a/lib/lp/services/messages/interfaces/message.py
+++ b/lib/lp/services/messages/interfaces/message.py
@@ -22,9 +22,9 @@ __all__ = [
 from lazr.delegates import delegate_to
 from lazr.restful.declarations import (
     accessor_for,
-    export_as_webservice_entry,
     export_read_operation,
     exported,
+    exported_as_webservice_entry,
     operation_for_version,
     )
 from lazr.restful.fields import (
@@ -51,13 +51,13 @@ from lp.services.librarian.interfaces import ILibraryFileAlias
 from lp.services.webservice.apihelpers import patch_reference_property
 
 
+@exported_as_webservice_entry('message')
 class IMessage(Interface):
     """A message.
 
     This is like an email (RFC822) message, though it could be created through
     the web as well.
     """
-    export_as_webservice_entry('message')
 
     id = Int(title=_('ID'), required=True, readonly=True)
     datecreated = exported(
diff --git a/lib/lp/services/temporaryblobstorage/interfaces.py b/lib/lp/services/temporaryblobstorage/interfaces.py
index d70090e..c941f36 100644
--- a/lib/lp/services/temporaryblobstorage/interfaces.py
+++ b/lib/lp/services/temporaryblobstorage/interfaces.py
@@ -13,10 +13,10 @@ __all__ = [
 
 from lazr.restful.declarations import (
     collection_default_content,
-    export_as_webservice_collection,
-    export_as_webservice_entry,
     export_read_operation,
     exported,
+    exported_as_webservice_collection,
+    exported_as_webservice_entry,
     operation_parameters,
     rename_parameters_as,
     )
@@ -41,11 +41,11 @@ class BlobTooLarge(Exception):
     pass
 
 
+@exported_as_webservice_entry(
+    singular_name='temporary_blob', plural_name='temporary_blobs',
+    as_of="beta")
 class ITemporaryBlobStorage(Interface):
     """A blob which we will store in the database temporarily."""
-    export_as_webservice_entry(
-        singular_name='temporary_blob', plural_name='temporary_blobs',
-        as_of="beta")
 
     uuid = exported(
         Text(title=_('UUID'), required=True, readonly=True),
@@ -64,9 +64,9 @@ class ITemporaryBlobStorage(Interface):
         """Returns a dict containing the processed blob data."""
 
 
+@exported_as_webservice_collection(ITemporaryBlobStorage)
 class ITemporaryStorageManager(Interface):
     """A tool to create temporary blobs."""
-    export_as_webservice_collection(ITemporaryBlobStorage)
 
     def new(blob, expires=None):
         """Create a new blob for storage in the database, returning the
diff --git a/lib/lp/services/webhooks/interfaces.py b/lib/lp/services/webhooks/interfaces.py
index ad01625..8b7c009 100644
--- a/lib/lp/services/webhooks/interfaces.py
+++ b/lib/lp/services/webhooks/interfaces.py
@@ -26,11 +26,11 @@ from lazr.lifecycle.snapshot import doNotSnapshot
 from lazr.restful.declarations import (
     call_with,
     error_status,
-    export_as_webservice_entry,
     export_destructor_operation,
     export_factory_operation,
     export_write_operation,
     exported,
+    exported_as_webservice_entry,
     operation_for_version,
     operation_parameters,
     REQUEST_USER,
@@ -125,10 +125,9 @@ class ValidWebhookEventTypeVocabulary(SimpleVocabulary):
         super(ValidWebhookEventTypeVocabulary, self).__init__(terms)
 
 
+@exported_as_webservice_entry(as_of='beta')
 class IWebhook(Interface):
 
-    export_as_webservice_entry(as_of='beta')
-
     id = Int(title=_("ID"), readonly=True, required=True)
 
     target = exported(Reference(
@@ -207,10 +206,9 @@ class IWebhookSet(Interface):
         """Trigger subscribed webhooks to deliver a payload."""
 
 
+@exported_as_webservice_entry(as_of='beta')
 class IWebhookTarget(Interface):
 
-    export_as_webservice_entry(as_of='beta')
-
     webhooks = exported(doNotSnapshot(CollectionField(
         title=_("Webhooks for this target."),
         value_type=Reference(schema=IWebhook),
@@ -261,11 +259,10 @@ class IWebhookJobSource(IJobSource):
         """Delete all `IWebhookJob`s for the given `IWebhook`."""
 
 
+@exported_as_webservice_entry('webhook_delivery', as_of='beta')
 class IWebhookDeliveryJob(IRunnableJob):
     """A Job that delivers an event to a webhook consumer."""
 
-    export_as_webservice_entry('webhook_delivery', as_of='beta')
-
     webhook = exported(Reference(
         title=_("Webhook"),
         description=_("The webhook that this delivery is for."),
diff --git a/lib/lp/services/worlddata/interfaces/country.py b/lib/lp/services/worlddata/interfaces/country.py
index 2ade8ea..a7e087a 100644
--- a/lib/lp/services/worlddata/interfaces/country.py
+++ b/lib/lp/services/worlddata/interfaces/country.py
@@ -13,10 +13,10 @@ __all__ = [
 
 from lazr.restful.declarations import (
     collection_default_content,
-    export_as_webservice_collection,
-    export_as_webservice_entry,
     export_read_operation,
     exported,
+    exported_as_webservice_collection,
+    exported_as_webservice_entry,
     operation_parameters,
     operation_returns_entry,
     )
@@ -37,10 +37,9 @@ from lp.services.fields import (
     )
 
 
+@exported_as_webservice_entry(plural_name='countries', publish_web_link=False)
 class ICountry(Interface):
     """The country description."""
-    export_as_webservice_entry(
-        plural_name='countries', publish_web_link=False)
 
     id = Int(
         title=_('Country ID'), required=True, readonly=True,
@@ -67,9 +66,9 @@ class ICountry(Interface):
                           "that country.")
 
 
+@exported_as_webservice_collection(ICountry)
 class ICountrySet(Interface):
     """A container for countries."""
-    export_as_webservice_collection(ICountry)
 
     def __getitem__(key):
         """Get a country."""
diff --git a/lib/lp/services/worlddata/interfaces/language.py b/lib/lp/services/worlddata/interfaces/language.py
index 31d4e0a..a283c97 100644
--- a/lib/lp/services/worlddata/interfaces/language.py
+++ b/lib/lp/services/worlddata/interfaces/language.py
@@ -19,10 +19,10 @@ from lazr.lifecycle.snapshot import doNotSnapshot
 from lazr.restful.declarations import (
     call_with,
     collection_default_content,
-    export_as_webservice_collection,
-    export_as_webservice_entry,
     export_read_operation,
     exported,
+    exported_as_webservice_collection,
+    exported_as_webservice_entry,
     operation_returns_collection_of,
     )
 from zope.interface import (
@@ -57,9 +57,9 @@ class TextDirection(DBEnumeratedType):
         """)
 
 
+@exported_as_webservice_entry()
 class ILanguage(Interface):
     """A Language."""
-    export_as_webservice_entry()
 
     id = Attribute("This Language ID.")
 
@@ -173,6 +173,7 @@ class ILanguage(Interface):
                 'must be set together, or not at all.')
 
 
+@exported_as_webservice_collection(ILanguage)
 class ILanguageSet(Interface):
     """The collection of languages.
 
@@ -181,8 +182,6 @@ class ILanguageSet(Interface):
     the getAllLanguages method.
     """
 
-    export_as_webservice_collection(ILanguage)
-
     @export_read_operation()
     @operation_returns_collection_of(ILanguage)
     @call_with(want_translators_count=True)
diff --git a/lib/lp/snappy/interfaces/snap.py b/lib/lp/snappy/interfaces/snap.py
index 1bad725..a6460b7 100644
--- a/lib/lp/snappy/interfaces/snap.py
+++ b/lib/lp/snappy/interfaces/snap.py
@@ -47,13 +47,13 @@ from lazr.restful.declarations import (
     call_with,
     collection_default_content,
     error_status,
-    export_as_webservice_collection,
-    export_as_webservice_entry,
     export_destructor_operation,
     export_factory_operation,
     export_read_operation,
     export_write_operation,
     exported,
+    exported_as_webservice_collection,
+    exported_as_webservice_entry,
     operation_for_version,
     operation_parameters,
     operation_returns_collection_of,
@@ -293,14 +293,13 @@ class SnapBuildRequestStatus(EnumeratedType):
         """)
 
 
+# XXX cjwatson 2018-06-14 bug=760849: "beta" is a lie to get WADL
+# generation working.  Individual attributes must set their version to
+# "devel".
+@exported_as_webservice_entry(as_of="beta")
 class ISnapBuildRequest(Interface):
     """A request to build a snap package."""
 
-    # XXX cjwatson 2018-06-14 bug=760849: "beta" is a lie to get WADL
-    # generation working.  Individual attributes must set their version to
-    # "devel".
-    export_as_webservice_entry(as_of="beta")
-
     id = Int(title=_("ID"), required=True, readonly=True)
 
     date_requested = exported(Datetime(
@@ -839,22 +838,20 @@ class ISnapAdminAttributes(Interface):
             "Resources hosted on Launchpad itself are always allowed.")))
 
 
+# XXX cjwatson 2015-07-17 bug=760849: "beta" is a lie to get WADL
+# generation working.  Individual attributes must set their version to
+# "devel".
+@exported_as_webservice_entry(as_of="beta")
 class ISnap(
     ISnapView, ISnapEdit, ISnapEditableAttributes, ISnapAdminAttributes,
     IPrivacy):
     """A buildable snap package."""
 
-    # XXX cjwatson 2015-07-17 bug=760849: "beta" is a lie to get WADL
-    # generation working.  Individual attributes must set their version to
-    # "devel".
-    export_as_webservice_entry(as_of="beta")
-
 
+@exported_as_webservice_collection(ISnap)
 class ISnapSet(Interface):
     """A utility to create and access snap packages."""
 
-    export_as_webservice_collection(ISnap)
-
     @call_with(registrant=REQUEST_USER)
     @operation_parameters(
         processors=List(
diff --git a/lib/lp/snappy/interfaces/snapbase.py b/lib/lp/snappy/interfaces/snapbase.py
index 9d3c586..5a3a97c 100644
--- a/lib/lp/snappy/interfaces/snapbase.py
+++ b/lib/lp/snappy/interfaces/snapbase.py
@@ -17,13 +17,13 @@ from lazr.restful.declarations import (
     call_with,
     collection_default_content,
     error_status,
-    export_as_webservice_collection,
-    export_as_webservice_entry,
     export_destructor_operation,
     export_factory_operation,
     export_read_operation,
     export_write_operation,
     exported,
+    exported_as_webservice_collection,
+    exported_as_webservice_entry,
     operation_for_version,
     operation_parameters,
     operation_returns_entry,
@@ -137,14 +137,13 @@ class ISnapBaseEdit(Interface):
         """
 
 
+# XXX cjwatson 2019-01-28 bug=760849: "beta" is a lie to get WADL
+# generation working.  Individual attributes must set their version to
+# "devel".
+@exported_as_webservice_entry(as_of="beta")
 class ISnapBase(ISnapBaseView, ISnapBaseEditableAttributes):
     """A base for snaps."""
 
-    # XXX cjwatson 2019-01-28 bug=760849: "beta" is a lie to get WADL
-    # generation working.  Individual attributes must set their version to
-    # "devel".
-    export_as_webservice_entry(as_of="beta")
-
 
 class ISnapBaseSetEdit(Interface):
     """`ISnapBaseSet` methods that require launchpad.Edit permission."""
@@ -171,11 +170,10 @@ class ISnapBaseSetEdit(Interface):
         """
 
 
+@exported_as_webservice_collection(ISnapBase)
 class ISnapBaseSet(ISnapBaseSetEdit):
     """Interface representing the set of bases for snaps."""
 
-    export_as_webservice_collection(ISnapBase)
-
     def __iter__():
         """Iterate over `ISnapBase`s."""
 
diff --git a/lib/lp/snappy/interfaces/snapbuild.py b/lib/lp/snappy/interfaces/snapbuild.py
index 3531f2d..c452092 100644
--- a/lib/lp/snappy/interfaces/snapbuild.py
+++ b/lib/lp/snappy/interfaces/snapbuild.py
@@ -22,10 +22,10 @@ from lazr.enum import (
     )
 from lazr.restful.declarations import (
     error_status,
-    export_as_webservice_entry,
     export_read_operation,
     export_write_operation,
     exported,
+    exported_as_webservice_entry,
     operation_for_version,
     operation_parameters,
     )
@@ -329,14 +329,13 @@ class ISnapBuildAdmin(Interface):
         """Change the build's score."""
 
 
+# XXX cjwatson 2014-05-06 bug=760849: "beta" is a lie to get WADL
+# generation working.  Individual attributes must set their version to
+# "devel".
+@exported_as_webservice_entry(as_of="beta")
 class ISnapBuild(ISnapBuildView, ISnapBuildEdit, ISnapBuildAdmin):
     """Build information for snap package builds."""
 
-    # XXX cjwatson 2014-05-06 bug=760849: "beta" is a lie to get WADL
-    # generation working.  Individual attributes must set their version to
-    # "devel".
-    export_as_webservice_entry(as_of="beta")
-
 
 class ISnapBuildSet(ISpecificBuildFarmJobSource):
     """Utility for `ISnapBuild`."""
diff --git a/lib/lp/snappy/interfaces/snappyseries.py b/lib/lp/snappy/interfaces/snappyseries.py
index 088806c..c8710b7 100644
--- a/lib/lp/snappy/interfaces/snappyseries.py
+++ b/lib/lp/snappy/interfaces/snappyseries.py
@@ -17,11 +17,11 @@ __all__ = [
 from lazr.restful.declarations import (
     call_with,
     collection_default_content,
-    export_as_webservice_collection,
-    export_as_webservice_entry,
     export_factory_operation,
     export_read_operation,
     exported,
+    exported_as_webservice_collection,
+    exported_as_webservice_entry,
     operation_for_version,
     operation_parameters,
     operation_returns_entry,
@@ -125,14 +125,13 @@ class ISnappySeriesEditableAttributes(Interface):
             "supported for this snappy series.")))
 
 
+# XXX cjwatson 2016-04-13 bug=760849: "beta" is a lie to get WADL
+# generation working.  Individual attributes must set their version to
+# "devel".
+@exported_as_webservice_entry(plural_name="snappy_serieses", as_of="beta")
 class ISnappySeries(ISnappySeriesView, ISnappySeriesEditableAttributes):
     """A series for snap packages in the store."""
 
-    # XXX cjwatson 2016-04-13 bug=760849: "beta" is a lie to get WADL
-    # generation working.  Individual attributes must set their version to
-    # "devel".
-    export_as_webservice_entry(plural_name="snappy_serieses", as_of="beta")
-
 
 class ISnappyDistroSeries(Interface):
     """A snappy/distro series link."""
@@ -162,11 +161,10 @@ class ISnappySeriesSetEdit(Interface):
         """Create an `ISnappySeries`."""
 
 
+@exported_as_webservice_collection(ISnappySeries)
 class ISnappySeriesSet(ISnappySeriesSetEdit):
     """Interface representing the set of snappy series."""
 
-    export_as_webservice_collection(ISnappySeries)
-
     def __iter__():
         """Iterate over `ISnappySeries`."""
 
diff --git a/lib/lp/soyuz/interfaces/archive.py b/lib/lp/soyuz/interfaces/archive.py
index 0e82e27..e28f08b 100644
--- a/lib/lp/soyuz/interfaces/archive.py
+++ b/lib/lp/soyuz/interfaces/archive.py
@@ -60,14 +60,14 @@ from lazr.restful.declarations import (
     call_with,
     collection_default_content,
     error_status,
-    export_as_webservice_collection,
-    export_as_webservice_entry,
     export_destructor_operation,
     export_factory_operation,
     export_operation_as,
     export_read_operation,
     export_write_operation,
     exported,
+    exported_as_webservice_collection,
+    exported_as_webservice_entry,
     operation_for_version,
     operation_parameters,
     operation_returns_collection_of,
@@ -2282,11 +2282,11 @@ class IArchiveRestricted(Interface):
             "with a higher score will build sooner.")))
 
 
+@exported_as_webservice_entry()
 class IArchive(IArchivePublic, IArchiveAppend, IArchiveEdit, IArchiveDelete,
                IArchiveSubscriberView, IArchiveView, IArchiveAdmin,
                IArchiveRestricted):
     """Main Archive interface."""
-    export_as_webservice_entry()
 
 
 class IPPA(IArchive):
@@ -2304,11 +2304,10 @@ class IArchiveEditDependenciesForm(Interface):
         title=_('Add PPA dependency'), required=False, vocabulary='PPA')
 
 
+@exported_as_webservice_collection(IArchive)
 class IArchiveSet(Interface):
     """Interface for ArchiveSet"""
 
-    export_as_webservice_collection(IArchive)
-
     title = Attribute('Title')
 
     @collection_default_content()
diff --git a/lib/lp/soyuz/interfaces/archivedependency.py b/lib/lp/soyuz/interfaces/archivedependency.py
index 9e6b01b..b6f7092 100644
--- a/lib/lp/soyuz/interfaces/archivedependency.py
+++ b/lib/lp/soyuz/interfaces/archivedependency.py
@@ -10,8 +10,8 @@ __all__ = [
     ]
 
 from lazr.restful.declarations import (
-    export_as_webservice_entry,
     exported,
+    exported_as_webservice_entry,
     )
 from lazr.restful.fields import Reference
 from zope.interface import Interface
@@ -27,9 +27,9 @@ from lp.registry.interfaces.pocket import PackagePublishingPocket
 from lp.soyuz.interfaces.archive import IArchive
 
 
+@exported_as_webservice_entry(publish_web_link=False)
 class IArchiveDependency(Interface):
     """ArchiveDependency interface."""
-    export_as_webservice_entry(publish_web_link=False)
 
     id = Int(title=_("The archive ID."), readonly=True)
 
diff --git a/lib/lp/soyuz/interfaces/archivepermission.py b/lib/lp/soyuz/interfaces/archivepermission.py
index 88481eb..390343b 100644
--- a/lib/lp/soyuz/interfaces/archivepermission.py
+++ b/lib/lp/soyuz/interfaces/archivepermission.py
@@ -13,8 +13,8 @@ __all__ = [
     ]
 
 from lazr.restful.declarations import (
-    export_as_webservice_entry,
     exported,
+    exported_as_webservice_entry,
     )
 from lazr.restful.fields import Reference
 from zope.interface import (
@@ -39,9 +39,9 @@ from lp.soyuz.interfaces.component import IComponent
 from lp.soyuz.interfaces.packageset import IPackageset
 
 
+@exported_as_webservice_entry(publish_web_link=False)
 class IArchivePermission(Interface):
     """The interface for `ArchivePermission`."""
-    export_as_webservice_entry(publish_web_link=False)
 
     id = Attribute("The archive permission ID.")
 
diff --git a/lib/lp/soyuz/interfaces/archivesubscriber.py b/lib/lp/soyuz/interfaces/archivesubscriber.py
index a9bc67b..493859e 100644
--- a/lib/lp/soyuz/interfaces/archivesubscriber.py
+++ b/lib/lp/soyuz/interfaces/archivesubscriber.py
@@ -14,9 +14,9 @@ __all__ = [
 
 from lazr.restful.declarations import (
     call_with,
-    export_as_webservice_entry,
     export_write_operation,
     exported,
+    exported_as_webservice_entry,
     operation_for_version,
     REQUEST_USER,
     )
@@ -122,9 +122,9 @@ class IArchiveSubscriberEdit(Interface):
         """
 
 
+@exported_as_webservice_entry()
 class IArchiveSubscriber(IArchiveSubscriberView, IArchiveSubscriberEdit):
     """An interface for archive subscribers."""
-    export_as_webservice_entry()
 
 
 class IArchiveSubscriberSetView(Interface):
diff --git a/lib/lp/soyuz/interfaces/binarypackagebuild.py b/lib/lp/soyuz/interfaces/binarypackagebuild.py
index d811c6c..cc43bcb 100644
--- a/lib/lp/soyuz/interfaces/binarypackagebuild.py
+++ b/lib/lp/soyuz/interfaces/binarypackagebuild.py
@@ -20,10 +20,10 @@ from lazr.enum import (
     )
 from lazr.restful.declarations import (
     error_status,
-    export_as_webservice_entry,
     export_read_operation,
     export_write_operation,
     exported,
+    exported_as_webservice_entry,
     operation_for_version,
     operation_parameters,
     operation_returns_entry,
@@ -307,11 +307,11 @@ class IBinaryPackageBuildAdmin(Interface):
         """Change the build's score."""
 
 
+@exported_as_webservice_entry(singular_name='build', plural_name='builds')
 class IBinaryPackageBuild(
     IBinaryPackageBuildView, IBinaryPackageBuildEdit,
     IBinaryPackageBuildRestricted, IBinaryPackageBuildAdmin):
     """A Build interface"""
-    export_as_webservice_entry(singular_name='build', plural_name='builds')
 
 
 class BuildSetStatus(EnumeratedType):
diff --git a/lib/lp/soyuz/interfaces/binarypackagerelease.py b/lib/lp/soyuz/interfaces/binarypackagerelease.py
index c69a23d..2ee397e 100644
--- a/lib/lp/soyuz/interfaces/binarypackagerelease.py
+++ b/lib/lp/soyuz/interfaces/binarypackagerelease.py
@@ -11,8 +11,8 @@ __all__ = [
     ]
 
 from lazr.restful.declarations import (
-    export_as_webservice_entry,
     exported,
+    exported_as_webservice_entry,
     )
 from lazr.restful.fields import (
     Reference,
@@ -104,9 +104,9 @@ class IBinaryPackageRelease(Interface):
         """
 
 
+@exported_as_webservice_entry()
 class IBinaryPackageReleaseDownloadCount(Interface):
     """Daily download count of a binary package release in an archive."""
-    export_as_webservice_entry()
 
     id = Int(title=_('ID'), required=True, readonly=True)
     archive = exported(Reference(
diff --git a/lib/lp/soyuz/interfaces/distroarchseries.py b/lib/lp/soyuz/interfaces/distroarchseries.py
index 862c646..d287840 100644
--- a/lib/lp/soyuz/interfaces/distroarchseries.py
+++ b/lib/lp/soyuz/interfaces/distroarchseries.py
@@ -16,10 +16,10 @@ __all__ = [
 from lazr.restful.declarations import (
     call_with,
     error_status,
-    export_as_webservice_entry,
     export_read_operation,
     export_write_operation,
     exported,
+    exported_as_webservice_entry,
     operation_for_version,
     operation_parameters,
     operation_returns_entry,
@@ -341,9 +341,9 @@ class IDistroArchSeriesModerate(Interface):
         """
 
 
+@exported_as_webservice_entry()
 class IDistroArchSeries(IDistroArchSeriesPublic, IDistroArchSeriesModerate):
     """An architecture for a distroseries."""
-    export_as_webservice_entry()
 
 
 class IPocketChroot(Interface):
diff --git a/lib/lp/soyuz/interfaces/distroarchseriesfilter.py b/lib/lp/soyuz/interfaces/distroarchseriesfilter.py
index 1cc324a..106bb97 100644
--- a/lib/lp/soyuz/interfaces/distroarchseriesfilter.py
+++ b/lib/lp/soyuz/interfaces/distroarchseriesfilter.py
@@ -13,8 +13,8 @@ __all__ = [
     ]
 
 from lazr.restful.declarations import (
-    export_as_webservice_entry,
     exported,
+    exported_as_webservice_entry,
     )
 from lazr.restful.fields import Reference
 from zope.interface import Interface
@@ -96,6 +96,10 @@ class IDistroArchSeriesFilterEdit(Interface):
         """Delete this filter."""
 
 
+# XXX cjwatson 2019-10-04 bug=760849: "beta" is a lie to get WADL
+# generation working.  Individual attributes must set their version to
+# "devel".
+@exported_as_webservice_entry(as_of="beta")
 class IDistroArchSeriesFilter(
         IDistroArchSeriesFilterView, IDistroArchSeriesFilterEdit):
     """A filter for packages to be included in or excluded from a DAS.
@@ -107,10 +111,6 @@ class IDistroArchSeriesFilter(
     exclude some packages ("this architecture can't handle some packages so
     we want to make them go away centrally").
     """
-    # XXX cjwatson 2019-10-04 bug=760849: "beta" is a lie to get WADL
-    # generation working.  Individual attributes must set their version to
-    # "devel".
-    export_as_webservice_entry(as_of="beta")
 
 
 class IDistroArchSeriesFilterSet(Interface):
diff --git a/lib/lp/soyuz/interfaces/livefs.py b/lib/lp/soyuz/interfaces/livefs.py
index 11a7ead..b9503b2 100644
--- a/lib/lp/soyuz/interfaces/livefs.py
+++ b/lib/lp/soyuz/interfaces/livefs.py
@@ -27,12 +27,12 @@ from lazr.restful.declarations import (
     call_with,
     collection_default_content,
     error_status,
-    export_as_webservice_collection,
-    export_as_webservice_entry,
     export_destructor_operation,
     export_factory_operation,
     export_read_operation,
     exported,
+    exported_as_webservice_collection,
+    exported_as_webservice_entry,
     operation_for_version,
     operation_parameters,
     operation_returns_entry,
@@ -284,23 +284,21 @@ class ILiveFSAdminAttributes(Interface):
             "Only build this live filesystem image on virtual builders.")))
 
 
+# XXX cjwatson 2014-05-06 bug=760849: "beta" is a lie to get WADL
+# generation working.  Individual attributes must set their version to
+# "devel".
+@exported_as_webservice_entry(
+    singular_name="livefs", plural_name="livefses", as_of="beta")
 class ILiveFS(
     ILiveFSView, ILiveFSEdit, ILiveFSEditableAttributes,
     ILiveFSModerateAttributes, ILiveFSAdminAttributes):
     """A buildable live filesystem image."""
 
-    # XXX cjwatson 2014-05-06 bug=760849: "beta" is a lie to get WADL
-    # generation working.  Individual attributes must set their version to
-    # "devel".
-    export_as_webservice_entry(
-        singular_name="livefs", plural_name="livefses", as_of="beta")
-
 
+@exported_as_webservice_collection(ILiveFS)
 class ILiveFSSet(Interface):
     """A utility to create and access live filesystems."""
 
-    export_as_webservice_collection(ILiveFS)
-
     @call_with(registrant=REQUEST_USER)
     @export_factory_operation(
         ILiveFS, ["owner", "distro_series", "name", "metadata"])
diff --git a/lib/lp/soyuz/interfaces/livefsbuild.py b/lib/lp/soyuz/interfaces/livefsbuild.py
index c32d44d..8d8f888 100644
--- a/lib/lp/soyuz/interfaces/livefsbuild.py
+++ b/lib/lp/soyuz/interfaces/livefsbuild.py
@@ -12,10 +12,10 @@ __all__ = [
     ]
 
 from lazr.restful.declarations import (
-    export_as_webservice_entry,
     export_read_operation,
     export_write_operation,
     exported,
+    exported_as_webservice_entry,
     operation_for_version,
     operation_parameters,
     )
@@ -183,14 +183,13 @@ class ILiveFSBuildAdmin(Interface):
         """Change the build's score."""
 
 
+# XXX cjwatson 2014-05-06 bug=760849: "beta" is a lie to get WADL
+# generation working.  Individual attributes must set their version to
+# "devel".
+@exported_as_webservice_entry(singular_name="livefs_build", as_of="beta")
 class ILiveFSBuild(ILiveFSBuildView, ILiveFSBuildEdit, ILiveFSBuildAdmin):
     """Build information for live filesystem builds."""
 
-    # XXX cjwatson 2014-05-06 bug=760849: "beta" is a lie to get WADL
-    # generation working.  Individual attributes must set their version to
-    # "devel".
-    export_as_webservice_entry(singular_name="livefs_build", as_of="beta")
-
 
 class ILiveFSBuildSet(ISpecificBuildFarmJobSource):
     """Utility for `ILiveFSBuild`."""
diff --git a/lib/lp/soyuz/interfaces/packageset.py b/lib/lp/soyuz/interfaces/packageset.py
index 6660532..b7d10d0 100644
--- a/lib/lp/soyuz/interfaces/packageset.py
+++ b/lib/lp/soyuz/interfaces/packageset.py
@@ -15,13 +15,13 @@ __all__ = [
 from lazr.restful.declarations import (
     collection_default_content,
     error_status,
-    export_as_webservice_collection,
-    export_as_webservice_entry,
     export_destructor_operation,
     export_factory_operation,
     export_read_operation,
     export_write_operation,
     exported,
+    exported_as_webservice_collection,
+    exported_as_webservice_entry,
     operation_for_version,
     operation_parameters,
     operation_returns_collection_of,
@@ -58,9 +58,9 @@ class DuplicatePackagesetName(Exception):
     """Raised for packagesets with the same name and distroseries."""
 
 
+@exported_as_webservice_entry(publish_web_link=False)
 class IPackagesetViewOnly(IHasOwner):
     """A read-only interface for package sets."""
-    export_as_webservice_entry(publish_web_link=False)
 
     id = exported(Int(title=_('ID'), required=True, readonly=True))
 
@@ -251,9 +251,9 @@ class IPackagesetViewOnly(IHasOwner):
         """
 
 
+@exported_as_webservice_entry(publish_web_link=False)
 class IPackagesetEdit(Interface):
     """A writeable interface for package sets."""
-    export_as_webservice_entry(publish_web_link=False)
 
     def add(data):
         """Add source package names or other package sets to this one.
@@ -361,18 +361,18 @@ class IPackagesetEdit(Interface):
         """Delete the package set."""
 
 
+@exported_as_webservice_entry(publish_web_link=False)
 class IPackagesetRestricted(Interface):
     """A writeable interface for restricted attributes of package sets."""
-    export_as_webservice_entry(publish_web_link=False)
 
     relative_build_score = exported(Int(
         title=_("Build score"), required=True, readonly=False,
         description=_("Build score bonus for packages in this package set.")))
 
 
+@exported_as_webservice_entry(publish_web_link=False)
 class IPackageset(IPackagesetViewOnly, IPackagesetEdit, IPackagesetRestricted):
     """An interface for package sets."""
-    export_as_webservice_entry(publish_web_link=False)
 
 
 class IPackagesetSetEdit(Interface):
@@ -413,9 +413,9 @@ class IPackagesetSetEdit(Interface):
         """
 
 
+@exported_as_webservice_collection(IPackageset)
 class IPackagesetSet(IPackagesetSetEdit):
     """An interface for multiple package sets."""
-    export_as_webservice_collection(IPackageset)
 
     @operation_parameters(
         name=copy_field(IPackageset['name']),
diff --git a/lib/lp/soyuz/interfaces/publishing.py b/lib/lp/soyuz/interfaces/publishing.py
index 6945260..4443284 100644
--- a/lib/lp/soyuz/interfaces/publishing.py
+++ b/lib/lp/soyuz/interfaces/publishing.py
@@ -28,11 +28,11 @@ __all__ = [
 from lazr.restful.declarations import (
     call_with,
     error_status,
-    export_as_webservice_entry,
     export_operation_as,
     export_read_operation,
     export_write_operation,
     exported,
+    exported_as_webservice_entry,
     operation_for_version,
     operation_parameters,
     operation_returns_collection_of,
@@ -580,10 +580,10 @@ class ISourcePackagePublishingHistoryEdit(IPublishingEdit):
         """
 
 
+@exported_as_webservice_entry(publish_web_link=False)
 class ISourcePackagePublishingHistory(ISourcePackagePublishingHistoryPublic,
                                       ISourcePackagePublishingHistoryEdit):
     """A source package publishing history record."""
-    export_as_webservice_entry(publish_web_link=False)
 
 
 #
@@ -880,10 +880,10 @@ class IBinaryPackagePublishingHistoryEdit(IPublishingEdit):
         """
 
 
+@exported_as_webservice_entry(publish_web_link=False)
 class IBinaryPackagePublishingHistory(IBinaryPackagePublishingHistoryPublic,
                                       IBinaryPackagePublishingHistoryEdit):
     """A binary package publishing record."""
-    export_as_webservice_entry(publish_web_link=False)
 
 
 class IPublishingSet(Interface):
diff --git a/lib/lp/soyuz/interfaces/queue.py b/lib/lp/soyuz/interfaces/queue.py
index 5a1679f..57ab31c 100644
--- a/lib/lp/soyuz/interfaces/queue.py
+++ b/lib/lp/soyuz/interfaces/queue.py
@@ -28,10 +28,10 @@ from lazr.lifecycle.snapshot import doNotSnapshot
 from lazr.restful.declarations import (
     call_with,
     error_status,
-    export_as_webservice_entry,
     export_read_operation,
     export_write_operation,
     exported,
+    exported_as_webservice_entry,
     operation_for_version,
     operation_parameters,
     REQUEST_USER,
@@ -117,11 +117,10 @@ class IPackageUploadQueue(Interface):
     """
 
 
+@exported_as_webservice_entry(publish_web_link=True, as_of="devel")
 class IPackageUploadLog(Interface):
     """A log entry recording a change in a package upload's status."""
 
-    export_as_webservice_entry(publish_web_link=True, as_of="devel")
-
     id = Int(title=_('ID'), required=True, readonly=True)
 
     package_upload = exported(
@@ -155,11 +154,10 @@ class IPackageUploadLog(Interface):
             required=False, readonly=True))
 
 
+@exported_as_webservice_entry(publish_web_link=False)
 class IPackageUpload(Interface):
     """A Queue item for the archive uploader."""
 
-    export_as_webservice_entry(publish_web_link=False)
-
     id = exported(
         Int(
             title=_("ID"), required=True, readonly=True,
diff --git a/lib/lp/translations/interfaces/hastranslationimports.py b/lib/lp/translations/interfaces/hastranslationimports.py
index 9a1ef68..827c05a 100644
--- a/lib/lp/translations/interfaces/hastranslationimports.py
+++ b/lib/lp/translations/interfaces/hastranslationimports.py
@@ -9,8 +9,8 @@ __all__ = [
     ]
 
 from lazr.restful.declarations import (
-    export_as_webservice_entry,
     export_read_operation,
+    exported_as_webservice_entry,
     operation_for_version,
     operation_parameters,
     operation_returns_collection_of,
@@ -25,15 +25,15 @@ from lp import _
 from lp.translations.enums import RosettaImportStatus
 
 
+@exported_as_webservice_entry(
+    singular_name='object_with_translation_imports',
+    plural_name='objects_with_translation_imports')
 class IHasTranslationImports(Interface):
     """An entity that has a translation import queue.
 
     Examples include `ProductSeries`, `SourcePackage`, `DistroSeries`,
     and `Person`.
     """
-    export_as_webservice_entry(
-        singular_name='object_with_translation_imports',
-        plural_name='objects_with_translation_imports')
 
     def getFirstEntryToImport():
         """Return the first entry of the queue ready to be imported."""
diff --git a/lib/lp/translations/interfaces/pofile.py b/lib/lp/translations/interfaces/pofile.py
index 9bc0f74..c75b103 100644
--- a/lib/lp/translations/interfaces/pofile.py
+++ b/lib/lp/translations/interfaces/pofile.py
@@ -10,8 +10,8 @@ __all__ = [
     ]
 
 from lazr.restful.declarations import (
-    export_as_webservice_entry,
     exported,
+    exported_as_webservice_entry,
     )
 from zope.component import getUtility
 from zope.interface import (
@@ -46,13 +46,12 @@ from lp.translations.interfaces.rosettastats import IRosettaStats
 from lp.translations.interfaces.translationsperson import ITranslationsPerson
 
 
+@exported_as_webservice_entry(
+    singular_name="translation_file",
+    plural_name="translation_files")
 class IPOFile(IRosettaStats):
     """A translation file."""
 
-    export_as_webservice_entry(
-        singular_name="translation_file",
-        plural_name="translation_files")
-
     id = exported(Int(
         title=_('The translation file id.'), required=True, readonly=True))
 
diff --git a/lib/lp/translations/interfaces/potemplate.py b/lib/lp/translations/interfaces/potemplate.py
index 30fe438..4a630ba 100644
--- a/lib/lp/translations/interfaces/potemplate.py
+++ b/lib/lp/translations/interfaces/potemplate.py
@@ -2,8 +2,8 @@
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 from lazr.restful.declarations import (
-    export_as_webservice_entry,
     exported,
+    exported_as_webservice_entry,
     )
 from lazr.restful.fields import (
     CollectionField,
@@ -52,13 +52,12 @@ class LanguageNotFound(NotFoundError):
     """Raised when a a language does not exist in the database."""
 
 
+@exported_as_webservice_entry(
+    singular_name='translation_template',
+    plural_name='translation_templates')
 class IPOTemplate(IRosettaStats):
     """A translation template."""
 
-    export_as_webservice_entry(
-        singular_name='translation_template',
-        plural_name='translation_templates')
-
     id = exported(Int(
         title=u"The translation template id.",
         required=True, readonly=True))
diff --git a/lib/lp/translations/interfaces/translationgroup.py b/lib/lp/translations/interfaces/translationgroup.py
index e2ef711..303ac4f 100644
--- a/lib/lp/translations/interfaces/translationgroup.py
+++ b/lib/lp/translations/interfaces/translationgroup.py
@@ -13,10 +13,10 @@ __all__ = [
 
 from lazr.restful.declarations import (
     collection_default_content,
-    export_as_webservice_collection,
-    export_as_webservice_entry,
     export_read_operation,
     exported,
+    exported_as_webservice_collection,
+    exported_as_webservice_entry,
     operation_for_version,
     operation_parameters,
     operation_returns_entry,
@@ -43,12 +43,11 @@ from lp.services.fields import (
 from lp.translations.enums import TranslationPermission
 
 
+@exported_as_webservice_entry(
+    singular_name='translation_group', plural_name='translation_groups')
 class ITranslationGroup(IHasOwner):
     """A TranslationGroup."""
 
-    export_as_webservice_entry(
-        singular_name='translation_group', plural_name='translation_groups')
-
     id = Int(
             title=_('Translation Group ID'), required=True, readonly=True,
             )
@@ -161,11 +160,10 @@ class ITranslationGroup(IHasOwner):
         """
 
 
+@exported_as_webservice_collection(ITranslationGroup)
 class ITranslationGroupSet(Interface):
     """A container for translation groups."""
 
-    export_as_webservice_collection(ITranslationGroup)
-
     title = Attribute('Title')
 
     @operation_parameters(
diff --git a/lib/lp/translations/interfaces/translationimportqueue.py b/lib/lp/translations/interfaces/translationimportqueue.py
index bea463e..b8c20d3 100644
--- a/lib/lp/translations/interfaces/translationimportqueue.py
+++ b/lib/lp/translations/interfaces/translationimportqueue.py
@@ -13,11 +13,11 @@ from lazr.restful.declarations import (
     call_with,
     collection_default_content,
     error_status,
-    export_as_webservice_collection,
-    export_as_webservice_entry,
     export_read_operation,
     export_write_operation,
     exported,
+    exported_as_webservice_collection,
+    exported_as_webservice_entry,
     operation_parameters,
     operation_returns_collection_of,
     operation_returns_entry,
@@ -120,11 +120,11 @@ class SpecialTranslationImportTargetFilter(DBEnumeratedType):
         """)
 
 
+@exported_as_webservice_entry(
+    singular_name='translation_import_queue_entry',
+    plural_name='translation_import_queue_entries')
 class ITranslationImportQueueEntry(Interface):
     """An entry of the Translation Import Queue."""
-    export_as_webservice_entry(
-        singular_name='translation_import_queue_entry',
-        plural_name='translation_import_queue_entries')
 
     id = exported(Int(title=_('The entry ID'), required=True, readonly=True))
 
@@ -290,9 +290,9 @@ class ITranslationImportQueueEntry(Interface):
         """
 
 
+@exported_as_webservice_collection(ITranslationImportQueueEntry)
 class ITranslationImportQueue(Interface):
     """A set of files to be imported into Rosetta."""
-    export_as_webservice_collection(ITranslationImportQueueEntry)
 
     def __iter__():
         """Iterate over all entries in the queue."""