/** * Parse a string, assuming that it is of the type expected by a given NamedParameter. * * <p>This method does not deal with sets; if the NamedParameter is set valued, then the provided * string should correspond to a single member of the set. It is up to the caller to call parse * once for each value that should be parsed as a member of the set. * * @return a non-null reference to the parsed value. */ @Override @SuppressWarnings("unchecked") public <T> T parse(final NamedParameterNode<T> np, final String value) throws ParseException { final ClassNode<T> iface; try { iface = (ClassNode<T>) getNode(np.getFullArgName()); } catch (final NameResolutionException e) { throw new IllegalStateException( "Could not parse validated named parameter argument type. NamedParameter is " + np.getFullName() + " argument type is " + np.getFullArgName()); } Class<?> clazz; String fullName; try { clazz = classForName(iface.getFullName()); fullName = null; } catch (final ClassNotFoundException e) { clazz = null; fullName = iface.getFullName(); } try { if (clazz != null) { return (T) parameterParser.parse(clazz, value); } else { return parameterParser.parse(fullName, value); } } catch (final UnsupportedOperationException e) { try { final Node impl = getNode(value); if (impl instanceof ClassNode && isImplementation(iface, (ClassNode<?>) impl)) { return (T) impl; } throw new ParseException( "Name<" + iface.getFullName() + "> " + np.getFullName() + " cannot take non-subclass " + impl.getFullName(), e); } catch (final NameResolutionException e2) { throw new ParseException( "Name<" + iface.getFullName() + "> " + np.getFullName() + " cannot take non-class " + value, e); } } }
private <T, U> Node buildPathToNode(final Class<U> clazz) throws ClassHierarchyException { final String[] path = clazz.getName().split("\\$"); Node root = namespace; for (int i = 0; i < path.length - 1; i++) { root = root.get(path[i]); } if (root == null) { throw new NullPointerException(); } final Node parent = root; final Type argType = ReflectionUtilities.getNamedParameterTargetOrNull(clazz); if (argType == null) { return JavaNodeFactory.createClassNode(parent, clazz); } else { // checked inside of NamedParameterNode, using reflection. @SuppressWarnings("unchecked") final NamedParameterNode<T> np = JavaNodeFactory.createNamedParameterNode( parent, (Class<? extends Name<T>>) clazz, argType); if (parameterParser.canParse(ReflectionUtilities.getFullName(argType)) && clazz.getAnnotation(NamedParameter.class).default_class() != Void.class) { throw new ClassHierarchyException( "Named parameter " + ReflectionUtilities.getFullName(clazz) + " defines default implementation for parsable type " + ReflectionUtilities.getFullName(argType)); } final String shortName = np.getShortName(); if (shortName != null) { final NamedParameterNode<?> oldNode = shortNames.get(shortName); if (oldNode != null) { if (oldNode.getFullName().equals(np.getFullName())) { throw new IllegalStateException( "Tried to double bind " + oldNode.getFullName() + " to short name " + shortName); } throw new ClassHierarchyException( "Named parameters " + oldNode.getFullName() + " and " + np.getFullName() + " have the same short name: " + shortName); } shortNames.put(shortName, np); } return np; } }
public ClassHierarchyImpl( final URL[] jars, final Class<? extends ExternalConstructor<?>>[] parameterParsers) { this.namespace = JavaNodeFactory.createRootPackageNode(); this.jars = new ArrayList<>(Arrays.asList(jars)); this.loader = new URLClassLoader(jars, this.getClass().getClassLoader()); for (final Class<? extends ExternalConstructor<?>> p : parameterParsers) { try { parameterParser.addParser(p); } catch (final BindException e) { throw new IllegalArgumentException("Could not register parameter parsers", e); } } }