@SuppressWarnings("unchecked") static Object bindInternal( String name, Class clazz, Type type, Annotation[] annotations, Map<String, String[]> params, String suffix, String[] profiles) { try { Logger.trace("bindInternal: name [" + name + "] suffix [" + suffix + "]"); String[] value = params.get(name + suffix); Logger.trace("bindInternal: value [" + value + "]"); Logger.trace("bindInternal: profile [" + Utils.join(profiles, ",") + "]"); // Let see if we have a BindAs annotation and a separator. If so, we need to split the values // Look up for the BindAs annotation. Extract the profile if there is any. // TODO: Move me somewhere else? if (annotations != null) { for (Annotation annotation : annotations) { if ((clazz.isArray() || Collection.class.isAssignableFrom(clazz)) && value != null && value.length > 0 && annotation.annotationType().equals(As.class)) { As as = ((As) annotation); final String separator = as.value()[0]; value = value[0].split(separator); } if (annotation.annotationType().equals(NoBinding.class)) { NoBinding bind = ((NoBinding) annotation); String[] localUnbindProfiles = bind.value(); Logger.trace( "bindInternal: localUnbindProfiles [" + Utils.join(localUnbindProfiles, ",") + "]"); if (localUnbindProfiles != null && contains(profiles, localUnbindProfiles)) { return NO_BINDING; } } } } // Arrays types // The array condition is not so nice... We should find another way of doing this.... if (clazz.isArray() && (clazz != byte[].class && clazz != byte[][].class && clazz != File[].class && clazz != Upload[].class)) { if (value == null) { value = params.get(name + suffix + "[]"); } if (value == null) { return MISSING; } Object r = Array.newInstance(clazz.getComponentType(), value.length); for (int i = 0; i <= value.length; i++) { try { Array.set(r, i, directBind(name, annotations, value[i], clazz.getComponentType())); } catch (Exception e) { // ?? One item was bad } } return r; } // Enums if (Enum.class.isAssignableFrom(clazz)) { if (value == null || value.length == 0) { return MISSING; } else if (StringUtils.isEmpty(value[0])) { return null; } return Enum.valueOf(clazz, value[0]); } // Map if (Map.class.isAssignableFrom(clazz)) { Class keyClass = String.class; Class valueClass = String.class; if (type instanceof ParameterizedType) { keyClass = (Class) ((ParameterizedType) type).getActualTypeArguments()[0]; valueClass = (Class) ((ParameterizedType) type).getActualTypeArguments()[1]; } // Special case Map<String, String> // Multivalues composite params are binded to a Map<String, String> // see http://play.lighthouseapp.com/projects/57987/tickets/443 if (keyClass == String.class && valueClass == String.class && isComposite(name, params)) { Map<String, String> stringMap = Utils.filterParams(params, name); if (stringMap.size() > 0) return stringMap; } // Search for all params Map<Object, Object> r = new HashMap<Object, Object>(); for (String param : params.keySet()) { Pattern p = Pattern.compile("^" + name + suffix + "\\[([^\\]]+)\\](.*)$"); Matcher m = p.matcher(param); if (m.matches()) { String key = m.group(1); value = params.get(param); Map<String, String[]> tP = new HashMap<String, String[]>(); tP.put("key", new String[] {key}); Object oKey = bindInternal("key", keyClass, keyClass, annotations, tP, "", value); if (oKey != MISSING) { if (isComposite(name + suffix + "[" + key + "]", params)) { BeanWrapper beanWrapper = getBeanWrapper(valueClass); Object oValue = beanWrapper.bind( "", type, params, name + suffix + "[" + key + "]", annotations); r.put(oKey, oValue); } else { tP = new HashMap<String, String[]>(); tP.put("value", params.get(name + suffix + "[" + key + "]")); Object oValue = bindInternal("value", valueClass, valueClass, annotations, tP, "", value); if (oValue != MISSING) { r.put(oKey, oValue); } else { r.put(oKey, null); } } } } } return r; } // Collections types if (Collection.class.isAssignableFrom(clazz)) { if (clazz.isInterface()) { if (clazz.equals(List.class)) { clazz = ArrayList.class; } if (clazz.equals(Set.class)) { clazz = HashSet.class; } if (clazz.equals(SortedSet.class)) { clazz = TreeSet.class; } } Collection r = (Collection) clazz.newInstance(); Class componentClass = String.class; if (type instanceof ParameterizedType) { componentClass = (Class) ((ParameterizedType) type).getActualTypeArguments()[0]; } // Create a an array of the component class if (value != null) { Object customArray = Array.newInstance(componentClass, value.length); // custom types for (Class<?> c : supportedTypes.keySet()) { if (c.isAssignableFrom(customArray.getClass())) { Object[] ar = (Object[]) supportedTypes .get(c) .bind("value", annotations, name, customArray.getClass(), null); List l = Arrays.asList(ar); if (clazz.equals(HashSet.class)) { return new HashSet(l); } else if (clazz.equals(TreeSet.class)) { return new TreeSet(l); } return l; } } } if (value == null) { value = params.get(name + suffix + "[]"); if (value == null && r instanceof List) { for (String param : params.keySet()) { Pattern p = Pattern.compile("^" + escape(name + suffix) + "\\[([0-9]+)\\](.*)$"); Matcher m = p.matcher(param); if (m.matches()) { int key = Integer.parseInt(m.group(1)); while (((List<?>) r).size() <= key) { ((List<?>) r).add(null); } if (isComposite(name + suffix + "[" + key + "]", params)) { BeanWrapper beanWrapper = getBeanWrapper(componentClass); Object oValue = beanWrapper.bind( "", type, params, name + suffix + "[" + key + "]", annotations); ((List) r).set(key, oValue); } else { Map<String, String[]> tP = new HashMap<String, String[]>(); tP.put("value", params.get(name + suffix + "[" + key + "]")); Object oValue = bindInternal( "value", componentClass, componentClass, annotations, tP, "", value); if (oValue != MISSING) { ((List) r).set(key, oValue); } } } } return r.isEmpty() ? MISSING : r; } } if (value == null) { return MISSING; } for (String v : value) { try { r.add(directBind(name, annotations, v, componentClass)); } catch (Exception e) { // ?? One item was bad Logger.debug(e, "error:"); } } return r; } // Assume a Bean if isComposite Logger.trace( "bindInternal: class [" + clazz + "] name [" + name + "] annotation [" + Utils.join(annotations, " ") + "] isComposite [" + isComposite(name + suffix, params) + "]"); if (isComposite(name + suffix, params)) { BeanWrapper beanWrapper = getBeanWrapper(clazz); return beanWrapper.bind(name, type, params, suffix, annotations); } // Simple types if (value == null || value.length == 0) { return MISSING; } return directBind(name, annotations, value[0], clazz, type); } catch (Exception e) { Validation.addError(name + suffix, "validation.invalid"); return MISSING; } }
public static Object bind( String name, Class<?> clazz, Type type, Annotation[] annotations, Map<String, String[]> params, Object o, Method method, int parameterIndex) { Logger.trace("bind: name [" + name + "] annotation [" + Utils.join(annotations, " ") + "] "); Object result = null; // Let a chance to plugins to bind this object for (PlayPlugin plugin : Play.plugins) { result = plugin.bind(name, clazz, type, annotations, params); if (result != null) { return result; } } String[] profiles = null; if (annotations != null) { for (Annotation annotation : annotations) { if (annotation.annotationType().equals(As.class)) { As as = ((As) annotation); profiles = as.value(); } if (annotation.annotationType().equals(NoBinding.class)) { NoBinding bind = ((NoBinding) annotation); profiles = bind.value(); } } } result = bindInternal(name, clazz, type, annotations, params, "", profiles); if (result == MISSING) { // Try the scala default if (o != null && parameterIndex > 0) { try { Method defaultMethod = method .getDeclaringClass() .getDeclaredMethod(method.getName() + "$default$" + parameterIndex); return defaultMethod.invoke(o); } catch (NoSuchMethodException e) { // } catch (Exception e) { throw new UnexpectedException(e); } } if (clazz.equals(boolean.class)) { return false; } if (clazz.equals(int.class)) { return 0; } if (clazz.equals(long.class)) { return 0; } if (clazz.equals(double.class)) { return 0; } if (clazz.equals(short.class)) { return 0; } if (clazz.equals(byte.class)) { return 0; } if (clazz.equals(char.class)) { return ' '; } return null; } return result; }