/** * Set the objects properties to the values in this setter. Iterates through each of the * properties in this setter, searches for a matching setter method for the property, and if * found, calls the setter with this object's property value. Can also insert values from the * attributes themselves, by using the %attributeName% placeholder in the value string. * * @param context Layer's context url * @param attributeValues Attribute values * @param objects Objects to search for matching setter properties, using reflection */ public void setPropertiesFromAttributes(URL context, AVList attributeValues, Object... objects) { Map<String, Method> methods = new HashMap<String, Method>(); Map<Method, Object> methodToObject = new HashMap<Method, Object>(); // create a list of the methods in the objects for (Object object : objects) { for (Method method : object.getClass().getMethods()) { methods.put(method.getName(), method); methodToObject.put(method, object); } } // for each of the properties in this setter for (Entry<String, String> entry : properties.entrySet()) { // search for the setter method for this property String property = entry.getKey(); String methodName = constructSetterName(property); if (!methods.containsKey(methodName)) { String message = "Could not find setter method '" + methodName + "' in class: "; for (Object object : objects) { message += object.getClass() + ", "; } message = message.substring(0, message.length() - 2); Logging.logger().warning(message); continue; } // find out the method's parameters Method setter = methods.get(methodName); Object object = methodToObject.get(setter); Class<?>[] parameters = setter.getParameterTypes(); // get the string value to pass to the method String stringValue = entry.getValue(); stringValue = replaceVariablesWithAttributeValues(stringValue, attributeValues); String[] paramValueStrings = splitPipeSeparatedString(stringValue); if (parameters.length != paramValueStrings.length) { String message = "Setter method '" + methodName + "' in class " + object.getClass() + " doesn't take " + paramValueStrings.length + " parameter(s)"; Logging.logger().severe(message); // Continue on incase this is an overloaded method continue; } Object[] parameterValues = new Object[paramValueStrings.length]; String[] typeOverrides = getTypeOverridesForProperty(property, parameterValues.length); // Convert each parameter value string into a parameter for (int i = 0; i < paramValueStrings.length; i++) { // find out the type to pass to the method Class<?> parameterType = parameters[i]; Class<?> type = parameterType; // check if the type has been overridden (useful if the type above is just 'Object') String typeOverride = typeOverrides[i]; if (!isBlank(typeOverride)) { type = convertTypeToClass(typeOverride); if (type == null) { String message = "Could not find class for type " + type; Logging.logger().severe(message); throw new IllegalArgumentException(message); } else if (!parameterType.isAssignableFrom(type)) { String message = "Setter method '" + methodName + "' in class " + object.getClass() + " parameter type " + parameterType + " not assignable from type " + type; Logging.logger().severe(message); throw new IllegalArgumentException(message); } } // convert the string value to a valid type Object value = convertStringToType(context, paramValueStrings[i], type); if (value == null) { String message = "Error converting '" + paramValueStrings[i] + "' to type " + type; Logging.logger().severe(message); throw new IllegalArgumentException(message); } parameterValues[i] = value; } // invoke the setter with the value try { setter.invoke(object, parameterValues); } catch (Exception e) { String message = "Error invoking '" + methodName + "' in class " + object.getClass() + ": " + e; Logging.logger().severe(message); throw new IllegalArgumentException(message, e); } } }
/** * Convert a string to a certain type, parsing the string if required * * @param context If creating a URL, use this as the URL's context * @param string String to convert * @param type Type to convert to * @return Converted string, or null if failed */ protected static Object convertStringToType(URL context, String string, Class<?> type) { try { if (type.isAssignableFrom(String.class)) { return string; } else if (type.isAssignableFrom(Double.class) || type.isAssignableFrom(double.class)) { return Double.valueOf(string); } else if (type.isAssignableFrom(Integer.class) || type.isAssignableFrom(int.class)) { return Integer.decode(string); } else if (type.isAssignableFrom(Float.class) || type.isAssignableFrom(float.class)) { return Float.valueOf(string); } else if (type.isAssignableFrom(Long.class) || type.isAssignableFrom(long.class)) { return Long.decode(string); } else if (type.isAssignableFrom(Character.class) || type.isAssignableFrom(char.class)) { return string.charAt(0); } else if (type.isAssignableFrom(Byte.class) || type.isAssignableFrom(byte.class)) { return Byte.decode(string); } else if (type.isAssignableFrom(Boolean.class) || type.isAssignableFrom(boolean.class)) { return Boolean.valueOf(string); } else if (type.isAssignableFrom(URL.class)) { try { return new URL(context, string); } catch (MalformedURLException e) { } } else if (type.isAssignableFrom(File.class)) { return new File(string); } else if (type.isAssignableFrom(Color.class)) { int[] ints = splitInts(string); if (ints.length == 1) return new Color(ints[0]); else if (ints.length == 3) return new Color(ints[0], ints[1], ints[2]); else if (ints.length == 4) return new Color(ints[0], ints[1], ints[2], ints[3]); } else if (type.isAssignableFrom(Dimension.class)) { int[] ints = splitInts(string); if (ints.length == 1) return new Dimension(ints[0], ints[0]); else if (ints.length == 2) return new Dimension(ints[0], ints[1]); } else if (type.isAssignableFrom(Point.class)) { int[] ints = splitInts(string); if (ints.length == 1) return new Point(ints[0], ints[0]); else if (ints.length == 2) return new Point(ints[0], ints[1]); } else if (type.isAssignableFrom(Font.class)) { return Font.decode(string); } else if (type.isAssignableFrom(Material.class)) { Color color = null; int[] ints = splitInts(string); if (ints.length == 1) color = new Color(ints[0]); else if (ints.length == 3) color = new Color(ints[0], ints[1], ints[2]); else if (ints.length == 4) color = new Color(ints[0], ints[1], ints[2], ints[3]); if (color != null) return new Material(color); } else if (type.isAssignableFrom(Insets.class)) { int[] ints = splitInts(string); if (ints.length == 4) return new Insets(ints[0], ints[1], ints[2], ints[3]); } } catch (Exception e) { } return null; }