private ValueType typeOf(final Object value, final FieldBinding binding) throws BindException { if (value == null) { return ValueType.NIL; } final Class<?> cls = value.getClass(); ValueType type = typeCache.get(cls); if (type == null) { if (binding != null && recipesByClass.containsKey(binding.getFieldType())) { final Mapping<?> recipe = recipesByClass.get(binding.getFieldType()); if (recipe instanceof ArrayMapping) { type = ValueType.ARRAY; } else if (recipe instanceof StructMapping) { type = ValueType.STRUCT; } else { throw new BindException( "Unknown recipe reference type: " + binding.getFieldType() + "\nField: " + binding.getFieldName() + "\nClass: " + cls.getName()); } } else { type = ValueType.typeFor(value); } if (type != null) { typeCache.put(cls, type); } } return type; }
private Field findField(final FieldBinding binding, final Class<?> parentCls) throws BindException { Field field = null; Class<?> fieldOwner = parentCls; while (field == null && fieldOwner != null) { try { field = fieldOwner.getDeclaredField(binding.getFieldName()); } catch (final NoSuchFieldException e) { // TODO: log this to debug log-level. field = null; fieldOwner = fieldOwner.getSuperclass(); } } if (field == null) { throw new BindException( "Cannot find field: " + binding.getFieldName() + " in class (or parent classes of): " + parentCls.getName()); } return field; }
private Object fireValueEvents( final FieldBinding binding, final Object parent, final XmlRpcListener listener, EventCallback before, EventCallback after) throws XmlRpcException { final Class<?> parentCls = parent.getClass(); try { final Field field = findField(binding, parentCls); field.setAccessible(true); Object value = field.get(parent); if (isSuppressedNull(field, parentCls, value)) { return null; } final ValueType type = typeOf(value, binding); if (before != null) { if (!before.call(value, type)) { return null; } } Converter converter = field.getAnnotation(Converter.class); if (converter == null) { Class<?> fieldType = field.getType(); converter = fieldType.getAnnotation(Converter.class); } if (converter != null) { final ValueBinder vc = XBRBinderInstantiator.newValueUnbinder(converter); vc.generate(listener, value, recipesByClass); } else if (recipesByClass.containsKey(binding.getFieldType())) { if (type == ValueType.ARRAY) { value = fireArrayEvents(binding.getFieldType(), value, listener); } else if (type == ValueType.STRUCT) { value = fireStructEvents(binding.getFieldType(), value, listener); } else { throw new BindException( "Unknown recipe reference type: " + binding.getFieldType() + "\nField: " + binding.getFieldName() + "\nClass: " + parentCls.getName()); } listener.value(value, type); } else { final Contains contains = field.getAnnotation(Contains.class); if (Map.class.isAssignableFrom(binding.getFieldType())) { fireMapEvents(value, binding.getFieldName(), contains, listener); } else if (binding.getFieldType().isArray() || Collection.class.isAssignableFrom(binding.getFieldType())) { fireCollectionEvents(value, binding.getFieldName(), contains, listener); } else { ValueCoercion coercion = type.coercion(); if (coercion == null) { throw new XmlRpcException( "Cannot render {} (type: {}) to string. It has no corresponding coercion, and isn't an @ArrayPart or a @StructPart!"); } value = coercion.toString(value); } listener.value(value, type); } if (after != null) { if (!after.call(value, type)) { return null; } } return value; } catch (final IllegalAccessException e) { throw new BindException( "Cannot retrieve field: " + binding.getFieldName() + " in class: " + parentCls.getName() + "\nError: " + e.getMessage(), e); } }