docs: protected Map<String, Object> resolveGenericTypes(DeclaredType type, TypeElement typeElement, Map<String, Object> boundTypes) {
          List<? extends TypeMirror> typeArguments = type.getTypeArguments();
          Map<String, Object> resolvedParameters = new LinkedHashMap<>();
          List<? extends TypeParameterElement> typeParameters = typeElement.getTypeParameters();
          if (typeArguments.size() == typeParameters.size()) {
              Iterator<? extends TypeMirror> i = typeArguments.iterator();
              for (TypeParameterElement typeParameter : typeParameters) {
                  String parameterName = typeParameter.toString();
                  TypeMirror mirror = i.next();
  
                  TypeKind kind = mirror.getKind();
                  switch (kind) {
                      case TYPEVAR:
                          TypeVariable tv = (TypeVariable) mirror;
                          if (boundTypes.containsKey(tv.toString())) {
                              resolvedParameters.put(parameterName, boundTypes.get(tv.toString()));
                          } else {
                              TypeMirror upperBound = tv.getUpperBound();
                              TypeMirror lowerBound = tv.getLowerBound();
                              if (upperBound.getKind() != TypeKind.NULL) {
                                  resolvedParameters.put(parameterName, resolveTypeReference(upperBound, Collections.emptyMap()));
                              } else if (lowerBound.getKind() != TypeKind.NULL) {
                                  resolvedParameters.put(parameterName, resolveTypeReference(lowerBound, Collections.emptyMap()));
                              }
                          }
                          continue;
                      case ARRAY:
                      case BOOLEAN:
                      case BYTE:
                      case CHAR:
                      case DOUBLE:
                      case FLOAT:
                      case INT:
                      case LONG:
                      case SHORT:
                          resolveGenericTypeParameterForPrimitiveOrArray(resolvedParameters, parameterName, mirror, boundTypes);
                          continue;
                      case DECLARED:
                          resolveGenericTypeParameter(resolvedParameters, parameterName, mirror, boundTypes);
                          continue;
                      case WILDCARD:
                          WildcardType wcType = (WildcardType) mirror;
                          TypeMirror extendsBound = wcType.getExtendsBound();
                          TypeMirror superBound = wcType.getSuperBound();
                          if (extendsBound != null) {
                              resolveGenericTypeParameter(resolvedParameters, parameterName, extendsBound, boundTypes);
                          } else if (superBound != null) {
                              resolveGenericTypeParameter(resolvedParameters, parameterName, superBound, boundTypes);
                          } else {
                              resolvedParameters.put(parameterName, Object.class);
                          }
                      default:
                          // no-op
                  }
              }
          }
          return resolvedParameters;
      }