package org.jboss.seam.util; import java.beans.Introspector; import java.io.Serializable; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Type; /** * A convenience class for working with an annotated property (either a field or method) of * a JavaBean class. * * @author Shane Bryzak */ public class AnnotatedBeanProperty<T extends Annotation> implements Serializable { private static final long serialVersionUID = 2508430507136805635L; private transient Field propertyField; private transient Method propertyGetter; private transient Method propertySetter; private String name; private Type propertyType; private T annotation; private boolean isFieldProperty; private boolean set = false; private Class<?> cls; private Class<? extends Annotation> annotationClass; public AnnotatedBeanProperty(Class<?> cls, Class<? extends Annotation> annotationClass) { this.cls = cls; this.annotationClass = annotationClass; init(); } private void init() { // First check declared fields for (Field f : cls.getDeclaredFields()) { if (f.isAnnotationPresent(annotationClass)) { setupFieldProperty(f); this.annotation = (T) f.getAnnotation(annotationClass); set = true; return; } } // Then check public fields, in case it's inherited for (Field f : cls.getFields()) { if (f.isAnnotationPresent(annotationClass)) { this.annotation = (T) f.getAnnotation(annotationClass); setupFieldProperty(f); set = true; return; } } // Then check public methods (we ignore private methods) for (Method m : cls.getMethods()) { if (m.isAnnotationPresent(annotationClass)) { this.annotation = (T) m.getAnnotation(annotationClass); String methodName = m.getName(); if ( m.getName().startsWith("get") ) { this.name = Introspector.decapitalize( m.getName().substring(3) ); } else if ( methodName.startsWith("is") ) { this.name = Introspector.decapitalize( m.getName().substring(2) ); } if (this.name != null) { this.propertyGetter = Reflections.getGetterMethod(cls, this.name); this.propertySetter = Reflections.getSetterMethod(cls, this.name); this.propertyType = this.propertyGetter.getGenericReturnType(); isFieldProperty = false; set = true; } else { throw new IllegalStateException("Invalid accessor method, must start with 'get' or 'is'. " + "Method: " + m + " in class: " + cls); } } } } public Field getPropertyField() { if (propertyField == null) { init(); } return propertyField; } public Method getPropertyGetter() { if (propertyGetter == null) { init(); } return propertyGetter; } public Method getPropertySetter() { if (propertySetter == null) { init(); } return propertySetter; } private void setupFieldProperty(Field propertyField) { this.propertyField = propertyField; isFieldProperty = true; this.name = propertyField.getName(); this.propertyType = propertyField.getGenericType(); } public void setValue(Object bean, Object value) { if (isFieldProperty) { Reflections.setAndWrap(getPropertyField(), bean, value); } else { Reflections.invokeAndWrap(getPropertySetter(), bean, value); } } public Object getValue(Object bean) { if (isFieldProperty) { return Reflections.getAndWrap(getPropertyField(), bean); } else { return Reflections.invokeAndWrap(getPropertyGetter(), bean); } } public String getName() { return name; } public T getAnnotation() { return (T) annotation; } public Type getPropertyType() { return propertyType; } public boolean isSet() { return set; } }