コード例 #1
0
    @Override
    public Object invokeProjection(
        final String resolvedXpath, final Object proxy, final Object[] args) throws Throwable {
      //   final String pathToElement = resolvedXpath.replaceAll("\\[@",
      // "[attribute::").replaceAll("/?@.*", "").replaceAll("\\[attribute::", "[@");
      lastInvocationContext.updateMethodArgs(args);
      final Document document = DOMHelper.getOwnerDocumentFor(node);
      assert document != null;
      final Object valueToSet = args[findIndexOfValue];
      final boolean isMultiValue = isMultiValue(method.getParameterTypes()[findIndexOfValue]);
      // ROOT element update
      if ("/*".equals(resolvedXpath)) { // Setting a new root element.
        if (isMultiValue) {
          throw new IllegalArgumentException(
              "Method "
                  + method
                  + " was invoked as setter changing the document root element, but tries to set multiple values.");
        }
        return handeRootElementReplacement(proxy, method, document, valueToSet);
      }
      final boolean wildCardTarget = resolvedXpath.endsWith("/*");
      try {
        if (!lastInvocationContext.isStillValid(resolvedXpath)) {
          final DuplexExpression duplexExpression =
              wildCardTarget
                  ? new DuplexXPathParser(projector.config().getUserDefinedNamespaceMapping())
                      .compile(resolvedXpath.substring(0, resolvedXpath.length() - 2))
                  : new DuplexXPathParser(projector.config().getUserDefinedNamespaceMapping())
                      .compile(resolvedXpath);
          MethodParamVariableResolver resolver = null;
          if (duplexExpression.isUsingVariables()) {
            resolver =
                new MethodParamVariableResolver(
                    method, args, duplexExpression, projector.config().getStringRenderer(), null);
            duplexExpression.setXPathVariableResolver(resolver);
          }
          Class<?> targetComponentType = findTargetComponentType(method);
          lastInvocationContext =
              new InvocationContext(
                  resolvedXpath,
                  null,
                  null,
                  duplexExpression,
                  resolver,
                  targetComponentType,
                  projector);
        }
        final DuplexExpression duplexExpression = lastInvocationContext.getDuplexExpression();
        if (duplexExpression.getExpressionType().isMustEvalAsString()) {
          throw new XBPathException("Unwriteable xpath selector used ", method, resolvedXpath);
        }
        // MULTIVALUE
        if (isMultiValue) {
          if (duplexExpression.getExpressionType().equals(ExpressionType.ATTRIBUTE)) {
            throw new IllegalArgumentException(
                "Method "
                    + method
                    + " was invoked as setter changing some attribute, but was declared to set multiple values. I can not create multiple attributes for one path.");
          }
          final Iterable<?> iterable2Set =
              valueToSet == null
                  ? Collections.emptyList()
                  : (valueToSet.getClass().isArray())
                      ? ReflectionHelper.array2ObjectList(valueToSet)
                      : (Iterable<?>) valueToSet;
          if (wildCardTarget) {
            // TODO: check support of ParameterizedType e.g. Supplier
            final Element parentElement = (Element) duplexExpression.ensureExistence(node);
            DOMHelper.removeAllChildren(parentElement);
            int count = 0;
            for (Object o : iterable2Set) {
              if (o == null) {
                continue;
              }
              ++count;
              if (o instanceof Node) {
                DOMHelper.appendClone(parentElement, (Node) o);
                continue;
              }
              if (o instanceof DOMAccess) {
                DOMHelper.appendClone(parentElement, ((DOMAccess) o).getDOMBaseElement());
                continue;
              }
              throw new XBPathException(
                  "When using a wildcard target, the type to set must be a DOM Node or another projection. Otherwise I can not determine the element name.",
                  method,
                  resolvedXpath);
            }
            return getProxyReturnValueForMethod(proxy, method, Integer.valueOf(count));
          }
          final Element parentElement = duplexExpression.ensureParentExistence(node);
          duplexExpression.deleteAllMatchingChildren(parentElement);
          int count = applyIterableSetOnElement(iterable2Set, parentElement, duplexExpression);
          return getProxyReturnValueForMethod(proxy, method, Integer.valueOf(count));
        }

        // ATTRIBUTES
        if (duplexExpression.getExpressionType().equals(ExpressionType.ATTRIBUTE)) {
          if (wildCardTarget) {
            // TODO: This may never happen, right?
            throw new XBPathException(
                "Wildcards are not allowed when writing to an attribute. I need to know to which Element I should set the attribute",
                method,
                resolvedXpath);
          }
          Attr attribute = (Attr) duplexExpression.ensureExistence(node);
          if (valueToSet == null) {
            attribute.getOwnerElement().removeAttributeNode(attribute);
            return getProxyReturnValueForMethod(proxy, method, Integer.valueOf(1));
          }

          DOMHelper.setStringValue(attribute, valueToSet.toString());
          return getProxyReturnValueForMethod(proxy, method, Integer.valueOf(1));
        }

        if ((valueToSet instanceof Node) || (valueToSet instanceof DOMAccess)) {
          if (valueToSet instanceof Attr) {
            if (wildCardTarget) {
              throw new XBPathException(
                  "Wildcards are not allowed when writing an attribute. I need to know to which Element I should set the attribute",
                  method,
                  resolvedXpath);
            }
            Element parentNode = duplexExpression.ensureParentExistence(node);
            if (((Attr) valueToSet).getNamespaceURI() != null) {
              parentNode.setAttributeNodeNS((Attr) valueToSet);
              return getProxyReturnValueForMethod(proxy, method, Integer.valueOf(1));
            }
            parentNode.setAttributeNode((Attr) valueToSet);
            return getProxyReturnValueForMethod(proxy, method, Integer.valueOf(1));
          }
          final Element newNodeOrigin =
              valueToSet instanceof DOMAccess
                  ? ((DOMAccess) valueToSet).getDOMBaseElement()
                  : (Element) valueToSet;
          final Element newNode = (Element) newNodeOrigin.cloneNode(true);
          DOMHelper.ensureOwnership(document, newNode);
          if (wildCardTarget) {
            Element parentElement = (Element) duplexExpression.ensureExistence(node);
            DOMHelper.removeAllChildren(parentElement);
            parentElement.appendChild(newNode);
            return getProxyReturnValueForMethod(proxy, method, Integer.valueOf(1));
          }
          Element previousElement = (Element) duplexExpression.ensureExistence(node);

          DOMHelper.replaceElement(previousElement, newNode);
          return getProxyReturnValueForMethod(proxy, method, Integer.valueOf(1));
        }

        final Element elementToChange = (Element) duplexExpression.ensureExistence(node);
        if (valueToSet == null) {
          // TODO: This should depend on the parameter type?
          // If param type == String, no structural change might be expected.
          DOMHelper.removeAllChildren(elementToChange);
        } else {
          final String asString =
              projector
                  .config()
                  .getStringRenderer()
                  .render(
                      valueToSet.getClass(),
                      valueToSet,
                      duplexExpression.getExpressionFormatPattern());
          elementToChange.setTextContent(asString);
        }
        return getProxyReturnValueForMethod(proxy, method, Integer.valueOf(1));
      } catch (XBPathParsingException e) {
        throw new XBPathException(e, method, resolvedXpath);
      }
    }