PROPOSAL: Method and Field Literals

David Goodenough david.goodenough at linkchoose.co.uk
Thu Mar 12 03:57:59 PDT 2009


On Thursday 12 March 2009, Frédéric Martini wrote:
> 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 <B> The Bean's type
>  * @param <T> 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 <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
> 	 * @throws RuntimeException if the property cannot be found
> 	 */
> 	private static <B,T> Property<B,T> findProperty(Class<B> beanClass,
> Class<T> 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<T> 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 <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 only get
> method * @throws RuntimeException if the property cannot be found
> 	 */
> 	public static <B,T> Property<B,? extends T>
> getReadableProperty(Class<B> beanClass, Class<T> 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,

Fred,

This is a lot like my lightweight properties proposal.  It only covers fields
(not methods) but your Property class and mine have a lot in common.

David



More information about the coin-dev mailing list