public static <T> T createFromArg(Class<T> clz, Object value) { if (value == null) { return null; } ClassMeta meta = ClassMeta.classMeta(clz); List<ConstructorAccess> constructors = meta.oneArgumentConstructors(); if (constructors.size() == 0) { return null; } else if (constructors.size() == 1) { ConstructorAccess constructorAccess = constructors.get(0); Class<?> arg1Type = constructorAccess.parameterTypes()[0]; if (arg1Type.isInstance(value)) { return (T) constructorAccess.create(value); } else { return (T) constructorAccess.create(coerce(arg1Type, value)); } } else { for (ConstructorAccess c : constructors) { Class<?> arg1Type = c.parameterTypes()[0]; if (arg1Type.isInstance(value)) { return (T) c.create(value); } } for (ConstructorAccess c : constructors) { Class<?> arg1Type = c.parameterTypes()[0]; if (arg1Type.isAssignableFrom(value.getClass())) { return (T) c.create(value); } } } return null; }
/** * @param c Class instance * @return ClassMeta which contains fields of class and customer write/read methods if they exist. * The results are cached internally for performance when called again with same Class. */ static ClassMeta getDeepDeclaredFields(Class c) { ClassMeta classInfo = _classMetaCache.get(c.getName()); if (classInfo != null) { return classInfo; } classInfo = new ClassMeta(); Class curr = c; while (curr != null) { try { Field[] local = curr.getDeclaredFields(); for (Field field : local) { if (!field.isAccessible()) { try { field.setAccessible(true); } catch (Exception ignored) { } } if ((field.getModifiers() & Modifier.STATIC) == 0) { // speed up: do not process static fields. classInfo.put(field.getName(), field); } } } catch (ThreadDeath t) { throw t; } catch (Throwable ignored) { } curr = curr.getSuperclass(); } try { classInfo._writeMethod = c.getDeclaredMethod("_writeJson", new Class[] {Writer.class}); } catch (Exception ignored) { } try { classInfo._readMethod = c.getDeclaredMethod("_readJson", new Class[] {Map.class}); } catch (Exception ignored) { } _classMetaCache.put(c.getName(), classInfo); return classInfo; }
private void traceFields(LinkedList<Object> stack, Object obj) { ClassMeta fields = getDeepDeclaredFields(obj.getClass()); for (Field field : fields.values()) { try { if (isPrimitiveWrapper( field .getType())) { // speed up: primitives & primitive wrappers cannot reference another // object continue; } Object o = field.get(obj); if (o != null) { stack.addFirst(o); } } catch (IllegalAccessException ignored) { } } }
private void hasOneInstantiatorDefinitionWithEmptyConstructorOnImpl( ClassMeta<?> classMeta, Class<?> impl) throws NoSuchMethodException { assertTrue(classMeta instanceof ArrayClassMeta); final List<InstantiatorDefinition> instantiatorDefinitions = classMeta.getInstantiatorDefinitions(); assertEquals(1, instantiatorDefinitions.size()); final ExecutableInstantiatorDefinition instantiatorDefinition = (ExecutableInstantiatorDefinition) instantiatorDefinitions.get(0); assertEquals(0, instantiatorDefinition.getParameters().length); assertEquals(impl.getDeclaredConstructor(), instantiatorDefinition.getExecutable()); }
public static <T> T coerceWithFlag( TypeType coerceTo, Class<T> clz, boolean[] flag, Object value) { flag[0] = true; if (value == null) { return null; } if (clz.isInstance(value)) { return (T) value; } switch (coerceTo) { case STRING: case CHAR_SEQUENCE: return (T) value.toString(); case INT: case INTEGER_WRAPPER: Integer i = toInt(value); if (i == Integer.MIN_VALUE) { flag[0] = false; } return (T) i; case SHORT: case SHORT_WRAPPER: Short s = toShort(value); if (s == Short.MIN_VALUE) { flag[0] = false; } return (T) s; case BYTE: case BYTE_WRAPPER: Byte by = toByte(value); if (by == Byte.MIN_VALUE) { flag[0] = false; } return (T) by; case CHAR: case CHAR_WRAPPER: Character ch = toChar(value); if (ch == (char) 0) { flag[0] = false; } return (T) ch; case LONG: case LONG_WRAPPER: Long l = toLong(value); if (l == Long.MIN_VALUE) { flag[0] = false; } return (T) l; case DOUBLE: case DOUBLE_WRAPPER: Double d = toDouble(value); if (d == Double.MIN_VALUE) { flag[0] = false; } return (T) d; case FLOAT: case FLOAT_WRAPPER: Float f = toFloat(value); if (f == Float.MIN_VALUE) { flag[0] = false; } return (T) f; case DATE: return (T) toDate(value); case BIG_DECIMAL: return (T) toBigDecimal(value); case BIG_INT: return (T) toBigInteger(value); case CALENDAR: return (T) toCalendar(toDate(value)); case BOOLEAN: case BOOLEAN_WRAPPER: return (T) (Boolean) toBooleanOrDie(value); case MAP: return (T) toMap(value); case ARRAY: case ARRAY_INT: case ARRAY_BYTE: case ARRAY_SHORT: case ARRAY_FLOAT: case ARRAY_DOUBLE: case ARRAY_LONG: case ARRAY_STRING: case ARRAY_OBJECT: return toPrimitiveArrayIfPossible(clz, value); case COLLECTION: return toCollection(clz, value); case INSTANCE: if (value instanceof Map) { return MapObjectConversion.fromMap((Map<String, Object>) value, clz); } else if (value instanceof List) { return MapObjectConversion.fromList((List<Object>) value, clz); } else if (clz.isInstance(value)) { return (T) value; } else { ClassMeta meta = ClassMeta.classMeta(clz); List<ConstructorAccess> constructors = meta.oneArgumentConstructors(); if (constructors.size() == 0) { return null; } else if (constructors.size() == 1) { ConstructorAccess constructorAccess = constructors.get(0); Class<?> arg1Type = constructorAccess.parameterTypes()[0]; if (arg1Type.isInstance(value)) { return (T) constructorAccess.create(value); } else { return (T) constructorAccess.create(coerce(arg1Type, value)); } } else { for (ConstructorAccess c : constructors) { Class<?> arg1Type = c.parameterTypes()[0]; if (arg1Type.isInstance(value)) { return (T) c.create(value); } } for (ConstructorAccess c : constructors) { Class<?> arg1Type = c.parameterTypes()[0]; if (arg1Type.isAssignableFrom(value.getClass())) { return (T) c.create(value); } } flag[0] = false; break; } } case ENUM: return (T) toEnum((Class<? extends Enum>) clz, value); case CLASS: return (T) toClass(value); case TIME_ZONE: return (T) toTimeZone(flag, value); case UUID: return (T) toUUID(flag, value); case CURRENCY: return (T) toCurrency(value); case OBJECT: return (T) value; default: flag[0] = false; break; } return null; }
public void visitFieldInsn(int opcode, String owner, String name, String desc) { if (transientAnnotation) { // The whole method is left as is super.visitFieldInsn(opcode, owner, name, desc); return; } if (opcode == Opcodes.GETSTATIC || opcode == Opcodes.PUTSTATIC) { if (meta.isLog(3)) { meta.log(" ... info: skip static field " + owner + " " + name + " in " + methodDescription); } super.visitFieldInsn(opcode, owner, name, desc); return; } if (isNonPersistentField(owner, name)) { if (meta.isLog(3)) { meta.log( " ... info: non-persistent field " + owner + " " + name + " in " + methodDescription); } super.visitFieldInsn(opcode, owner, name, desc); return; } // every basicField has a special set of field interception methods if (opcode == Opcodes.GETFIELD) { String methodName = "_ebean_get_" + name; String methodDesc = "()" + desc; if (meta.isLog(4)) { meta.log( "GETFIELD method:" + methodDescription + " field:" + name + " > " + methodName + " " + methodDesc); } super.visitMethodInsn(INVOKEVIRTUAL, className, methodName, methodDesc, false); } else if (opcode == Opcodes.PUTFIELD) { String methodName = "_ebean_set_" + name; String methodDesc = "(" + desc + ")V"; if (meta.isLog(4)) { meta.log( "PUTFIELD method:" + methodDescription + " field:" + name + " > " + methodName + " " + methodDesc); } super.visitMethodInsn(INVOKEVIRTUAL, className, methodName, methodDesc, false); } else { meta.log( "Warning adapting method:" + methodDescription + "; unexpected static access to a persistent field?? " + name + " opCode not GETFIELD or PUTFIELD?? opCode:" + opcode + ""); super.visitFieldInsn(opcode, owner, name, desc); } }
public MethodFieldAdapter(MethodVisitor mv, ClassMeta meta, String methodDescription) { super(Opcodes.ASM5, mv); this.meta = meta; this.className = meta.getClassName(); this.methodDescription = methodDescription; }
/** Return true if the field is non-persistent and hence should not be intercepted. */ private boolean isNonPersistentField(String owner, String name) { return !isSameOwner(owner) || !meta.isFieldPersistent(name); }
/** * String, Date, and Class have been written before calling this method, strictly for performance. * * @param obj Object to be written in JSON format * @param showType boolean true means show the "@type" field, false eliminates it. Many times the * type can be dropped because it can be inferred from the field or array type. * @throws IOException if an error occurs writing to the output stream. */ private void writeObject(Object obj, boolean showType) throws IOException { if (obj instanceof String) { writeJsonUtf8String((String) obj); return; } else if (obj.getClass().equals(Date.class)) { writeDate(obj, showType); return; } else if (obj instanceof Class) { writeClass(obj, showType); return; } if (writeOptionalReference(obj)) { return; } if (obj instanceof Calendar) { Calendar cal = (Calendar) obj; _dateFormat.setTimeZone(cal.getTimeZone()); String date = _dateFormat.format(cal.getTime()); writeSpecial(obj, showType, date); return; } else if (obj instanceof BigDecimal) { writeSpecial(obj, showType, ((BigDecimal) obj).toPlainString()); return; } else if (obj instanceof BigInteger) { writeSpecial(obj, showType, obj.toString()); return; } else if (obj instanceof java.sql.Date) { writeSpecial(obj, showType, obj.toString()); return; } _out.write('{'); boolean referenced = _objsReferenced.containsKey(obj); if (referenced) { writeId(getId(obj)); } ClassMeta classInfo = getDeepDeclaredFields(obj.getClass()); if (classInfo._writeMethod != null) { // Must show type when class has custom _writeJson() method on it. // The JsonReader uses this to know it is dealing with an object // that has custom json io methods on it. showType = true; } if (referenced && showType) { _out.write(','); } if (showType) { writeType(obj); } boolean first = !showType; if (referenced && !showType) { first = false; } if (classInfo._writeMethod == null) { for (Field field : classInfo.values()) { if (_prettyMode && (field.getModifiers() & Modifier.TRANSIENT) != 0) { // Skip transient fields when in 'prettyMode' continue; } if (first) { first = false; } else { _out.write(','); } writeJsonUtf8String(field.getName()); _out.write(':'); Object o; try { o = field.get(obj); } catch (IllegalAccessException e) { o = null; } if (o == null) { // don't quote null _out.write("null"); continue; } Class type = field.getType(); boolean forceType = o.getClass() != type; // If types are not exactly the same, write "@type" field if (isPrimitiveWrapper(type)) { writePrimitive(o); } else { writeImpl(o, forceType); } } } else { // Invoke custom _writeJson() method. _out.write(','); try { classInfo._writeMethod.invoke(obj, _out); } catch (Exception e) { throw new IOException("Error invoking " + obj.getClass() + "._jsonWrite()", e); } } _out.write('}'); }