RIFE logo
This page last changed on Dec 08, 2006 by hynek.

RIFE supports an automated method to add meta data to POJO classes without having any additional code nor annotations inside the POJOs themselves.

Consider a class Foo and another class FooMetaData. When FooMetaData implements the MetaDataMerged interface (which is simply a marker), RIFE will instrument Foo and make it implement all the interfaces that FooMetaData implements. Also, when the default constructor of Foo is called, an instance of FooMetaData will be created and stored in a new hidden member variable. The added method implementations simple delegate execution to this instance of FooMetaData. Optionally, FooMetaData can also implement the MetaDataBeanAware interface, in which case the instance of FooMetaData will receive the instance of Foo that it belongs to right after it has been instantiated. Note that the relationship between Foo and FooMetaData is purely name based (the MetaData suffix). RIFE will look up the meta data class through the classpath, which means that it's possible to augment any class. MetaData classes must share the same package name as the class they're to be merged with. For example, to inject MetaData information into org.rifers.Bean you would create a class org.rifers.BeanMetaData.

Constraints are a typical usage for this feature. Any POJO is now able to have constraints attached to it, without violating the purity of the POJO class implementation itself. For convenience, you can extend the MetaData abstract base class which implements everything you need to easily specify constraints in a meta data class.

For example, the Person class:

public class Person {
    private String firstname;
    private String lastname;
     
    public void setFirstname(String firstname) {
        this.firstname = firstname;
    }
     
    public String getFirstname() {
        return firstname;
    }
     
    public void setLastname(String lastname) {
        this.lastname = lastname;
    }
     
    public String getLastname() {
        return lastname;
    }
}

and the PersonMetaData class:

public class PersonMetaData extends MetaData {
    public void activateMetaData() {
        addConstraint(new ConstrainedProperty("firstname")
            .maxLength(10)
            .notNull(true));
        addConstraint(new ConstrainedProperty("lastname")
            .inList("Smith", "Jones", "Ronda"));
    }
}

As long as RIFE's classloader is active, both will be automatically merged into a new Person class. You can access the added interface methods simply by casting an instance of Person to the appropriate interface name.

For example:

Person person = new Person();
Validated validated = (Validated)person;
assertFalse(validated.validate());
 
validated.resetValidation();
 
person.setFirstname("John");
person.setLastname("Smith");
assertTrue(validated.validate());

Note that this is also implicitly available to RIFE/Crud, which means that you can easily generated CRUD web interfaces for existing models, without having to add constraints to their original implementation.

If your classes are part of an inheritance hierarchy, note that metadata merging is performed only for a named pair of classes, such as Person and PersonMetaData. RIFE does not merge metadata from superclasses. This means that if your metadata class should also enforce constraints defined for a superclass, then the metadata class should extend the superclass's metadata class (not MetaData), and methods should explicitly invoke superclass methods (e.g. method activateMetaData() should begin with a call to super.activateMetaData()).

Document generated by Confluence on Oct 19, 2010 14:57