PropertiesAnalyzer.java |
package lectures.class_dual_roles.instances; import util.annotations.WebDocuments; import java.beans.BeanInfo; import java.beans.IntrospectionException; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import lectures.constructors_pointers.ABMISpreadsheet; /** * Here we will understand the Java Beans standard and the underlying concepts of * stateful objects. * Java Beans is an industry standard formally defined by the imported classes * and others. * It defines the notion of Beans and properties, which are more abstract than * Objects, methods and instance variables. * * A Bean is an object with properties, * This class helps you define what a property is. * * We see here only instance properties - we can similarly define class properties. * The goal of this class is to formally getters and setters through the concept of * properties, which are not be mistaken with instance variables. * */ @WebDocuments({"Lectures/ClassDualRolesInstances.pptx", "Lectures/ClassDualRolesInstances.pdf", "Videos/ClassDualRolesInstances.avi"}) public class PropertiesAnalyzer { /** * The following method uses the imported Bean classes to * extract properties of the object passed to it. * It used getters and setters of the object to determine * the properties. You do no have to understand how it * works, though the curious may want to look at it at leisure. * Extracting properties is an example of introspection. */ public static void printProperties (Object anObject) { try { Class aClass = anObject.getClass(); BeanInfo aBeanInfo = Introspector.getBeanInfo(aClass); PropertyDescriptor[] aPropertyDesciptors = aBeanInfo.getPropertyDescriptors(); System.out.println ("Properties defined by:" + aClass.getSimpleName()); for (PropertyDescriptor aPropertyDescriptor:aPropertyDesciptors) { String aName = Character.toUpperCase( aPropertyDescriptor.getName().charAt(0)) + aPropertyDescriptor.getName().substring(1); /* * Every object has the (inherited) property, Class", * we want to ignore inheritance issues right now * */ if ("Class".equals(aName)) { continue; } System.out.println ("Read method:" + aPropertyDescriptor.getReadMethod()); System.out.println ("Write method:" + aPropertyDescriptor.getWriteMethod()); String aType = aPropertyDescriptor.getPropertyType().getSimpleName(); boolean isEditable = aPropertyDescriptor.getWriteMethod() != null; printComponent(aName, aType, isEditable); } } catch (IntrospectionException e) { e.printStackTrace(); } } /** * The following method uses the imported Java reflection classes to * You do no have to understand how it * works, though the curious may want to look at it at leisure. * Extracting variables is an example of reflection. */ public static void printVariables (Object anObject) { Class aClass = anObject.getClass(); Field[] aFields = aClass.getDeclaredFields(); System.out.println ("Variables defined by:" + aClass.getSimpleName()); for (Field aField:aFields) { String aName = aField.getName(); String aType = aField.getType().getSimpleName(); boolean isEditable = !Modifier.isFinal(aField.getModifiers()); printComponent(aName, aType, isEditable); } } public static void printComponent (String aName, String aType, boolean isEditable) { String aNameAndType = aName + ":" + aType; String anEditable = isEditable?"Editable ":"Readonly ";; System.out.println (anEditable + aNameAndType); } /** * The main method prints the names and types of properties of instancesof * various classes. */ public static void main (String[] args) { printVariables(new ALoopingFactorialSpreadsheet()); printProperties(new ALoopingFactorialSpreadsheet()); /* * Run the main method and study the output. * (T/F) If we ignore case, for each property in ALoopingFactorialSpreadsheet * there is an (instance) variable with the same name. * (T/F) The number of properties in * ALoopingFactorialSpreadsheet is the same as the number of variables in it. * (T/F) Each read method of ALoopingFactorialSpreadsheet accesses * a different set of instance variables. * * (T/F) Each write method of ALoopingFactorialSpreadsheet changes * a different set of instance variables. */ /* * Uncomment the the code below. Study * the definition of the AnotherLoopingFactorialSpreadsheet. * What output do you expect, what do you get? */ // printVariables(new AnotherLoopingFactorialSpreadsheet()); // printProperties(new AnotherLoopingFactorialSpreadsheet()); /* . * (T/F) If we ignore case, for each property in AnotherLoopingFactorialSpreadsheet * there is a variable with the same name. * * (T/F) The number of properties in * AnotherLoopingFactorialSpreadsheet is the same as the number of variables in it. * (T/F) Each read method of AnotherLoopingFactorialSpreadsheet accesses * a different set of instance variables. * * (T/F) Each write method of AnotherLoopingFactorialSpreadsheet changes * a different set of instance variables. * (T/F) AnotherLoopingFactorialSpreadsheet and ALoopingFactorialSpreadsheet * have the same public behavior, that is behavior defined by public * methods. */ /* * Uncomment the the code below, commenting the prints above. * Visit the definition of AFactorialSpreadsheetPretender. * What properties do you expect, what do you get? * */ // printVariables(new AFactorialSpreadsheetPretender()); // printProperties(new AFactorialSpreadsheetPretender()); /* * (T/F) For each property of AFactorialSpreadsheetPretender there * exists a property with the same name and type in * ALoopingFactorialSpreadsheet. * * (T/F) For each variable of AFactorialSpreadsheetPretender there * exists a variable with the same name and type in * ALoopingFactorialSpreadsheet. * * (T/F) AFactorialSpreadsheetPretender and ALoopingFactorialSpreadsheet * have the same public behavior, that is behavior defined by the execution of * public methods. */ /* * Uncomment the the code below, commenting the prints above. * Visit the definition of AnotherFactorialSpreadsheetPretender. * What properties do you expect, what do you get? */ // printVariables(new AnotherFactorialSpreadsheetPretender()); // printProperties(new AnotherFactorialSpreadsheetPretender()); /* * (T/F) For each property of AnotherFactorialSpreadsheetPretender there * exists a property with the same name and type in * ALoopingFactorialSpreadsheet. * * (T/F) For each variable of AnotherFactorialSpreadsheetPretender there * exists a variable with the same name and type in * ALoopingFactorialSpreadsheet. */ /* * Uncomment the the code below, commenting the prints above. * Visit the definition of ANonBeanLoopingFactorialSpreadsheet. * What properties do you expect, what do you get? */ // printVariables(new ANonBeanLoopingFactorialSpreadsheet()); // printProperties(new ANonBeanLoopingFactorialSpreadsheet()); /* * (T/F) ANonBeanLoopingFactorialSpreadsheet and ALoopingFactorialSpreadsheet * have the same behavior except that they use different method names. * * (T/F) For each property of ANonBeanLoopingFactorialSpreadsheet there * exists a property with the same name and type in * ALoopingFactorialSpreadsheet. * */ /* * Uncomment the the code below, commenting the prints above. * Visit the definition of ANonBeanLoopingFactorialSpreadsheet. * What properties do you expect, what do you get? */ // printVariables(new ALoopingFactorialSpreadsheetWithNonPublicMethods()); // printProperties(new ALoopingFactorialSpreadsheetWithNonPublicMethods()); /* * (T/F) ALoopingFactorialSpreadsheetWithNonPublicMethods and ALoopingFactorialSpreadsheet * have the same behavior except that they give different access to their methods. * (T/F) For each property of ALoopingFactorialSpreadsheetWithNonPublicMethods there * exists a property with the same name and type in * ALoopingFactorialSpreadsheet. * */ } } /* * By printing the names and types of the properties and variables of * instances of different classes, * the various runs of the main method help you answer the following * general questions. * In other words, your answers to these should be consistent with * the output you see in the various runs. * (T/F) The names of variables begin with lowercase letters. * (T/F) The names of properties begin with lowercase letters. * (T/F) Each editable property has a public read method. * (T/F) Each editable property has a public write method. * (T/F) Each readonly property has a public read method. * (T/F) Each readonly property has a public write method. * A read method of a property named P of type T has the name getP and: * takes a parameter of type T, and returns a value of type T. * takes a parameter of type T, and returns no value. * takes no parameter, and returns a value of type T. * * A write method of a property named P of type T has the name setP and: * takes a parameter of type T, and returns a value of type T. * takes a parameter of type T, and returns no value. * takes no parameter, and returns a value of type T. * The names and types of the properties defined by a class depend on: * Only methods of the class. * Only variables of the class. * Both variables and methods of the class. */ // Go to