private boolean generateComputedProperties()

in json/src/main/java/org/netbeans/html/json/impl/ModelProcessor.java [759:946]


    private boolean generateComputedProperties(
        String className,
        Writer w, Prprt[] fixedProps,
        Collection<? extends Element> arr, Collection<GetSet> props,
        Map<String,Collection<String[]>> deps
    ) throws IOException {
        boolean ok = true;
        NEXT_ANNOTATION: for (Element e : arr) {
            if (e.getKind() != ElementKind.METHOD) {
                continue;
            }
            final ComputedProperty cp = e.getAnnotation(ComputedProperty.class);
            final Transitive tp = e.getAnnotation(Transitive.class);
            if (cp == null) {
                continue;
            }
            if (!e.getModifiers().contains(Modifier.STATIC)) {
                error("Method " + e.getSimpleName() + " has to be static when annotated by @ComputedProperty", e);
                ok = false;
                continue;
            }
            ExecutableElement ee = (ExecutableElement)e;
            ExecutableElement write = null;
            boolean instance = e.getEnclosingElement().getAnnotation(Model.class).instance();
            if (!cp.write().isEmpty()) {
                write = findWrite(ee, (TypeElement)e.getEnclosingElement(), cp.write(), className);
                ok = write != null;
            }
            final TypeMirror rt = ee.getReturnType();
            final Types tu = processingEnv.getTypeUtils();
            TypeMirror ert = tu.erasure(rt);
            String tn = fqn(ert, ee);
            boolean array = false;
            final TypeMirror toCheck;
            if (tn.equals("java.util.List")) {
                array = true;
                toCheck = ((DeclaredType)rt).getTypeArguments().get(0);
            } else {
                toCheck = rt;
            }

            final String sn = ee.getSimpleName().toString();

            if (toCheck.getKind().isPrimitive()) {
                // OK
            } else {
                TypeMirror stringType = processingEnv.getElementUtils().getTypeElement("java.lang.String").asType();
                TypeMirror enumType = processingEnv.getElementUtils().getTypeElement("java.lang.Enum").asType();

                if (tu.isSubtype(toCheck, stringType)) {
                    // OK
                } else if (tu.isSubtype(tu.erasure(toCheck), tu.erasure(enumType))) {
                    // OK
                } else if (isModel(toCheck)) {
                    // OK
                } else {
                    try {
                        tu.unboxedType(toCheck);
                        // boxed types are OK
                    } catch (IllegalArgumentException ex) {
                        ok = false;
                        error(sn + " cannot return " + toCheck, e);
                    }
                }
            }

            final String propertyName = e.getSimpleName().toString();
            for (GetSet prop : props) {
                if (propertyName.equals(prop.name)) {
                    error("Cannot have the property " + propertyName + " defined twice", e);
                    ok = false;
                    continue NEXT_ANNOTATION;
                }
            }

            String[] gs = toGetSet(sn, tn, array);

            w.write("  public " + tn);
            if (array) {
                w.write("<" + toCheck + ">");
            }
            w.write(" " + gs[0] + "() {\n");
            int arg = 0;
            boolean deep = false;

            final List<? extends VariableElement> methodParameters = ee.getParameters();

            String unknownSingleProperty = methodParameters.size() != 1 ? null :
                verifyPropName(methodParameters.get(0), fixedProps);

            if (unknownSingleProperty == null) {
                for (VariableElement pe : methodParameters) {
                    final String dn = pe.getSimpleName().toString();

                    String unknownPropertyError = verifyPropName(pe, fixedProps);
                    if (unknownPropertyError != null) {
                        error(unknownPropertyError, e);
                        ok = false;
                    }
                    final TypeMirror pt = pe.asType();
                    if (isModel(pt)) {
                        deep = true;
                    }
                    final String dt = fqn(pt, ee);
                    if (dt.startsWith("java.util.List") && pt instanceof DeclaredType) {
                        final List<? extends TypeMirror> ptArgs = ((DeclaredType)pt).getTypeArguments();
                        if (ptArgs.size() == 1 && isModel(ptArgs.get(0))) {
                            deep = true;
                        }
                    }
                    String[] call = toGetSet(dn, dt, false);
                    w.write("    " + dt + " arg" + (++arg) + " = ");
                    w.write(call[0] + "();\n");

                    Collection<String[]> depends = deps.get(dn);
                    if (depends == null) {
                        depends = new LinkedHashSet<String[]>();
                        deps.put(dn, depends);
                    }
                    depends.add(new String[] { sn, gs[0] });
                }
            } else {
                VariableElement firstProp = methodParameters.get(0);
                TypeMirror type = firstProp.asType();
                CharSequence simpleName;
                if (type.getKind() == TypeKind.DECLARED) {
                    simpleName = ((DeclaredType) type).asElement().getSimpleName();
                } else {
                    simpleName = type.toString();
                }
                if (simpleName.toString().equals(className)) {
                } else {
                    error("Single parameter needs to be of type " + className + " or " + unknownSingleProperty, e);
                    ok = false;
                    continue NEXT_ANNOTATION;
                }
                w.write("    " + simpleName + " arg" + (++arg) + " = this;\n");
            }
            w.write("    try {\n");
            if (tp != null) {
                deep = tp.deep();
            }
            if (deep) {
                w.write("      proto.acquireLock(\"" + sn + "\");\n");
            } else {
                w.write("      proto.acquireLock();\n");
            }
            w.write("      return " + fqn(ee.getEnclosingElement().asType(), ee) + '.' + e.getSimpleName() + "(");
            String sep = "";
            for (int i = 1; i <= arg; i++) {
                w.write(sep);
                w.write("arg" + i);
                sep = ", ";
            }
            w.write(");\n");
            w.write("    } finally {\n");
            w.write("      proto.releaseLock();\n");
            w.write("    }\n");
            w.write("  }\n");

            if (write == null) {
                props.add(new GetSet(
                    propertyName,
                    gs[0],
                    null,
                    tn,
                    true,
                    false
                ));
            } else {
                w.write("  public void " + gs[4] + "(" + write.getParameters().get(1).asType());
                w.write(" value) {\n");
                w.write("    " + (instance ? "instance" : fqn(ee.getEnclosingElement().asType(), ee)) + '.' + write.getSimpleName() + "(this, value);\n");
                w.write("  }\n");

                props.add(new GetSet(
                    propertyName,
                    gs[0],
                    gs[4],
                    tn,
                    false,
                    false
                ));
            }
        }

        return ok;
    }