In my opinion, this ties the business object a little bit 'too close' to the UI. However I realise that's a very subjective thing. So while Metawidget does not offer this 'out of the box', you can implement it quite easily. Here's how.
The Annotation
First, define the annotation...
package com.myapp;
import java.lang.annotation.*;
/**
* Array of name/value pairs of arbitrary UIComponent properties.
*/
@Retention( RetentionPolicy.RUNTIME )
@Target( ElementType.METHOD )
public @interface UiFacesComponentProperties {
String[] value();
}
import java.lang.annotation.*;
/**
* Array of name/value pairs of arbitrary UIComponent properties.
*/
@Retention( RetentionPolicy.RUNTIME )
@Target( ElementType.METHOD )
public @interface UiFacesComponentProperties {
String[] value();
}
...which you can use like this...
@UiFacesLookup( "#{feeType.summary}" )
@UiFacesComponentProperties( { "layout", "pageDirection" } )
public Set<FeeType> getExcludeFees() {
return mExcludeFees;
}
@UiFacesComponentProperties( { "layout", "pageDirection" } )
public Set<FeeType> getExcludeFees() {
return mExcludeFees;
}
The Inspector
Next, define an Inspector to detect this annotation and turn it into a Metawidget attribute...
package com.myapp;
import static org.metawidget.inspector.InspectionResultConstants.*;
import java.util.Map;
import org.metawidget.inspector.impl.*;
import org.metawidget.inspector.impl.propertystyle.*;
import org.metawidget.util.*;
import com.myapp.UiFacesComponentProperties;
public class MyAnnotationInspector
extends BaseObjectInspector {
public CoreAnnotationInspector() {
this( new BaseObjectInspectorConfig() );
}
@Override
protected Map<String, String> inspectProperty( Property property )
throws Exception {
Map<String, String> mapAttributes = CollectionUtils.newHashMap();
UiFacesComponentProperties componentProperties = property.getAnnotation( UiFacesComponentProperties.class );
if ( componentProperties != null )
mapAttributes.put( "faces-component-properties", ArrayUtils.toString( componentProperties.value() ) );
}
}
import static org.metawidget.inspector.InspectionResultConstants.*;
import java.util.Map;
import org.metawidget.inspector.impl.*;
import org.metawidget.inspector.impl.propertystyle.*;
import org.metawidget.util.*;
import com.myapp.UiFacesComponentProperties;
public class MyAnnotationInspector
extends BaseObjectInspector {
public CoreAnnotationInspector() {
this( new BaseObjectInspectorConfig() );
}
@Override
protected Map<String, String> inspectProperty( Property property )
throws Exception {
Map<String, String> mapAttributes = CollectionUtils.newHashMap();
UiFacesComponentProperties componentProperties = property.getAnnotation( UiFacesComponentProperties.class );
if ( componentProperties != null )
mapAttributes.put( "faces-component-properties", ArrayUtils.toString( componentProperties.value() ) );
}
}
...and add it into your CompositeInspector chain.
The WidgetProcessor
Finally, declare a WidgetProcessor to act on the Metawidget attribute...
package com.myapp;
import static org.metawidget.inspector.InspectionResultConstants.*;
import static org.metawidget.inspector.propertytype.PropertyTypeInspectionResultConstants.*;
import java.lang.reflect.Method;
import java.util.*;
import javax.el.ValueExpression;
import javax.faces.component.*;
import org.metawidget.faces.component.*;
import org.metawidget.util.*;
import org.metawidget.widgetprocessor.iface.WidgetProcessor;
public class MyWidgetProcessor
implements WidgetProcessor {
@Override
public UIComponent processWidget( UIComponent component, String elementName, Map<String, String> attributes, UIMetawidget metawidget ) {
List<String> listComponentProperties = CollectionUtils.fromString( attributes.get( "faces-component-properties" ));
for ( int loop = 0, length = listComponentProperties.size(); loop < length; loop += 2 ) {
ClassUtils.setProperty( component, listComponentProperties.get( loop ), listComponentProperties.get( loop + 1 ) );
}
}
}
import static org.metawidget.inspector.InspectionResultConstants.*;
import static org.metawidget.inspector.propertytype.PropertyTypeInspectionResultConstants.*;
import java.lang.reflect.Method;
import java.util.*;
import javax.el.ValueExpression;
import javax.faces.component.*;
import org.metawidget.faces.component.*;
import org.metawidget.util.*;
import org.metawidget.widgetprocessor.iface.WidgetProcessor;
public class MyWidgetProcessor
implements WidgetProcessor
@Override
public UIComponent processWidget( UIComponent component, String elementName, Map<String, String> attributes, UIMetawidget metawidget ) {
List<String> listComponentProperties = CollectionUtils.fromString( attributes.get( "faces-component-properties" ));
for ( int loop = 0, length = listComponentProperties.size(); loop < length; loop += 2 ) {
ClassUtils.setProperty( component, listComponentProperties.get( loop ), listComponentProperties.get( loop + 1 ) );
}
}
}
...and add both into your WidgetProcessor list in WEB-INF/metawidget.xml:
<htmlMetawidget xmlns="java:org.metawidget.faces.component.html">
<inspector>
<compositeInspector xmlns="java:org.metawidget.inspector.composite" config="CompositeInspectorConfig">
<inspectors>
<array>
...
<myAnnotationInspector xmlns="java:com.myapp"/>
</array>
</inspectors>
</compositeInspector>
</inspector>
...
<widgetProcessors>
<array>
...
<myWidgetProcessor xmlns="java:com.myapp"/>
</array>
</widgetProcessors>
<inspector>
<compositeInspector xmlns="java:org.metawidget.inspector.composite" config="CompositeInspectorConfig">
<inspectors>
<array>
...
<myAnnotationInspector xmlns="java:com.myapp"/>
</array>
</inspectors>
</compositeInspector>
</inspector>
...
<widgetProcessors>
<array>
...
<myWidgetProcessor xmlns="java:com.myapp"/>
</array>
</widgetProcessors>
Note this version will only work with String properties, and you might want to disable it for read-only scenarios (TRUE.equals(attributes.get(READ_ONLY))), but I'll leave it simple for now.
Feedback welcome!