Hi Thiago! Nice feature! Simple but very useful. Thanks you.
Just a thought. What about multiple contributions to the ComponentReplacer for the same page/component or mixin ? In a next improvement, it could be very handy to allow some kind of ordered configuration. Nourredine. 2014-06-16 3:18 GMT+02:00 <thiag...@apache.org>: > Repository: tapestry-5 > Updated Branches: > refs/heads/master 9cd156f37 -> e6a83e031 > > > TAP5-1611 : out-of-the-box way in Tapestry for replacing components > > > Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo > Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/e6a83e03 > Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/e6a83e03 > Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/e6a83e03 > > Branch: refs/heads/master > Commit: e6a83e031ad65eac99614f108392d06a8ff6c8f9 > Parents: 9cd156f > Author: Thiago H. de Paula Figueiredo <thiag...@apache.org> > Authored: Sun Jun 15 22:17:47 2014 -0300 > Committer: Thiago H. de Paula Figueiredo <thiag...@apache.org> > Committed: Sun Jun 15 22:17:47 2014 -0300 > > ---------------------------------------------------------------------- > .../internal/ComponentReplacerImpl.java | 89 ++++++++++++++++++++ > .../tapestry5/modules/TapestryModule.java | 32 +++++++ > .../tapestry5/services/ComponentReplacer.java | 51 +++++++++++ > tapestry-core/src/test/app3/Login.tml | 6 ++ > tapestry-core/src/test/app3/OverridePage.tml | 12 +++ > .../src/test/app3/OverridePageAtComponent.tml | 12 +++ > tapestry-core/src/test/app3/OverridenPage.tml | 8 ++ > .../app3/AdditionalIntegrationTests.java | 21 +++++ > .../app3/components/OverrideComponent.java | 24 ++++++ > .../app3/components/OverridenComponent.java | 24 ++++++ > .../integration/app3/mixins/OverrideMixin.java | 32 +++++++ > .../integration/app3/mixins/OverridenMixin.java | 30 +++++++ > .../integration/app3/pages/OverridePage.java | 18 ++++ > .../app3/pages/OverridePageAtComponent.java | 35 ++++++++ > .../integration/app3/pages/OverridenPage.java | 18 ++++ > .../integration/app3/services/AppModule.java | 16 +++- > 16 files changed, 427 insertions(+), 1 deletion(-) > ---------------------------------------------------------------------- > > > > http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/e6a83e03/tapestry-core/src/main/java/org/apache/tapestry5/internal/ComponentReplacerImpl.java > ---------------------------------------------------------------------- > diff --git > a/tapestry-core/src/main/java/org/apache/tapestry5/internal/ComponentReplacerImpl.java > b/tapestry-core/src/main/java/org/apache/tapestry5/internal/ComponentReplacerImpl.java > new file mode 100644 > index 0000000..8d7fc75 > --- /dev/null > +++ > b/tapestry-core/src/main/java/org/apache/tapestry5/internal/ComponentReplacerImpl.java > @@ -0,0 +1,89 @@ > +// Copyright 2014 The Apache Software Foundation > +// > +// Licensed under the Apache License, Version 2.0 (the "License"); > +// you may not use this file except in compliance with the License. > +// You may obtain a copy of the License at > +// > +// http://www.apache.org/licenses/LICENSE-2.0 > +// > +// Unless required by applicable law or agreed to in writing, software > +// distributed under the License is distributed on an "AS IS" BASIS, > +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or > implied. > +// See the License for the specific language governing permissions and > +// limitations under the License. > +package org.apache.tapestry5.internal; > + > +import java.util.ArrayList; > +import java.util.Collections; > +import java.util.HashMap; > +import java.util.List; > +import java.util.Map; > +import java.util.Map.Entry; > +import java.util.Set; > + > +import org.apache.tapestry5.ioc.util.CaseInsensitiveMap; > +import org.apache.tapestry5.services.ComponentReplacer; > +import org.slf4j.Logger; > + > +public class ComponentReplacerImpl implements ComponentReplacer > +{ > + > + final Logger logger; > + final private Map<Class, Class> replacements; > + final private Map<String, Class> nameToClass; > + > + @SuppressWarnings("rawtypes") > + public ComponentReplacerImpl(Map<Class, Class> contributions, Logger > logger) > + { > + > + this.logger = logger; > + this.replacements = Collections.unmodifiableMap(contributions); > + Map<String, Class> nameToClass = new HashMap<String, Class>(); > + > + int maxLength = 0; > + > + for (Class<?> clasz : contributions.keySet()) > + { > + > + final String name = clasz.getName(); > + if (name.length() > maxLength) { > + maxLength = name.length(); > + } > + nameToClass.put(name, contributions.get(clasz)); > + > + } > + > + this.nameToClass = Collections.unmodifiableMap(nameToClass); > + > + if (replacements.size() > 0 && logger.isInfoEnabled()) > + { > + > + StringBuilder builder = new StringBuilder(1000); > + final String format = "%" + maxLength + "s: %s\n"; > + builder.append("Component replacements (including components, > pages and mixins):\n"); > + List<String> names = new > ArrayList<String>(nameToClass.keySet()); > + Collections.sort(names); > + > + for (String name : names) { > + builder.append(String.format(format, name, > nameToClass.get(name).getName())); > + } > + > + logger.info(builder.toString()); > + > + } > + > + } > + > + @Override > + public Map<Class, Class> getReplacements() > + { > + return replacements; > + } > + > + @Override > + public Class getReplacement(String className) > + { > + return nameToClass.get(className); > + } > + > +} > > > http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/e6a83e03/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java > ---------------------------------------------------------------------- > diff --git > a/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java > b/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java > index 63c114b..1a08540 100644 > --- > a/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java > +++ > b/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java > @@ -65,7 +65,9 @@ import org.apache.tapestry5.ioc.util.AvailableValues; > import org.apache.tapestry5.ioc.util.StrategyRegistry; > import org.apache.tapestry5.json.JSONArray; > import org.apache.tapestry5.json.JSONObject; > +import org.apache.tapestry5.plastic.MethodAdvice; > import org.apache.tapestry5.plastic.MethodDescription; > +import org.apache.tapestry5.plastic.MethodInvocation; > import org.apache.tapestry5.runtime.Component; > import org.apache.tapestry5.runtime.ComponentResourcesAware; > import org.apache.tapestry5.runtime.RenderCommand; > @@ -95,6 +97,7 @@ import org.slf4j.Logger; > import javax.servlet.ServletContext; > import javax.servlet.http.HttpServletRequest; > import javax.servlet.http.HttpServletResponse; > + > import java.io.IOException; > import java.lang.annotation.Annotation; > import java.math.BigDecimal; > @@ -372,6 +375,7 @@ public final class TapestryModule > binder.bind(DateUtilities.class, DateUtilitiesImpl.class); > binder.bind(PartialTemplateRenderer.class, > PartialTemplateRendererImpl.class); > > binder.bind(org.apache.tapestry5.services.exceptions.ExceptionReporter.class, > ExceptionReporterImpl.class); > + binder.bind(ComponentReplacer.class, > ComponentReplacerImpl.class).eagerLoad(); > } > > // > ======================================================================== > @@ -2660,4 +2664,32 @@ public final class TapestryModule > { > return strategyBuilder.build(ValueLabelProvider.class, > configuration); > } > + > + @Advise(serviceInterface = ComponentInstantiatorSource.class) > + public static void componentReplacer(MethodAdviceReceiver > methodAdviceReceiver, > + final ComponentReplacer componentReplacer) throws > NoSuchMethodException, SecurityException { > + > + if (componentReplacer.getReplacements().size() > 0) { > + > + MethodAdvice advice = new MethodAdvice() > + { > + @Override > + public void advise(MethodInvocation invocation) > + { > + String className = (String) > invocation.getParameter(0); > + final Class<?> replacement = > componentReplacer.getReplacement(className); > + if (replacement != null) > + { > + invocation.setParameter(0, replacement.getName()); > + } > + invocation.proceed(); > + } > + }; > + > + methodAdviceReceiver.adviseMethod( > + > ComponentInstantiatorSource.class.getMethod("getInstantiator", > String.class), advice); > + > + } > + } > + > } > > > http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/e6a83e03/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentReplacer.java > ---------------------------------------------------------------------- > diff --git > a/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentReplacer.java > b/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentReplacer.java > new file mode 100644 > index 0000000..375a8c6 > --- /dev/null > +++ > b/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentReplacer.java > @@ -0,0 +1,51 @@ > +// Copyright 2014 The Apache Software Foundation > +// > +// Licensed under the Apache License, Version 2.0 (the "License"); > +// you may not use this file except in compliance with the License. > +// You may obtain a copy of the License at > +// > +// http://www.apache.org/licenses/LICENSE-2.0 > +// > +// Unless required by applicable law or agreed to in writing, software > +// distributed under the License is distributed on an "AS IS" BASIS, > +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or > implied. > +// See the License for the specific language governing permissions and > +// limitations under the License. > + > +package org.apache.tapestry5.services; > + > +import java.util.Map; > + > +import org.apache.tapestry5.ioc.MethodAdviceReceiver; > +import org.apache.tapestry5.ioc.annotations.UsesMappedConfiguration; > + > +/** > + * Service that allows replacing one component, page or mixin class by > another without changing the sources. > + * This service shouldn't be used directly: it's not an internal service > just because it receives > + * contributions. > + * > + * Contributions to it are mapped: the key is the component, page or > mixin class to be > + * replaced, the value is the replacement. > + * > + * @since 5.4 > + * @see ComponentClassResolver. > + */ > +@UsesMappedConfiguration(key = Class.class, value = Class.class) > +public interface ComponentReplacer > +{ > + > + /** > + * Returns an immutable map of replacements. Internal use only. > + * > + * @return a {@link Map}. > + */ > + Map<Class, Class> getReplacements(); > + > + /** > + * Returns the replacement for a class given its name. > + * @param className the fully qualified class name. > + * @return a {@link Class} or null. > + */ > + Class getReplacement(String className); > + > +} > > > http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/e6a83e03/tapestry-core/src/test/app3/Login.tml > ---------------------------------------------------------------------- > diff --git a/tapestry-core/src/test/app3/Login.tml > b/tapestry-core/src/test/app3/Login.tml > index 9fba45c..6937cd2 100644 > --- a/tapestry-core/src/test/app3/Login.tml > +++ b/tapestry-core/src/test/app3/Login.tml > @@ -22,6 +22,12 @@ > <li> > <t:pagelink > page="BeanEditorWithOverridenCssClassesDemo">BeanEditor with overriden CSS > classes demo</t:pagelink> > </li> > + <li> > + <t:pagelink page="OverridenPage">ComponentReplacer > demo</t:pagelink> > + </li> > + <li> > + <t:pagelink > page="OverridePageAtComponent">ComponentReplacer demo (using @Component to > declare component instances)</t:pagelink> > + </li> > </ul> > > </body> > > > http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/e6a83e03/tapestry-core/src/test/app3/OverridePage.tml > ---------------------------------------------------------------------- > diff --git a/tapestry-core/src/test/app3/OverridePage.tml > b/tapestry-core/src/test/app3/OverridePage.tml > new file mode 100644 > index 0000000..cddb3e3 > --- /dev/null > +++ b/tapestry-core/src/test/app3/OverridePage.tml > @@ -0,0 +1,12 @@ > +<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd"> > + <head> > + <title>Override Page</title> > + </head> > + <body> > + <h1>Override Page</h1> > + <p> > + Link with mixin <t:pagelink t:page="Index" > t:mixins="OverridenMixin">Index</t:pagelink> > + </p> > + <t:overridenComponent/> > + </body> > +</html> > \ No newline at end of file > > > http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/e6a83e03/tapestry-core/src/test/app3/OverridePageAtComponent.tml > ---------------------------------------------------------------------- > diff --git a/tapestry-core/src/test/app3/OverridePageAtComponent.tml > b/tapestry-core/src/test/app3/OverridePageAtComponent.tml > new file mode 100644 > index 0000000..d10610b > --- /dev/null > +++ b/tapestry-core/src/test/app3/OverridePageAtComponent.tml > @@ -0,0 +1,12 @@ > +<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd"> > + <head> > + <title>Override Page</title> > + </head> > + <body> > + <h1>Override Page with @Component</h1> > + <p> > + Link with mixin <a t:id="link" href="#">Index</a> > + </p> > + <div t:id="overridenComponent"/> > + </body> > +</html> > \ No newline at end of file > > > http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/e6a83e03/tapestry-core/src/test/app3/OverridenPage.tml > ---------------------------------------------------------------------- > diff --git a/tapestry-core/src/test/app3/OverridenPage.tml > b/tapestry-core/src/test/app3/OverridenPage.tml > new file mode 100644 > index 0000000..cf9b1a7 > --- /dev/null > +++ b/tapestry-core/src/test/app3/OverridenPage.tml > @@ -0,0 +1,8 @@ > +<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd"> > + <head> > + <title>Overriden</title> > + </head> > + <body> > + <h1>Overriden</h1> > + </body> > +</html> > \ No newline at end of file > > > http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/e6a83e03/tapestry-core/src/test/java/org/apache/tapestry5/integration/app3/AdditionalIntegrationTests.java > ---------------------------------------------------------------------- > diff --git > a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app3/AdditionalIntegrationTests.java > b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app3/AdditionalIntegrationTests.java > index 8e03e34..774df44 100644 > --- > a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app3/AdditionalIntegrationTests.java > +++ > b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app3/AdditionalIntegrationTests.java > @@ -15,12 +15,14 @@ > package org.apache.tapestry5.integration.app3; > > import org.apache.tapestry5.integration.TapestryCoreTestCase; > +import org.apache.tapestry5.test.TapestryTestConfiguration; > import org.testng.annotations.Test; > > /** > * Additional integration tests that do not fit with the main group due > to the need for special > * configuration. > */ > +@TapestryTestConfiguration(webAppFolder = "src/test/app3") > public class AdditionalIntegrationTests extends TapestryCoreTestCase > { > /** > @@ -88,4 +90,23 @@ public class AdditionalIntegrationTests extends > TapestryCoreTestCase > > assertTextPresent("Communication with the server failed: > Server-side exception."); > } > + > + // TAP5-1611 > + @Test > + public void component_replacer() > + { > + > + final String[] pageNames = {"ComponentReplacer demo", > "ComponentReplacer demo (using @Component to declare component instances)"}; > + for (String pageName : pageNames) > + { > + openLinks(pageName); > + > + assertTrue(isElementPresent("overrideMixin")); > + assertFalse(isElementPresent("overridenMixin")); > + assertTrue(isElementPresent("overrideComponent")); > + assertFalse(isElementPresent("overridenComponent")); > + } > + > + } > + > } > > > http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/e6a83e03/tapestry-core/src/test/java/org/apache/tapestry5/integration/app3/components/OverrideComponent.java > ---------------------------------------------------------------------- > diff --git > a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app3/components/OverrideComponent.java > b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app3/components/OverrideComponent.java > new file mode 100644 > index 0000000..a43a745 > --- /dev/null > +++ > b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app3/components/OverrideComponent.java > @@ -0,0 +1,24 @@ > +// Copyright 2014 The Apache Software Foundation > +// > +// Licensed under the Apache License, Version 2.0 (the "License"); > +// you may not use this file except in compliance with the License. > +// You may obtain a copy of the License at > +// > +// http://www.apache.org/licenses/LICENSE-2.0 > +// > +// Unless required by applicable law or agreed to in writing, software > +// distributed under the License is distributed on an "AS IS" BASIS, > +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or > implied. > +// See the License for the specific language governing permissions and > +// limitations under the License. > +package org.apache.tapestry5.integration.app3.components; > + > +import org.apache.tapestry5.MarkupWriter; > + > +public class OverrideComponent > +{ > + void beginRender(MarkupWriter writer) { > + writer.element("div", "id", > "overrideComponent").element("p").text("Override component"); > + writer.end(); // div > + } > +} > > > http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/e6a83e03/tapestry-core/src/test/java/org/apache/tapestry5/integration/app3/components/OverridenComponent.java > ---------------------------------------------------------------------- > diff --git > a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app3/components/OverridenComponent.java > b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app3/components/OverridenComponent.java > new file mode 100644 > index 0000000..01f5130 > --- /dev/null > +++ > b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app3/components/OverridenComponent.java > @@ -0,0 +1,24 @@ > +// Copyright 2014 The Apache Software Foundation > +// > +// Licensed under the Apache License, Version 2.0 (the "License"); > +// you may not use this file except in compliance with the License. > +// You may obtain a copy of the License at > +// > +// http://www.apache.org/licenses/LICENSE-2.0 > +// > +// Unless required by applicable law or agreed to in writing, software > +// distributed under the License is distributed on an "AS IS" BASIS, > +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or > implied. > +// See the License for the specific language governing permissions and > +// limitations under the License. > +package org.apache.tapestry5.integration.app3.components; > + > +import org.apache.tapestry5.MarkupWriter; > + > +public class OverridenComponent > +{ > + void beginRender(MarkupWriter writer) { > + writer.element("div", "id", > "overridenComponent").element("p").text("Overriden component"); > + writer.end(); // div > + } > +} > > > http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/e6a83e03/tapestry-core/src/test/java/org/apache/tapestry5/integration/app3/mixins/OverrideMixin.java > ---------------------------------------------------------------------- > diff --git > a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app3/mixins/OverrideMixin.java > b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app3/mixins/OverrideMixin.java > new file mode 100644 > index 0000000..5614178 > --- /dev/null > +++ > b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app3/mixins/OverrideMixin.java > @@ -0,0 +1,32 @@ > +// Copyright 2014 The Apache Software Foundation > +// > +// Licensed under the Apache License, Version 2.0 (the "License"); > +// you may not use this file except in compliance with the License. > +// You may obtain a copy of the License at > +// > +// http://www.apache.org/licenses/LICENSE-2.0 > +// > +// Unless required by applicable law or agreed to in writing, software > +// distributed under the License is distributed on an "AS IS" BASIS, > +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or > implied. > +// See the License for the specific language governing permissions and > +// limitations under the License. > +package org.apache.tapestry5.integration.app3.mixins; > + > +import org.apache.tapestry5.ClientElement; > +import org.apache.tapestry5.MarkupWriter; > +import org.apache.tapestry5.annotations.InjectContainer; > +import org.apache.tapestry5.annotations.MixinAfter; > +import org.apache.tapestry5.dom.Element; > + > +@MixinAfter > +public class OverrideMixin > +{ > + @InjectContainer > + private ClientElement clientElement; > + > + void afterRender(MarkupWriter writer) { > + final Element element = > writer.getDocument().getElementById(clientElement.getClientId()); > + element.element("span", "id", "overrideMixin").text(" [Override > mixin]"); > + } > +} > > > http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/e6a83e03/tapestry-core/src/test/java/org/apache/tapestry5/integration/app3/mixins/OverridenMixin.java > ---------------------------------------------------------------------- > diff --git > a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app3/mixins/OverridenMixin.java > b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app3/mixins/OverridenMixin.java > new file mode 100644 > index 0000000..50ea142 > --- /dev/null > +++ > b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app3/mixins/OverridenMixin.java > @@ -0,0 +1,30 @@ > +// Copyright 2014 The Apache Software Foundation > +// > +// Licensed under the Apache License, Version 2.0 (the "License"); > +// you may not use this file except in compliance with the License. > +// You may obtain a copy of the License at > +// > +// http://www.apache.org/licenses/LICENSE-2.0 > +// > +// Unless required by applicable law or agreed to in writing, software > +// distributed under the License is distributed on an "AS IS" BASIS, > +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or > implied. > +// See the License for the specific language governing permissions and > +// limitations under the License. > +package org.apache.tapestry5.integration.app3.mixins; > + > +import org.apache.tapestry5.ClientElement; > +import org.apache.tapestry5.MarkupWriter; > +import org.apache.tapestry5.annotations.InjectContainer; > +import org.apache.tapestry5.dom.Element; > + > +public class OverridenMixin > +{ > + @InjectContainer > + private ClientElement clientElement; > + > + void afterRender(MarkupWriter writer) { > + final Element element = > writer.getDocument().getElementById(clientElement.getClientId()); > + element.element("span", "id", "overridenMixin").text(" [Overriden > mixin]"); > + } > +} > \ No newline at end of file > > > http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/e6a83e03/tapestry-core/src/test/java/org/apache/tapestry5/integration/app3/pages/OverridePage.java > ---------------------------------------------------------------------- > diff --git > a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app3/pages/OverridePage.java > b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app3/pages/OverridePage.java > new file mode 100644 > index 0000000..7f803b7 > --- /dev/null > +++ > b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app3/pages/OverridePage.java > @@ -0,0 +1,18 @@ > +// Copyright 2014 The Apache Software Foundation > +// > +// Licensed under the Apache License, Version 2.0 (the "License"); > +// you may not use this file except in compliance with the License. > +// You may obtain a copy of the License at > +// > +// http://www.apache.org/licenses/LICENSE-2.0 > +// > +// Unless required by applicable law or agreed to in writing, software > +// distributed under the License is distributed on an "AS IS" BASIS, > +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or > implied. > +// See the License for the specific language governing permissions and > +// limitations under the License. > +package org.apache.tapestry5.integration.app3.pages; > + > +public class OverridePage > +{ > +} > > > http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/e6a83e03/tapestry-core/src/test/java/org/apache/tapestry5/integration/app3/pages/OverridePageAtComponent.java > ---------------------------------------------------------------------- > diff --git > a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app3/pages/OverridePageAtComponent.java > b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app3/pages/OverridePageAtComponent.java > new file mode 100644 > index 0000000..33ba903 > --- /dev/null > +++ > b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app3/pages/OverridePageAtComponent.java > @@ -0,0 +1,35 @@ > +// Copyright 2014 The Apache Software Foundation > +// > +// Licensed under the Apache License, Version 2.0 (the "License"); > +// you may not use this file except in compliance with the License. > +// You may obtain a copy of the License at > +// > +// http://www.apache.org/licenses/LICENSE-2.0 > +// > +// Unless required by applicable law or agreed to in writing, software > +// distributed under the License is distributed on an "AS IS" BASIS, > +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or > implied. > +// See the License for the specific language governing permissions and > +// limitations under the License. > +package org.apache.tapestry5.integration.app3.pages; > + > +import org.apache.tapestry5.annotations.Component; > +import org.apache.tapestry5.annotations.MixinClasses; > +import org.apache.tapestry5.corelib.components.PageLink; > +import > org.apache.tapestry5.integration.app3.components.OverridenComponent; > +import org.apache.tapestry5.integration.app3.mixins.OverridenMixin; > + > +/** > + * Same as OverridePage, but using @Component to declare components. > + */ > +public class OverridePageAtComponent > +{ > + > + @Component(id = "link", parameters={"page=Index"}) > + @MixinClasses(OverridenMixin.class) > + private PageLink pageLink; > + > + @Component > + private OverridenComponent overridenComponent; > + > +} > > > http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/e6a83e03/tapestry-core/src/test/java/org/apache/tapestry5/integration/app3/pages/OverridenPage.java > ---------------------------------------------------------------------- > diff --git > a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app3/pages/OverridenPage.java > b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app3/pages/OverridenPage.java > new file mode 100644 > index 0000000..6a03091 > --- /dev/null > +++ > b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app3/pages/OverridenPage.java > @@ -0,0 +1,18 @@ > +// Copyright 2014 The Apache Software Foundation > +// > +// Licensed under the Apache License, Version 2.0 (the "License"); > +// you may not use this file except in compliance with the License. > +// You may obtain a copy of the License at > +// > +// http://www.apache.org/licenses/LICENSE-2.0 > +// > +// Unless required by applicable law or agreed to in writing, software > +// distributed under the License is distributed on an "AS IS" BASIS, > +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or > implied. > +// See the License for the specific language governing permissions and > +// limitations under the License. > +package org.apache.tapestry5.integration.app3.pages; > + > +public class OverridenPage > +{ > +} > > > http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/e6a83e03/tapestry-core/src/test/java/org/apache/tapestry5/integration/app3/services/AppModule.java > ---------------------------------------------------------------------- > diff --git > a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app3/services/AppModule.java > b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app3/services/AppModule.java > index 2f4a73d..58648bd 100644 > --- > a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app3/services/AppModule.java > +++ > b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app3/services/AppModule.java > @@ -15,10 +15,17 @@ > package org.apache.tapestry5.integration.app3.services; > > import org.apache.tapestry5.SymbolConstants; > +import org.apache.tapestry5.integration.app3.components.OverrideComponent; > +import > org.apache.tapestry5.integration.app3.components.OverridenComponent; > +import org.apache.tapestry5.integration.app3.mixins.OverrideMixin; > +import org.apache.tapestry5.integration.app3.mixins.OverridenMixin; > +import org.apache.tapestry5.integration.app3.pages.OverridePage; > +import org.apache.tapestry5.integration.app3.pages.OverridenPage; > import org.apache.tapestry5.ioc.Configuration; > import org.apache.tapestry5.ioc.MappedConfiguration; > import org.apache.tapestry5.ioc.OrderedConfiguration; > import org.apache.tapestry5.ioc.annotations.Contribute; > +import org.apache.tapestry5.services.ComponentReplacer; > import org.apache.tapestry5.services.DisplayBlockContribution; > import org.apache.tapestry5.services.Request; > import org.apache.tapestry5.services.compatibility.Compatibility; > @@ -58,7 +65,7 @@ public class AppModule > configuration.add(SymbolConstants.FORM_FIELD_CSS_CLASS, > FORM_FIELD_CSS_CLASS_VALUE); > > } > - > + > @Contribute(Compatibility.class) > public static void > disableBackwardsCompatibleFeatures(MappedConfiguration<Trait, Boolean> > configuration) > { > @@ -78,5 +85,12 @@ public class AppModule > } > }, "before:*"); > } > + > + @Contribute(ComponentReplacer.class) > + public static void > overridePageAndComponentAndMixin(MappedConfiguration<Class, Class> > configuration) { > + configuration.add(OverridenPage.class, OverridePage.class); > + configuration.add(OverridenComponent.class, > OverrideComponent.class); > + configuration.add(OverridenMixin.class, OverrideMixin.class); > + } > > } > >