PROPOSAL: Lightweight Properties

Reinier Zwitserloot reinier at zwitserloot.com
Tue Mar 3 15:11:41 PST 2009


But it seems that we _would_ lose a thing or two with this proposal.  
For example, if a complete properties proposal supports full backwards  
compatibility and generates getters and setters, then we have a bunch  
of code around that uses the foo#bar notation, which is by then  
already outdated, and would in fact get in the way of using foo#bar  
notation as a shorthand for calling the appropriate getter/setter. I  
don't know if that is a desired syntax sugar, but the point is: Your  
proposal would effectively make it impossible to add that later, as it  
would already be shorthand for creating a Property object.

The # and the backtick are the only easily typed symbols that have no  
meaning whatsoever in java right now. Using one up for an simplified  
properties proposal is another serious disdvantage. I don't think your  
proposal makes property support light enough to warrant its inclusion  
in project coin. That's not to say I have something against  
properties; on the contrary, I love the idea and I'm very impressed  
with the way properties work in JavaFX. All the more reason to get it  
right instead of using a bandage.

  --Reinier Zwitserloot



On Mar 3, 2009, at 23:00, David Goodenough wrote:

> Well that depends on what you mean by a complete proposal.
>
> There are two parts to the use of Properties.  There is the framework
> side, inside BeansBinding or JPA and then there is the consumer
> side, the application code.
>
> My proposal is very simple on the consumer side (the only bit needed
> is the # notation).  You can use clasical getters and setters (a  
> nuisance
> but everyone understands them), or the simple getter/setter mechanism
> that my Property provides.  So for the consumer my proposal is real
> simple.  All you need do is add (either explicity or by byte code  
> enhancement)
> a PropertyChangeSupport object and the relevant methods and you
> are home and dry.
>
> For the Frameworks, well you only write them once.  Even so something
> nice and simple appeals and my proposal is simple.
>
> It may not be Beans as we know it, but they never were integrated
> properly into Java.  But its really not that dissimilar just slightly
> different.
>
> So other than a little sytactic sugar (not having to code the
> PropertyChangeSupport object) we have not really lost anything  of
> the "full" solution.  Having a Bound annotation which would add this  
> under the
> covers with a byte code enhancer would not be difficult.  The implicit
> getters and setters come with the package.  So the question to be
> asked whether a fuller solution is really needed.
>
> David
>
> On Tuesday 03 March 2009, Reinier Zwitserloot wrote:
>> The language change required for your proposal is indeed lighter, but
>> to understand it, it is seems a lot more complicated.
>>
>> Also, it would be infeasible to introduce a 'lightweight' (according
>> to anyone's definition) proposal now that is lacking in certain
>> aspects, and then fix it later, unless that fix is syntactically very
>> similar and backwards- and migration compatible. That's the major  
>> beef
>> I have with this proposal: It effectively shuts the door on any other
>> property proposal. In my view, a proposal solves the problem  
>> properly,
>> or shouldn't be added at all; no quick hacky fixes that aren't part  
>> of
>> a planned evolution path to a complete solution.
>>
>> If you can highlight how a complete properties proposal will
>> seamlessly work with your syntax, I'm more inclined to like it.
>>
>>  --Reinier Zwitserloot
>>
>> On Mar 3, 2009, at 22:04, David Goodenough wrote:
>>> Yes I do.  What you propose is much more invasive.  Look at it
>>> again and maybe you will see the Light(ness).
>>>
>>> David
>>>
>>> On Tuesday 03 March 2009, Reinier Zwitserloot wrote:
>>>> You call that lightweight?
>>>>
>>>> How about following the beans spec more to the letter and just
>>>> generate the addPropertyChangeListener,  
>>>> removePropertyChangeListener,
>>>> setX(), and get/isX() method in response to seeing a keyword or
>>>> annotation on a given field. You'll have to work out the details,  
>>>> but
>>>> that sounds far, far simpler to understand.
>>>>
>>>> You'll need to flesh this out, but it would look something like:
>>>>
>>>> public class Foo {
>>>>   private property int x;
>>>> }
>>>>
>>>> Which would generate the addPropertyChangeListener,
>>>> removePropertyChangeListener, setX, getX methods, all public, along
>>>> with the required infrastructure to make it tick. If you don't like
>>>> the generation, for example because you want the setter to be  
>>>> package
>>>> private, you just add the setter in the source file; the keyword  
>>>> will
>>>> only generate the missing stuff. It doesn't cover every use case,  
>>>> but
>>>> there's always the alternative of doing whatever people do now with
>>>> beans. Something you didn't mention in your proposal, by the way.
>>>>
>>>> I think there's also a fully fleshed out property proposal  
>>>> (including
>>>> a 'property' keyword) out there somewhere.
>>>>
>>>> Possibly make a way to opt out of generating the property change
>>>> listener support, and just the getters/setters.
>>>> --Reinier Zwitserloot
>>>>
>>>> On Mar 3, 2009, at 15:59, David Goodenough wrote:
>>>>> Below is my proposal for Lightweight Properties.  I know that the
>>>>> syntax
>>>>> change is an abbomination to some people, but I have tried to  
>>>>> reduce
>>>>> this to its absolute minimum, while still getting a significant
>>>>> benefit.
>>>>>
>>>>> PROJECT COIN SMALL LANGUAGE CHANGE PROPOSAL FORM v1.0
>>>>>
>>>>> AUTHOR(S):
>>>>>
>>>>> David Goodenough, long time Java user. I can be reached at
>>>>> david.goodenough at linkchoose.co.uk.
>>>>>
>>>>> OVERVIEW
>>>>>
>>>>> FEATURE SUMMARY:
>>>>>
>>>>> Lightweight Property support
>>>>>
>>>>> MAJOR ADVANTAGE:
>>>>>
>>>>> Both BeansBinding (whether JSR-295 or others such an JFace or the
>>>>> JGoodies
>>>>> binding) and the JPA Criteria API currently require field names  
>>>>> (as
>>>>> Strings)
>>>>> as arguments, which an IDE/compiler can not check. With this
>>>>> proposal the
>>>>> strings would be abandoned, and the IDE/compiler will be able to
>>>>> check the
>>>>> correctness of the code.
>>>>>
>>>>> MAJOR BENEFIT:
>>>>>
>>>>> Manual checking no longer required. This proposal introduces a
>>>>> simple well
>>>>> defined IDE/compiler checkable solution.
>>>>>
>>>>> MAJOR DISADVANTAGE:
>>>>>
>>>>> It is a language change, and this seems to upset some people.
>>>>>
>>>>> ALTERNATIVES:
>>>>>
>>>>> None really, apart from using another language or continuing to  
>>>>> use
>>>>> String
>>>>> names. The existing solutions all require String names which are
>>>>> uncheckable.
>>>>>
>>>>> EXAMPLES
>>>>>
>>>>> Lets assume we have a POJO called foo, of type Foo with a field  
>>>>> bar
>>>>> of type
>>>>> Bar, which itself has a field of type Jim called jim.
>>>>>
>>>>> There are two forms of lightweight properties:-
>>>>>
>>>>> 1) foo#bar would be translated by the compiler into:-
>>>>>
>>>>> 	new Property<Foo,Bar>(foo,"bar");
>>>>>
>>>>> while foo#bar#jim would be translated into:-
>>>>>
>>>>> 	new Property<Foo,Jim>(foo,"bar","jim");
>>>>>
>>>>> 2) Foo#bar would be translated into:-
>>>>>
>>>>> 	new Property<Foo,Bar>(Foo.class,"bar");
>>>>>
>>>>> while Foo#bar#jim would be translated into:-
>>>>>
>>>>> 	new Property<Foo,Jim>(Foo.class,"bar","jim");
>>>>>
>>>>> These two forms create (1) a bound Property, or (2) an unbound  
>>>>> one.
>>>>> Bound
>>>>> Properties are explicitly bound to a particular instance of a  
>>>>> class
>>>>> (in this
>>>>> case foo), while unbound Properties are templates which can be
>>>>> applied to any
>>>>> instance of class Foo. Actually bound properties can also be  
>>>>> used as
>>>>> unbound
>>>>> properties, but that is a harmless and useful side effect not a
>>>>> primary
>>>>> intent.
>>>>>
>>>>> The Property class would need to be added (it is appended below),
>>>>> and should
>>>>> be added either to the java.beans package or to the
>>>>> java.lang.reflect package
>>>>> (with which is probably has more in common).
>>>>>
>>>>> Syntactically a "#" can be placed wherever a "." can be placed
>>>>> (except inside
>>>>> a number), and the same checks need to be made (that each field to
>>>>> the right
>>>>> of a # is a field in the left hand side) as would be made for a  
>>>>> ".".
>>>>> The only
>>>>> difference is in field visibility - For the "#" any field is
>>>>> visible, which
>>>>> follows the model currently available in the Field class with
>>>>> getDeclaredFields(). It also follows the model that while a field
>>>>> might be
>>>>> private and therefore not directly accessible from outside,  
>>>>> getters
>>>>> and
>>>>> setters can provide access.
>>>>>
>>>>> The Property object provides type safe access to the field in the
>>>>> form of
>>>>> getters and setters. These come in pairs, one for bound and the
>>>>> other for
>>>>> unbound access. So for bound access no object is required to fetch
>>>>> the value,
>>>>> for an unbound object the parent object needs to be specified.  
>>>>> So if
>>>>> we
>>>>> have:-
>>>>>
>>>>> 	Property<Foo,Bar>prop = foo#bar;
>>>>>
>>>>> we can later say:-
>>>>>
>>>>> 	Bar b = prop.get();
>>>>>
>>>>> or for an unbound one from a second Foo object foo2:-
>>>>>
>>>>> 	Bar b = prop.get(foo2);
>>>>>
>>>>> The getters and setters in the Property object will defer to
>>>>> explicitly coded
>>>>> getters and setters if present, otherwise they will use the Field
>>>>> getter and
>>>>> setter.
>>>>>
>>>>> If a setter is not explicitly coded, the implicit setter will look
>>>>> for a
>>>>> PropertyChangeSupport object in the parent object of the rightmost
>>>>> field and
>>>>> fire a PropertyChangeEvent to that object.
>>>>>
>>>>> There are also two Annotations provided by the Property class,
>>>>> ReadOnly and
>>>>> WriteOnly. These stop implicit getters and setters from trying to
>>>>> read/write
>>>>> the property.
>>>>>
>>>>> Talking of Annotations, this notation can also be used to get at  
>>>>> the
>>>>> Annotations for a field. So to test for the presence of an
>>>>> Annotation Ann on
>>>>> Foo.bar we would use:-
>>>>>
>>>>> 	if(Foo#bar.getFields()[0].isAnnotationPresent(Ann.class)) ...
>>>>>
>>>>> SIMPLE EXAMPLE:
>>>>>
>>>>> To take an example from BeansBinding (taken from Shannon Hickey's
>>>>> blog):-
>>>>>
>>>>> 	// create a BeanProperty representing a bean's firstName
>>>>> 	Property firstP = BeanProperty.create("firstName");
>>>>> 	// Bind Duke's first name to the text property of a Swing
>>>>> JTextField
>>>>> 	BeanProperty textP = BeanProperty.create("text");
>>>>> 	Binding binding = Bindings.createAutoBinding(READ_WRITE, duke,
>>>>> 					firstP, textfield, textP);
>>>>> 	binding.bind();
>>>>>
>>>>>
>>>>> would instead be written:-
>>>>>
>>>>> 	Binding binding = Bindings.createAutoBinding(READ_WRITE,
>>>>> 					duke#firstName, textfield#text);
>>>>> 	binding.bind();
>>>>>
>>>>> which of course can be checked by the IDE/compiler, and will not
>>>>> wait until
>>>>> run time (not even instantiation time) to show up the error.
>>>>>
>>>>> ADVANCED EXAMPLE:
>>>>>
>>>>> For a JComboBox (or JList or JTable or JTree) there is a need to  
>>>>> map
>>>>> a list of
>>>>> objects to the value strings (or column contents). For this we  
>>>>> need
>>>>> to have
>>>>> an unbound Property which can be applied to each element of the
>>>>> list.
>>>>>
>>>>> 	Duke duke;
>>>>> 	List<Duke>dukes;
>>>>> 	BoundComboBox combo = new
>>>>> BoundComboBox(dukes,Duke#fullname,this#duke);
>>>>>
>>>>> and now the combo box will be populated from the list dukes, and  
>>>>> the
>>>>> display
>>>>> values in the list will be taken from the fullname field of each
>>>>> Duke
>>>>> element, and the initial value will be set from the local class
>>>>> field duke
>>>>> and any changes to the combo box selected element will be  
>>>>> reflected
>>>>> back to
>>>>> the duke field.
>>>>>
>>>>> DETAILS
>>>>>
>>>>> SPECIFICATION:
>>>>>
>>>>> This proposal adds a new syntactic element, "#", which can be used
>>>>> in the same
>>>>> way that "." can be used to qualify fields within a Java object.
>>>>>
>>>>> COMPILATION:
>>>>>
>>>>> This proposal requires no change to the class files, and is
>>>>> implemented by a
>>>>> simple generation of the required instance using the relevant
>>>>> Property
>>>>> constructor. Obviously the compiler would have to make sure that  
>>>>> the
>>>>> use that
>>>>> the property object was being put to (in the examples above the  
>>>>> left
>>>>> hand
>>>>> side of the assignment) had the correct Generic attributes.
>>>>>
>>>>> TESTING:
>>>>>
>>>>> How can the feature be tested?
>>>>>
>>>>> LIBRARY SUPPORT:
>>>>>
>>>>> The new Property class is required (see below).
>>>>>
>>>>> REFLECTIVE APIS:
>>>>>
>>>>> No changes are required to the reflective APIs although it makes
>>>>> extensive use
>>>>> of those APIs.
>>>>>
>>>>> OTHER CHANGES:
>>>>>
>>>>> No other changes are requires.
>>>>>
>>>>> MIGRATION:
>>>>>
>>>>> Fortunately there is no code that is formally part of J2SE 6 which
>>>>> uses such
>>>>> Properties. There are however two proposals which will need it
>>>>> (BeansBinding
>>>>> and JPA Criteria API), but neither of these seem to be destined to
>>>>> be part of
>>>>> J2SE 7 (BeansBinding seems to have died the death and the Criteria
>>>>> API would
>>>>> be part of the next J2EE which will follow J2SE 7), so this will
>>>>> provide a
>>>>> base for them to use and no existing code need to be updated.
>>>>>
>>>>> There are other extant Beans-Binding libraries, which could be
>>>>> modified to use
>>>>> this proposal, but as none of the existing features have been
>>>>> changed there
>>>>> is no need to change them (other than for type safety and  
>>>>> compiler/
>>>>> IDE
>>>>> checkability).
>>>>>
>>>>> COMPATIBILITY
>>>>>
>>>>> BREAKING CHANGES:
>>>>>
>>>>> None.  This change should not make any existing correct code  
>>>>> fail to
>>>>> compile
>>>>> or run or change the way in which it compiles/runs.
>>>>>
>>>>> EXISTING PROGRAMS:
>>>>>
>>>>> No change required to any existing programs
>>>>>
>>>>> REFERENCES
>>>>>
>>>>> EXISTING BUGS:
>>>>>
>>>>> None
>>>>>
>>>>> URL FOR PROTOTYPE (optional):
>>>>>
>>>>> I do not have the knowledge to make changes to the compiler, and  
>>>>> the
>>>>> only
>>>>> documentation making such changes concentrated on adding operators
>>>>> not
>>>>> changes at this level. So there is no prototype of the compiler
>>>>> part, but the
>>>>> Property class follows:-
>>>>>
>>>>> package java.lang.reflect;
>>>>>
>>>>> import java.beans.BeanInfo;
>>>>> import java.beans.Introspector;
>>>>> import java.beans.PropertyChangeSupport;
>>>>> import java.beans.PropertyDescriptor;
>>>>> import java.lang.reflect.Field;
>>>>> import java.lang.reflect.Method;
>>>>>
>>>>> /**
>>>>> * Property class
>>>>> * This is the support class for use with the # notation to provide
>>>>> lightweight
>>>>> * Property support for Java.
>>>>> *
>>>>> * @copyright Copyright(C) 2009 David Goodenough Linkchoose Ltd
>>>>> * @licence LPGL V2 : details of which can be found at http://
>>>>> fsf.org.
>>>>> * @author david.goodenough at linkchoose.co.uk
>>>>> *
>>>>> * @param <C> The Parent class for this field
>>>>> * @param <F> The Type of this field
>>>>> */
>>>>> public class Property<C,F> {
>>>>>  private C parent;
>>>>> private Class<?> parentClass;
>>>>> private Field[] fields;
>>>>> private PropertyDescriptor[] pd = null;
>>>>> /**
>>>>>  * Constructor used to create Property objects.  The Parent object
>>>>> may be
>>>>>  * null, but should normally be specified as it can be overridden
>>>>> anyway.
>>>>>  * @param parent C object that contains the field
>>>>>  * @param field Field describing this field
>>>>>  */
>>>>> public Property(C parent, String ... fieldNames) {
>>>>>     this.parent = parent;
>>>>>      this(parent.getClass(), fieldNames);
>>>>>      }
>>>>>  /**
>>>>>   * Constructor for unbound Properties, but also used internally
>>>>> after
>>>>> setting
>>>>>   * the parent object by the bound Property objects.
>>>>>   * @param parentClass Class of the parent object
>>>>>   * @param fieldNames String[] of field names
>>>>>   */
>>>>>  public Property(Class<?>parentClass, String .. fieldNames) {
>>>>>      this.parentClass = parentClass;
>>>>>     fields = new Field[fieldNames.length];
>>>>>     pd = new PropertyDescriptor[fieldNames.length];
>>>>> outer:  for(int index = 0; index < fields.length; index++) {
>>>>>         Field[]dclFields = parentClass.getDeclaredFields();
>>>>>     	    for(Field field:dclFields) {
>>>>>     		if(field.getName().equals(fieldNames[index])) {
>>>>>     			fields[index] = field;
>>>>>     			field.setAccessible(true);
>>>>>     	    	try {
>>>>>     	    		BeanInfo beanInfo =
>>>>> Introspector.getBeanInfo(parent.getClass());
>>>>>     	    		PropertyDescriptor[]props =
>>>>> beanInfo.getPropertyDescriptors();
>>>>>     	    		for(PropertyDescriptor prop : props) {
>>>>>     	    			if(prop.getName().equals(field.getName())) {
>>>>>     	    				pd[index] = prop;
>>>>>     	    				break;
>>>>>     	    				}
>>>>>     	    			}
>>>>>     	    		} catch(Exception e) { /* assume can not find getter/
>>>>> setter
>>>>> */ }
>>>>>     			parentClass = field.getType();
>>>>>     			continue outer;
>>>>>     			}
>>>>>     		}
>>>>> 	throw new IllegalArgumentException("Field " + fieldNames[index] +
>>>>>                         " not found in class " +
>>>>> parentClass.getCanonicalName());
>>>>>     	}
>>>>>     }
>>>>> /**
>>>>>  * Getter from the field in the parent specified when this
>>>>> Property was
>>>>> created.
>>>>>  * @see Property.get(C otherParent)
>>>>>  * @return F the value of this field
>>>>>  */
>>>>> public F get() {
>>>>>     return get(parent);
>>>>>     }
>>>>> /**
>>>>>  * Getter with explicit parent.
>>>>>  * This code will check see if this field is WriteOnly, and
>>>>> complain if it
>>>>> is.
>>>>>  * It will then see if the use has provided am explicit getter,
>>>>> and call
>>>>> that
>>>>>  * if present, otherwise it will just fetch the value through the
>>>>> Field
>>>>> provided
>>>>>  * method.
>>>>>  * @param otherParent C parent object
>>>>>  * @return F value of the field
>>>>>  */
>>>>> @SuppressWarnings("unchecked") // This should actually not be
>>>>> needed,
>>>>>                                // but the Field.get method is not
>>>>> typed
>>>>> public F get(C otherParent) {
>>>>> 	Object result = otherParent;
>>>>> 	try {
>>>>> 	    for(int index = 0; index < fields.length; index++) {
>>>>>
>>>>> if(fields[index].getType().isAnnotationPresent(WriteOnly.class))
>>>>>                 throw new IllegalAccessException(
>>>>>                     "Can not get from a WriteOnly field - " +
>>>>> fields[index].getName());
>>>>> 		Method getter = pd[index] == null ? null :
>>>>> pd[index].getReadMethod();
>>>>> 		if(getter == null) result = fields[index].get(result);
>>>>> 		    else result = getter.invoke(result);
>>>>> 		}
>>>>> 	    } catch(Exception e) {
>>>>> 		throw new RuntimeException("Should not occur exception", e);
>>>>> 		}
>>>>> 	return (F)result;
>>>>>     }
>>>>> /**
>>>>>  * Setter to set the value of the field in the parent object
>>>>> declared with
>>>>> the
>>>>>  * Property object
>>>>>  * @param newValue F new value of this field
>>>>>  */
>>>>> public void set(F newValue) {
>>>>>     set(parent,newValue);
>>>>>     }
>>>>> /**
>>>>>  * Setter to set the value of the field to an explicit parent
>>>>> object.
>>>>>  * If there is a ReadOnly annotation, then we object.  If there is
>>>>> an
>>>>> explicit
>>>>>  * setter then we use that, otherwise we set the field using the
>>>>> Field
>>>>> provided
>>>>>  * set method and if there is a PropertyChangeSupport field,  
>>>>> fire a
>>>>> property
>>>>>  * change event to it.
>>>>>  * We walk our way down the field chain, until we have the last
>>>>> object and
>>>>> its
>>>>>  * field, and then we do the set.
>>>>>  * @param parent C explicit parent object
>>>>>  * @param newValue F new value for field in parent
>>>>>  */
>>>>> public void set(C parent,F newValue) {
>>>>> 	try {
>>>>> 	    Object last = parent;
>>>>> 	    int index;
>>>>> 	    for(index = 0; index < fields.length - 1; index++) {
>>>>>
>>>>> if(fields[index].getType().isAnnotationPresent(WriteOnly.class))
>>>>>                 throw new IllegalAccessException(
>>>>>                     "Can not get from a WriteOnly field - " +
>>>>>                     fields[index].getName());
>>>>>             Method getter = pd[index] == null ? null :
>>>>> pd[index].getReadMethod();
>>>>> 	        if(getter == null) last = fields[index].get(last);
>>>>> 	        else last = getter.invoke(last);
>>>>>             }
>>>>>
>>>>> if(fields[index].getType().isAnnotationPresent(ReadOnly.class))
>>>>>             throw new IllegalAccessException(
>>>>>                 "Can not get from a WriteOnly field - " +
>>>>> fields[index].getName());
>>>>> 		Method setter = pd[index] == null ? null :
>>>>> pd[index].getWriteMethod();
>>>>> 		if(setter == null) {
>>>>> 	            PropertyChangeSupport pcs = findPcs(last.getClass());
>>>>> 	            fields[index].set(last,newValue);
>>>>> 	        if(pcs != null)
>>>>> pcs.firePropertyChange(fields[index].getName(),
>>>>>                                                     newValue,
>>>>>
>>>>> fields[index].get(last));
>>>>> 		} else setter.invoke(last,newValue);
>>>>> 	    } catch(Exception e) {
>>>>>             throw new RuntimeException("Should not occur
>>>>> exception", e);
>>>>>             }
>>>>>     }
>>>>> /**
>>>>>  * This is used so that the caller can view the Field name
>>>>>  * @return String field name
>>>>>  */
>>>>> public String[] getFieldName() {
>>>>> 	String[]names = new String[fields.length];
>>>>> 	for(int index = 0; index < fields.length; index++) {
>>>>>         names[index] = fields[index].getName();
>>>>>         }
>>>>> 	return names;
>>>>> 	}
>>>>>  /**
>>>>>   * This method is used to fetch the Field array, which is useful
>>>>> if you
>>>>> need to
>>>>>   * access the Annotations of a field.
>>>>>   * @return Field[] the array of Fields describing this Property.
>>>>>   */
>>>>>  public Field[] getFields() {
>>>>>      return fields;
>>>>>      }
>>>>> /**
>>>>>  * This private method looks for a PropertyChangeSupport object in
>>>>> the
>>>>> class and
>>>>>  * if one is found it will return it.  It looks right the way up
>>>>> the class
>>>>> tree
>>>>>  * by recurring up the superClasses.
>>>>>  * @param parent Class to check for PropertyChangeSupport fields
>>>>>  * @return PropertyChangeSupport first found object, or null if
>>>>> not found
>>>>>  */
>>>>> private PropertyChangeSupport findPcs(Class<?> parent) {
>>>>> 	Field fields[] = parent.getDeclaredFields();
>>>>> 	for(Field field:fields) {
>>>>> 	    field.setAccessible(true);
>>>>> 	    try {
>>>>> 	        if(field.getType() == PropertyChangeSupport.class)
>>>>> 	            return (PropertyChangeSupport)field.get(parent);
>>>>>             } catch(Exception e) { }
>>>>> 	    }
>>>>> 	// If we did not find it then try the superclass
>>>>> 	Class<?>superClass = parent.getSuperclass();
>>>>> 	if(superClass == null) return null;
>>>>> 	return findPcs(parent.getClass().getSuperclass());
>>>>>     }
>>>>> /**
>>>>>  * This annotation is used to mark a field as WriteOnly, i.e. it
>>>>> can not
>>>>> be read.
>>>>>  * This stops the automatic getter operation.
>>>>>  */
>>>>> public @interface WriteOnly {
>>>>> 	}
>>>>> /**
>>>>>  * This annotation is used to mark a field as ReadOnly, i.e. it
>>>>> can not be
>>>>> written.
>>>>>  * This stops the automatic setter operation.
>>>>>  */
>>>>> public @interface ReadOnly {
>>>>> 	}
>>>>> }
>
>
>




More information about the coin-dev mailing list