Over a million developers have joined DZone.

Tapestry Mixins & ClassTransformations

· Java Zone

Bitbucket is for the code that takes us to Mars, decodes the human genome, or drives your next car. What will your code do? Get started with Bitbucket today, it's free.

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/

Bitbucket is the Git solution for professional teams who code with a purpose, not just as a hobby. Get started today, it's free.


Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

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

{{ parent.tldr }}

{{ parent.urlSource.name }}