1 /* 2 * Copyright the original author or authors. 3 * 4 * Licensed under the MOZILLA PUBLIC LICENSE, Version 1.1 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.mozilla.org/MPL/MPL-1.1.html 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 import org.as2lib.core.BasicClass; 18 import org.as2lib.util.Stringifier; 19 import org.as2lib.env.reflect.TypeInfo; 20 import org.as2lib.env.reflect.MethodInfo; 21 import org.as2lib.env.reflect.TypeMemberInfo; 22 import org.as2lib.env.reflect.stringifier.PropertyInfoStringifier; 23 24 /** 25 * {@code PropertyInfo} represents a property. 26 * 27 * <p>The term property means only properties added via {@code Object.addProperty} 28 * or the ones added with the {@code get} and {@code set} keywords, that are implicit 29 * getters and setters, not variables. 30 * 31 * <p>{@code PropertyInfo} instances for specific properties can be obtained using 32 * the methods {@link ClassInfo#getProperties} or {@link ClassInfo#getProperty}. 33 * That means you first have to get a class info for the class that declares or 34 * inherits the property. You can therefor use the {@link ClassInfo#forObject}, 35 * {@link ClassInfo#forClass}, {@link ClassInfo#forInstance} and {@link ClassInfo#forName} 36 * methods. 37 * 38 * <p>When you have obtained the property info you can use it to get information 39 * about the property. 40 * 41 * <code> 42 * trace("Property name: " + propertyInfo.getName()); 43 * trace("Declaring type: " + propertyInfo.getDeclaringType().getFullName()); 44 * trace("Is Static?: " + propertyInfo.isStatic()); 45 * trace("Is Writable?: " + propertyInfo.isWritable()); 46 * trace("Is Readable?: " + propertyInfo.isReadable()); 47 * </code> 48 * 49 * @author Simon Wacker 50 */ 51 class org.as2lib.env.reflect.PropertyInfo extends BasicClass implements TypeMemberInfo { 52 53 /** The property info stringifier. */ 54 private static var stringifier:Stringifier; 55 56 /** 57 * Returns the stringifier used to stringify property infos. 58 * 59 * <p>If no custom stringifier has been set via the {@link #setStringifier} method, 60 * an instance of the default {@link PropertyInfoStringifier} class is returned. 61 * 62 * @return the stringifier that stringifies property infos 63 */ 64 public static function getStringifier(Void):Stringifier { 65 if (!stringifier) stringifier = new PropertyInfoStringifier(); 66 return stringifier; 67 } 68 69 /** 70 * Sets the stringifier used to stringify property infos. 71 * 72 * <p>If {@code propertyInfoStringifier} is {@code null} or {@code undefined} the 73 * {@link #getStringifier} method will return the default stringifier. 74 * 75 * @param propertyInfoStringifier the stringifier that stringifies property infos 76 */ 77 public static function setStringifier(propertyInfoStringifier:PropertyInfoStringifier):Void { 78 stringifier = propertyInfoStringifier; 79 } 80 81 /** The name of this property. */ 82 private var name:String; 83 84 /** The setter method of this property. */ 85 private var setter:MethodInfo; 86 87 /** The getter method of this property. */ 88 private var getter:MethodInfo; 89 90 /** The type that declares this property. */ 91 private var declaringType:TypeInfo; 92 93 /** A flag representing whether this property is static. */ 94 private var staticFlag:Boolean; 95 96 /** 97 * Constructs a new {@code PropertyInfo} instance. 98 * 99 * <p>All arguments are allowed to be {@code null}. But keep in mind that not all 100 * methods will function properly if one is. 101 * 102 * <p>If arguments {@code setter} or {@code getter} are not specified they will be 103 * resolved at run-time everytime asked for. Making use of this functionality you 104 * will always get the up-to-date setter or getter. 105 * 106 * @param name the name of the property 107 * @param declaringType the type declaring the property 108 * @param staticFlag determines whether the property is static 109 * @param setter (optional) the setter method of the property 110 * @param getter (optional) the getter method of the property 111 */ 112 public function PropertyInfo(name:String, 113 declaringType:TypeInfo, 114 staticFlag:Boolean, 115 setter:Function, 116 getter:Function) { 117 this.name = name; 118 this.declaringType = declaringType; 119 this.staticFlag = staticFlag; 120 this.setter = new MethodInfo("__set__" + name, declaringType, staticFlag, setter); 121 this.getter = new MethodInfo("__get__" + name, declaringType, staticFlag, getter); 122 } 123 124 /** 125 * Returns the name of this property. 126 * 127 * <p>If you want the getter or setter methods' name you must use the {@code getName} 128 * method of the {@code getGetter} or {@code getSetter} method respectively. The 129 * name of this getter or setter method is the prefix '__get__' or '__set__' plus 130 * the name of this property. 131 * 132 * @return the name of this property 133 */ 134 public function getName(Void):String { 135 return name; 136 } 137 138 /** 139 * Returns the full name of this property. 140 * 141 * <p>The full name is the fully qualified name of the declaring type plus the name 142 * of this property. 143 * 144 * @return the full name of this property 145 */ 146 public function getFullName(Void):String { 147 if (declaringType.getFullName()) { 148 return declaringType.getFullName() + "." + name; 149 } 150 return name; 151 } 152 153 /** 154 * Returns the setter method of this property. 155 * 156 * <p>The setter method of a property takes one argument, that is the new value that 157 * shall be assigned to the property. You can invoke it the same as every other method. 158 * 159 * <p>The name of this setter method is the prefix '__set__' plus the name of this 160 * property. 161 * 162 * <p>Property setter methods are also known under the name implicit setters. 163 * 164 * @return the setter method of this property 165 */ 166 public function getSetter(Void):MethodInfo { 167 if (setter.getMethod()) { 168 return setter; 169 } 170 return null; 171 } 172 173 /** 174 * Returns the getter method of this property. 175 * 176 * <p>The getter method of a property takes no arguments, but returns the value of 177 * the property. You can invoke it the same as every other method. 178 * 179 * <p>The name of this getter method is the prefix '__get__' plus the name of this 180 * property. 181 * 182 * <p>Property getter methods are also known under the name implicit getters. 183 * 184 * @return the getter method of the property 185 */ 186 public function getGetter(Void):MethodInfo { 187 if (getter.getMethod()) { 188 return getter; 189 } 190 return null; 191 } 192 193 /** 194 * Returns the type that declares this property. 195 * 196 * <p>At this time interfaces are not allowed to declare properties. The declaring 197 * type is thus allways an instance of type {@link ClassInfo}, a class. 198 * 199 * @return the type that declares this property 200 */ 201 public function getDeclaringType(Void):TypeInfo { 202 return declaringType; 203 } 204 205 /** 206 * Returns whether this property is writable. 207 * 208 * <p>This property is writable when its setter is not {@code null}. 209 * 210 * @return {@code true} if this property is writable else {@code false} 211 */ 212 public function isWritable(Void):Boolean { 213 return (getSetter() != null); 214 } 215 216 /** 217 * Returns whether this property is readable. 218 * 219 * <p>This property is readable when its getter is not {@code null}. 220 * 221 * @return {@code true} when this property is readable else {@code false} 222 */ 223 public function isReadable(Void):Boolean { 224 return (getGetter() != null); 225 } 226 227 /** 228 * Returns whether this property is static or not. 229 * 230 * <p>Static properties are properties per type. 231 * 232 * <p>Non-Static properties are properties per instance. 233 * 234 * @return {@code true} if this property is static else {@code false} 235 */ 236 public function isStatic(Void):Boolean { 237 return staticFlag; 238 } 239 240 /** 241 * Returns a property info that reflects the current state of this property info. 242 * 243 * @return a snapshot of this property info 244 */ 245 public function snapshot(Void):PropertyInfo { 246 var setter:Function = null; 247 if (getSetter()) setter = getSetter().getMethod(); 248 var getter:Function = null; 249 if (getGetter()) getter = getGetter().getMethod(); 250 return new PropertyInfo(name, declaringType, staticFlag, setter, getter); 251 } 252 253 /** 254 * Returns the string representation of this property. 255 * 256 * <p>The string representation is obtained via the stringifier returned by the 257 * static {@link #getStringifier} method. 258 * 259 * @return the string representation of this property 260 */ 261 public function toString():String { 262 return getStringifier().execute(this); 263 } 264 265 }