private void processMethod( String name, ExecutableElement getterElt, ExecutableElement setterElt, ExecutableElement adderElt) { PropertyKind propKind = null; TypeInfo propType = null; TypeMirror propTypeMirror = null; // if (setterElt != null) { VariableElement paramElt = setterElt.getParameters().get(0); propTypeMirror = paramElt.asType(); propType = typeFactory.create(propTypeMirror); propKind = PropertyKind.forType(propType.getKind()); switch (propKind) { case LIST: case SET: propType = ((ParameterizedTypeInfo) propType).getArgs().get(0); propTypeMirror = ((DeclaredType) propTypeMirror).getTypeArguments().get(0); break; case MAP: propType = ((ParameterizedTypeInfo) propType).getArgs().get(1); propTypeMirror = ((DeclaredType) propTypeMirror).getTypeArguments().get(1); break; } } // if (getterElt != null) { TypeMirror getterTypeMirror = getterElt.getReturnType(); TypeInfo getterType = typeFactory.create(getterTypeMirror); PropertyKind getterKind = PropertyKind.forType(getterType.getKind()); switch (getterKind) { case LIST: case SET: getterType = ((ParameterizedTypeInfo) getterType).getArgs().get(0); getterTypeMirror = ((DeclaredType) getterTypeMirror).getTypeArguments().get(0); break; case MAP: getterType = ((ParameterizedTypeInfo) getterType).getArgs().get(1); getterTypeMirror = ((DeclaredType) getterTypeMirror).getTypeArguments().get(1); break; } if (propType != null) { if (propKind != getterKind) { throw new GenException( getterElt, name + " getter " + getterKind + " does not match the setter " + propKind); } if (!getterType.equals(propType)) { throw new GenException( getterElt, name + " getter type " + getterType + " does not match the setter type " + propType); } } else { propTypeMirror = getterTypeMirror; propType = getterType; propKind = getterKind; } } // if (adderElt != null) { switch (adderElt.getParameters().size()) { case 1: { VariableElement paramElt = adderElt.getParameters().get(0); TypeMirror adderTypeMirror = paramElt.asType(); TypeInfo adderType = typeFactory.create(adderTypeMirror); if (propTypeMirror != null) { if (propKind != PropertyKind.LIST && propKind != PropertyKind.SET) { throw new GenException( adderElt, name + "adder does not correspond to non list/set"); } if (!adderType.equals(propType)) { throw new GenException( adderElt, name + " adder type " + adderType + " does not match the property type " + propType); } } else { propTypeMirror = adderTypeMirror; propType = adderType; propKind = PropertyKind.LIST; } break; } case 2: { VariableElement paramElt = adderElt.getParameters().get(1); TypeMirror adderTypeMirror = paramElt.asType(); TypeInfo adderType = typeFactory.create(adderTypeMirror); if (propTypeMirror != null) { if (propKind != PropertyKind.MAP) { throw new GenException(adderElt, name + "adder does not correspond to non map"); } if (!adderType.equals(propType)) { throw new GenException( adderElt, name + " adder type " + adderType + " does not match the property type " + propType); } } else { propTypeMirror = adderTypeMirror; propType = adderType; propKind = PropertyKind.MAP; } break; } } } // boolean jsonifiable; switch (propType.getKind()) { case OBJECT: if (propKind == PropertyKind.VALUE) { return; } case PRIMITIVE: case BOXED_PRIMITIVE: case STRING: case API: case JSON_OBJECT: case JSON_ARRAY: case ENUM: jsonifiable = true; break; case DATA_OBJECT: Element propTypeElt = typeUtils.asElement(propTypeMirror); jsonifiable = propTypeElt.getAnnotation(DataObject.class) == null || Helper.isJsonifiable(elementUtils, typeUtils, (TypeElement) propTypeElt); break; default: return; } boolean declared = false; Doc doc = null; for (ExecutableElement methodElt : Arrays.asList(setterElt, adderElt, getterElt)) { if (methodElt != null) { // A stream that list all overriden methods from super types // the boolean control whether or not we want to filter only annotated // data objects Function<Boolean, Stream<ExecutableElement>> overridenMeths = (annotated) -> { Set<DeclaredType> ancestorTypes = Helper.resolveAncestorTypes(modelElt, true, true); return ancestorTypes .stream() .map(DeclaredType::asElement) .filter(elt -> !annotated || elt.getAnnotation(DataObject.class) != null) .flatMap(Helper.cast(TypeElement.class)) .flatMap(elt -> elementUtils.getAllMembers(elt).stream()) .flatMap(Helper.instanceOf(ExecutableElement.class)) .filter( executableElt -> executableElt.getKind() == ElementKind.METHOD && elementUtils.overrides(methodElt, executableElt, modelElt)); }; // if (doc == null) { doc = docFactory.createDoc(methodElt); if (doc == null) { Optional<Doc> first = overridenMeths .apply(false) .map(docFactory::createDoc) .filter(d -> d != null) .findFirst(); doc = first.orElse(null); } } // if (!declared) { Element ownerElt = methodElt.getEnclosingElement(); if (ownerElt.equals(modelElt)) { Object[] arr = overridenMeths .apply(true) .limit(1) .filter(elt -> !elt.getModifiers().contains(Modifier.ABSTRACT)) .toArray(); // Handle the case where this methods overrides from another data object declared = arr.length == 0; } else { declared = ownerElt.getAnnotation(DataObject.class) == null; } } } } PropertyInfo property = new PropertyInfo( declared, name, doc, propType, setterElt != null ? setterElt.getSimpleName().toString() : null, adderElt != null ? adderElt.getSimpleName().toString() : null, getterElt != null ? getterElt.getSimpleName().toString() : null, propKind, jsonifiable); propertyMap.put(property.name, property); }