PROPOSAL: Method and Field Literals (original) (raw)
Frédéric Martini frederic.martini at gmail.com
Thu Mar 12 03:41:54 PDT 2009
- Previous message: PROPOSAL: Method and Field Literals
- Next message: PROPOSAL: Method and Field Literals
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Hello,
Before to start, sorry for my poor english. This is not my spoken language :(
My advice for this proposal : this is a must-have : this will allow to use secure-code with reflection !
But I want to extends this proposal with the support of beans' property. In fact, access to field is very limited due to visibility : there are more often protected or private... For example: we cannot use Exception#message or Exception#cause :(
It will be more interresting to use the beans' property notion, by exemple with a Property's class like this (this is a scratch exemple, with RuntimeException to be replaced by a more precise unchecked exception...) :
/**
Immutable class
@param The Bean's type
@param The property's type */ final class Property<B,T> {
/** Name of the property / private final String name; /* Read-method of the property / private final Method get; /* Write-method of the property */ private final Method set;
/**
- Private Constructor
- @see Property#getReadableProperty(Class, Class, String)
- @see Property#getWritableProperty(Class, Class, String) */ private Property(String name, Method get, Method set) { this.name = name; this.get = get; this.set = set; }
/**
- @return the property name */ public String name() { return this.name; }
/**
- Call the get-method on the specified instance. */ public T get(B beans) { try { @SuppressWarnings("unchecked") T result = (T) this.get.invoke(beans); return result; } catch (Exception e) { throw new RuntimeException("get()", e); } }
/**
- @return true if this property is writable (have write-method) */ public boolean isWritable() { return this.set!=null; }
/**
- Call the set-method on the specified instance. */ public void set(B beans, T value) { try { this.set.invoke(beans, value); } catch (Exception e) { throw new RuntimeException("set()", e); } }
/**
- Find an create an Property.
- @param The Bean's type
- @param The property's type
- @param beanClass The Bean's type
- @param propertyClass The property's type
- @param propertyName The property's name
- @return A Property for the specified beans-property
- @throws RuntimeException if the property cannot be found */ private static <B,T> Property<B,T> findProperty(Class beanClass,
Class propertyClass, String propertyName) { try { for (PropertyDescriptor descriptor : Introspector.getBeanInfo(beanClass).getPropertyDescriptors() ) { if (descriptor.getName().equals(propertyName) && propertyClass.equals(descriptor.getPropertyType())) { return new Property<B,T>(descriptor.getName(), descriptor.getReadMethod(), descriptor.getWriteMethod()); } } } catch (IntrospectionException e) { throw new RuntimeException("Property not found : " + propertyName, e); } throw new RuntimeException("Property not found : " + propertyName); }
/**
* Get a read/write property
* @param <B> The Bean's type
* @param <T> The property's type
* @param beanClass The Bean's type
* @param propertyClass The property's type
* @param propertyName The property's name
* @return A Property for the specified beans-property, with get/set method
* @throws RuntimeException if the property cannot be found, or is not writable
*/
public static <B,T> Property<B,T> getWritableProperty(Class<B>
beanClass, Class propertyClass, String propertyName) { Property<B,T> property = findProperty(beanClass, propertyClass, propertyName); if (!property.isWritable()) { throw new RuntimeException("Non-writable property : " + propertyName); } return property; }
/**
* Get a read-only property.
* The return type is Property<B,? extends T> in order to forbid the
use of the set() method * @param The Bean's type * @param The property's type * @param beanClass The Bean's type * @param propertyClass The property's type * @param propertyName The property's name * @return A Property for the specified beans-property, with only get method * @throws RuntimeException if the property cannot be found */ public static <B,T> Property<B,? extends T> getReadableProperty(Class beanClass, Class propertyClass, String propertyName) { return findProperty(beanClass, propertyClass, propertyName); } }
Property.getWritableProperty() return a property with read/write access, and Property.getReadableProperty() return a property with read-only access, declared as Property<B,? extends T> in order to have compile-time error if the set method is used...
Exemple of use :
public class MyObject {
private final String name;
private int value;
public MyObject(String name) {
this.name = name;
}
public String getName() {
return name;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public static void main(String[] args) {
MyObject beans = new MyObject("name");
Property<MyObject, Integer> valueProperty =
Property.getWritableProperty(MyObject.class, int.class, "value"); int value = valueProperty.get(beans); // OK valueProperty.set(beans, 100); // OK
Property<MyObject, ? extends String> nameProperty =
Property.getReadableProperty(MyObject.class, String.class, "name"); String name = nameProperty.get(beans); // OK nameProperty.set(beans, "hello"); // Compile error (is not applicable...) } }
My proposal is to use a literal in order to replace the static method call (unsafe because based on a String) with a checked literral :
So this :
Property<MyObject, Integer> valueProperty = Property.getWritableProperty(MyObject.class, int.class, "value"); Property<MyObject, ? extends String> nameProperty = Property.getReadableProperty(MyObject.class, String.class, "name");
May be remplaced with something like (or equivalent) :
Property<MyObject, Integer> value = MyObject#value; Property<MyObject, ? extends String> name = MyObject#name;
(We can use the same notation that the Field literral, based on context, or any other syntaxe...)
MyObject#value is matched to Property<MyObject, Integer> because the MyObject's class have a property called "value", with a getter (getValue()) and a setter (setValue()). MyObject#name is matched to Property<MyObject, ? extends String> because the name's property only have a getter and no-setter !
Of course the literral MyObject#value will be checked at compile time, to produce compile-time error on bad usage.
This will allow the literral to be more useful and usable with almost all classes :
Field message = Throwable#message; // ERROR : message don't exist or is private :( Property<Throwable, ? extends String> message = Throwable#message; // OK
What do you think about this ?
Thanks for reading ;)
Fred,
- Previous message: PROPOSAL: Method and Field Literals
- Next message: PROPOSAL: Method and Field Literals
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]