1 16 package com.google.gwt.dev.shell; 17 18 import com.google.gwt.core.ext.TreeLogger; 19 import com.google.gwt.dev.util.TypeInfo; 20 21 import java.lang.reflect.Constructor ; 22 import java.lang.reflect.Field ; 23 import java.lang.reflect.InvocationTargetException ; 24 25 29 public class JsValueGlue { 30 public static final String JSO_CLASS = "com.google.gwt.core.client.JavaScriptObject"; 31 32 41 public static Object createJavaScriptObject(JsValue value, Class type) { 42 try { 43 if (!value.isJavaScriptObject()) { 45 throw new RuntimeException ( 46 "Only Object type JavaScript objects can be made into JavaScriptObject"); 47 } 48 49 50 Class jsoType = getJavaScriptObjectSuperclass(type); 51 if (jsoType == null) { 52 throw new RuntimeException ("Requested type " + type.getName() 53 + " not a subclass of JavaScriptObject"); 54 } 55 56 57 Constructor ctor = type.getDeclaredConstructor(new Class [] {}); 58 ctor.setAccessible(true); 59 Object jso = ctor.newInstance(new Object [] {}); 60 61 62 Field referenceField = jsoType.getDeclaredField("hostedModeReference"); 63 referenceField.setAccessible(true); 64 referenceField.set(jso, value); 65 return jso; 66 } catch (InstantiationException e) { 67 throw new RuntimeException ("Error creating JavaScript object", e); 68 } catch (IllegalAccessException e) { 69 throw new RuntimeException ("Error creating JavaScript object", e); 70 } catch (SecurityException e) { 71 throw new RuntimeException ("Error creating JavaScript object", e); 72 } catch (NoSuchFieldException e) { 73 throw new RuntimeException ("Error creating JavaScript object", e); 74 } catch (NoSuchMethodException e) { 75 throw new RuntimeException ("Error creating JavaScript object", e); 76 } catch (IllegalArgumentException e) { 77 throw new RuntimeException ("Error creating JavaScript object", e); 78 } catch (InvocationTargetException e) { 79 throw new RuntimeException ("Error creating JavaScript object", e); 80 } 81 } 82 83 94 public static Object get(JsValue value, Class type, String msgPrefix) { 95 double doubleVal; 96 if (value.isNull()) { 97 return null; 98 } 99 if (value.isUndefined()) { 100 throw new HostedModeException(msgPrefix 102 + ": JavaScript undefined, expected " + type.getName()); 103 } 104 if (value.isWrappedJavaObject()) { 105 Object origObject = value.getWrappedJavaObject(); 106 if (!type.isAssignableFrom(origObject.getClass())) { 107 throw new HostedModeException(msgPrefix + ": Java object of type " 108 + origObject.getClass().getName() + ", expected " + type.getName()); 109 } 110 return origObject; 111 } 112 if (getJavaScriptObjectSuperclass(type) != null) { 113 if (!value.isJavaScriptObject()) { 114 throw new HostedModeException(msgPrefix + ": JS object of type " 115 + value.getTypeString() + ", expected " + type.getName()); 116 } 117 return createJavaScriptObject(value, type); 118 } 119 switch (TypeInfo.classifyType(type)) { 120 case TypeInfo.TYPE_WRAP_BOOLEAN: 121 case TypeInfo.TYPE_PRIM_BOOLEAN: 122 if (!value.isBoolean()) { 123 throw new HostedModeException(msgPrefix + ": JS value of type " 124 + value.getTypeString() + ", expected boolean"); 125 } 126 return Boolean.valueOf(value.getBoolean()); 127 128 case TypeInfo.TYPE_WRAP_BYTE: 129 case TypeInfo.TYPE_PRIM_BYTE: 130 return new Byte ((byte) getIntRange(value, Byte.MIN_VALUE, 131 Byte.MAX_VALUE, "byte", msgPrefix)); 132 133 case TypeInfo.TYPE_WRAP_CHAR: 134 case TypeInfo.TYPE_PRIM_CHAR: 135 return new Character ((char) getIntRange(value, Character.MIN_VALUE, 136 Character.MAX_VALUE, "char", msgPrefix)); 137 138 case TypeInfo.TYPE_WRAP_DOUBLE: 139 case TypeInfo.TYPE_PRIM_DOUBLE: 140 if (!value.isNumber()) { 141 throw new HostedModeException(msgPrefix + ": JS value of type " 142 + value.getTypeString() + ", expected double"); 143 } 144 return new Double (value.getNumber()); 145 146 case TypeInfo.TYPE_WRAP_FLOAT: 147 case TypeInfo.TYPE_PRIM_FLOAT: 148 if (!value.isNumber()) { 149 throw new HostedModeException(msgPrefix + ": JS value of type " 150 + value.getTypeString() + ", expected float"); 151 } 152 doubleVal = value.getNumber(); 153 154 if ((float)(doubleVal - Float.MIN_VALUE) == 0.0f) { 161 doubleVal = Float.MIN_VALUE; 162 } 163 164 float floatVal = (float)doubleVal; 165 if (Float.isInfinite(floatVal) && !Double.isInfinite(doubleVal)) { 166 throw new HostedModeException(msgPrefix + ": JS value " + doubleVal 171 + " out of range for a float"); 172 } 173 return new Float (floatVal); 174 175 case TypeInfo.TYPE_WRAP_INT: 176 case TypeInfo.TYPE_PRIM_INT: 177 return new Integer (getIntRange(value, Integer.MIN_VALUE, 178 Integer.MAX_VALUE, "int", msgPrefix)); 179 180 case TypeInfo.TYPE_WRAP_LONG: 181 case TypeInfo.TYPE_PRIM_LONG: 182 if (!value.isNumber()) { 183 throw new HostedModeException(msgPrefix + ": JS value of type " 184 + value.getTypeString() + ", expected long"); 185 } 186 doubleVal = value.getNumber(); 187 if (doubleVal < Long.MIN_VALUE || doubleVal > Long.MAX_VALUE) { 188 throw new HostedModeException(msgPrefix + ": JS double value " + doubleVal 189 + " out of range for a long"); 190 } 191 long longVal = (long) doubleVal; 193 if (doubleVal != longVal) { 194 ModuleSpace.getLogger().log(TreeLogger.WARN, msgPrefix 196 + ": Loss of precision converting double to long", null); 197 } 198 return new Long (longVal); 199 200 case TypeInfo.TYPE_WRAP_SHORT: 201 case TypeInfo.TYPE_PRIM_SHORT: 202 return new Short ((short) getIntRange(value, Short.MIN_VALUE, 203 Short.MAX_VALUE, "short", msgPrefix)); 204 205 case TypeInfo.TYPE_WRAP_STRING: 206 if (!value.isString()) { 207 throw new HostedModeException(msgPrefix + ": JS value of type " 208 + value.getTypeString() + ", expected string"); 209 } 210 return value.getString(); 211 212 case TypeInfo.TYPE_USER: 213 if (value.isString()) { 214 return value.getString(); 215 } 216 break; 218 } 219 220 throw new IllegalArgumentException (msgPrefix + ": Cannot convert to type " 222 + TypeInfo.getSourceRepresentation(type) + " from " 223 + value.getTypeString()); 224 } 225 226 236 public static JsValue getUnderlyingObject(Object jso) { 237 try { 238 242 Class type = getJavaScriptObjectSuperclass(jso.getClass()); 243 244 if (type == null) { 245 throw new HostedModeException( 246 "Underlying JSO not a subclass of JavaScriptObject"); 247 } 248 249 Field referenceField = type.getDeclaredField("hostedModeReference"); 250 referenceField.setAccessible(true); 251 return (JsValue) referenceField.get(jso); 252 } catch (IllegalAccessException e) { 253 throw new RuntimeException ("Error reading handle", e); 254 } catch (SecurityException e) { 255 throw new RuntimeException ("Error reading handle", e); 256 } catch (NoSuchFieldException e) { 257 throw new RuntimeException ("Error reading handle", e); 258 } 259 } 260 261 268 public static void set(JsValue value, CompilingClassLoader cl, Class type, 269 Object obj) { 270 if (obj == null) { 271 value.setNull(); 272 } else if (type.equals(String .class)) { 273 value.setString((String ) obj); 274 } else if (type.equals(boolean.class)) { 275 value.setBoolean(((Boolean ) obj).booleanValue()); 276 } else if (type.equals(short.class)) { 277 value.setInt(((Short ) obj).shortValue()); 278 } else if (type.equals(int.class)) { 279 value.setInt(((Integer ) obj).intValue()); 280 } else if (type.equals(byte.class)) { 281 value.setInt(((Byte ) obj).byteValue()); 282 } else if (type.equals(char.class)) { 283 value.setInt(((Character ) obj).charValue()); 284 } else if (type.equals(long.class)) { 285 long longVal = ((Long ) obj).longValue(); 286 double doubleVal = longVal; 287 if ((long) doubleVal != longVal) { 288 ModuleSpace.getLogger().log(TreeLogger.WARN, 290 "Loss of precision converting long to double", null); 291 } 292 value.setDouble(doubleVal); 293 } else if (type.equals(float.class)) { 294 value.setDouble(((Float ) obj).floatValue()); 295 } else if (type.equals(double.class)) { 296 value.setDouble(((Double ) obj).doubleValue()); 297 } else { 298 try { 300 Class jso = Class.forName(JSO_CLASS, true, cl); 301 if (jso.isAssignableFrom(type) && jso.isAssignableFrom(obj.getClass())) { 302 JsValue jsObject = getUnderlyingObject(obj); 303 value.setValue(jsObject); 304 return; 305 } 306 } catch (ClassNotFoundException e) { 307 } 310 311 if (!type.isAssignableFrom(obj.getClass())) { 313 throw new HostedModeException("object is of type " 314 + obj.getClass().getName() + ", expected " + type.getName()); 315 } 316 value.setWrappedJavaObject(cl, obj); 317 } 318 } 319 320 private static int getIntRange(JsValue value, int low, int high, 321 String typeName, String msgPrefix) { 322 int intVal; 323 if (value.isInt()) { 324 intVal = value.getInt(); 325 if (intVal < low || intVal > high) { 326 throw new HostedModeException(msgPrefix + ": JS int value " + intVal 327 + " out of range for a " + typeName); 328 } 329 } else if (value.isNumber()) { 330 double doubleVal = value.getNumber(); 331 if (doubleVal < low || doubleVal > high) { 332 throw new HostedModeException(msgPrefix + ": JS double value " 333 + doubleVal + " out of range for a " + typeName); 334 } 335 intVal = (int) doubleVal; 336 if (intVal != doubleVal) { 337 ModuleSpace.getLogger().log(TreeLogger.WARN, msgPrefix 338 + ": Rounding double to int for " + typeName, null); 339 } 340 } else { 341 throw new HostedModeException(msgPrefix + ": JS value of type " 342 + value.getTypeString() + ", expected " + typeName); 343 } 344 return intVal; 345 } 346 347 357 private static Class getJavaScriptObjectSuperclass(Class type) { 358 while (type != null && !type.getName().equals(JSO_CLASS)) { 359 type = type.getSuperclass(); 360 } 361 return type; 362 } 363 } 364 | Popular Tags |