Tapestry Mixins & ClassTransformations

DZone 's Guide to

Tapestry Mixins & ClassTransformations

· Java Zone ·
Free Resource

Tapestry‘s Class Transformation can save you a lot of time and can show you clearly why it is better than inheritance most of the time. This blog has many examples of it. I just finished a new one. Here is the scenario. I want a label to have a title attribute(simple tooltip) which is to be fetched from the message catalog of the corresponding component/page. This is not that difficult, just create a mixin. But what if you want all labels to have this feature, even the ones you have no control over like the labels in BeanEditors.

Lets go step by step. First the mixin

public class HelpText {

    private Component component;

    private Environment environment;

    void setupEnvironment(MarkupWriter writer) {

        final ValidationDecorator delegate = environment.peek(ValidationDecorator.class);
        Messages containerMessages = component.getComponentResources().getContainerMessages();

                new HelpTextValidationDecorator(delegate,  environment, containerMessages));



This mixin just pushes our own ValidationDecorator implementation onto the Environment. Also note that we are passing Messages of the component’s container so that any component/page containing the label is able to use its property file.

public class HelpTextValidationDecorator extends ValidationDecoratorWrapper {

    private ValidationDecorator delegate;

    private Messages messages;

    private Environment environment;

    public HelpTextValidationDecorator(ValidationDecorator delegate,
        Environment environment, Messages messages) {

        this.delegate = delegate;
        this.messages = messages;
        this.environment = environment;


    public void insideLabel(Field field, Element labelElement){
        delegate.insideLabel(field, labelElement);

        String key = field.getClientId() + "-help";
        if(messages.contains(key)) {
            labelElement.attribute("title", messages.get(key));

        ValidationDecorator currentDecorator = environment.peek(ValidationDecorator.class);
        if(currentDecorator == this){


This decorator delegates every method call to the original decorator except for insideLabel() call which is called just after creating the opening tag of label. We add an attribute named title to the label tag. The content of the title is obtained from the message catalog of the components container. Finally we remove the decorator from the Environment.

Now that the mixin is in place, we need a way to add this mixin to every label. Here comes the magic, Class transformation. We implement ComponentClassTransformWorker.

public class HelpTextMixinWorker implements ComponentClassTransformWorker {

    public void transform(ClassTransformation transformation, MutableComponentModel model) {

        if (Label.class.getName().equals(transformation.getClassName())) {





For Tapestry 5.3+, the code is a bit different

public class HelpTextMixinWorker implements ComponentClassTransformWorker2 {
   public void transform(final PlasticClass plasticClass,
        TransformationSupport support, MutableComponentModel model) {
        if (Label.class.getName().equals(plasticClass.getClassName())) {


Finally, remember to contribute this to the ComponentClassTransformWorker(ComponentClassTransformWorker2 in case of 5.3+) service.

public static void
        provideWorkers(OrderedConfiguration<ComponentClassTransformWorker> workers) {
    workers.addInstance("HelpTextMixinWorker", HelpTextMixinWorker.class);


From http://tawus.wordpress.com/2011/08/01/tapestry-mixins-classtransformations/

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}