/** * A helper method that returns the parsed default value of a given NamedParameter. * * @return null or an empty set if there is no default value, the default value (or set of values) * otherwise. * @throws ClassHierarchyException if a default value was specified, but could not be parsed, or * if a set of values were specified for a non-set parameter. */ @SuppressWarnings("unchecked") @Override public <T> T parseDefaultValue(final NamedParameterNode<T> name) { final String[] vals = name.getDefaultInstanceAsStrings(); final T[] ret = (T[]) new Object[vals.length]; for (int i = 0; i < vals.length; i++) { final String val = vals[i]; try { ret[i] = parse(name, val); } catch (final ParseException e) { throw new ClassHierarchyException("Could not parse default value", e); } } if (name.isSet()) { return (T) new HashSet<T>(Arrays.asList(ret)); } else if (name.isList()) { return (T) new ArrayList<T>(Arrays.asList(ret)); } else { if (ret.length == 0) { return null; } else if (ret.length == 1) { return ret[0]; } else { throw new IllegalStateException( "Multiple defaults for non-set named parameter! " + name.getFullName()); } } }
private Node register(final String s) { final Class<?> c; try { c = classForName(s); } catch (final ClassNotFoundException e1) { return null; } try { final Node n = getAlreadyBoundNode(c); return n; } catch (final NameResolutionException e) { // node not bound yet } // First, walk up the class hierarchy, registering all out parents. This // can't be loopy. if (c.getSuperclass() != null) { register(ReflectionUtilities.getFullName(c.getSuperclass())); } for (final Class<?> i : c.getInterfaces()) { register(ReflectionUtilities.getFullName(i)); } // Now, we'd like to register our enclosing classes. This turns out to be // safe. // Thankfully, Java doesn't allow: // class A implements A.B { class B { } } // It also doesn't allow cycles such as: // class A implements B.BB { interface AA { } } // class B implements A.AA { interface BB { } } // So, even though grafting arbitrary DAGs together can give us cycles, Java // seems // to have our back on this one. final Class<?> enclosing = c.getEnclosingClass(); if (enclosing != null) { register(ReflectionUtilities.getFullName(enclosing)); } // Now register the class. This has to be after the above so we know our // parents (superclasses and enclosing packages) are already registered. final Node n = registerClass(c); // Finally, do things that might introduce cycles that invlove c. // This has to be below registerClass, which ensures that any cycles // this stuff introduces are broken. for (final Class<?> innerClass : c.getDeclaredClasses()) { register(ReflectionUtilities.getFullName(innerClass)); } if (n instanceof ClassNode) { final ClassNode<?> cls = (ClassNode<?>) n; for (final ConstructorDef<?> def : cls.getInjectableConstructors()) { for (final ConstructorArg arg : def.getArgs()) { register(arg.getType()); if (arg.getNamedParameterName() != null) { final NamedParameterNode<?> np = (NamedParameterNode<?>) register(arg.getNamedParameterName()); try { // TODO: When handling sets, need to track target of generic parameter, and check the // type here! if (!np.isSet() && !np.isList() && !ReflectionUtilities.isCoercable( classForName(arg.getType()), classForName(np.getFullArgName()))) { throw new ClassHierarchyException( "Named parameter type mismatch in " + cls.getFullName() + ". Constructor expects a " + arg.getType() + " but " + np.getName() + " is a " + np.getFullArgName()); } } catch (final ClassNotFoundException e) { throw new ClassHierarchyException( "Constructor refers to unknown class " + arg.getType(), e); } } } } } else if (n instanceof NamedParameterNode) { final NamedParameterNode<?> np = (NamedParameterNode<?>) n; register(np.getFullArgName()); } return n; }