Skip to content

Commit

Permalink
Add possibility to pass request headers to HttpClient
Browse files Browse the repository at this point in the history
Fixes vojtechhabarta#790

Signed-off-by: Oleksandr Porunov <alexandr.porunov@gmail.com>
  • Loading branch information
porunov committed Feb 6, 2022
1 parent 65d0434 commit 58b8c03
Show file tree
Hide file tree
Showing 14 changed files with 273 additions and 102 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import cz.habarta.typescript.generator.parser.MethodParameterModel;
import cz.habarta.typescript.generator.parser.RestMethodModel;
import cz.habarta.typescript.generator.parser.RestQueryParam;
import cz.habarta.typescript.generator.parser.RestParam;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.List;
Expand All @@ -12,10 +12,11 @@ public class DefaultRestMethodBuilder implements RestMethodBuilder{
@Override
public RestMethodModel build(Class<?> originClass, String name, Type returnType, Method originalMethod,
Class<?> rootResource, String httpMethod, String path,
List<MethodParameterModel> pathParams, List<RestQueryParam> queryParams,
MethodParameterModel entityParam, List<String> comments) {
List<MethodParameterModel> pathParams, List<RestParam> queryParams,
MethodParameterModel entityParam, List<String> comments, List<RestParam> headers) {

return new RestMethodModel(originClass, name, returnType, originalMethod, rootResource, httpMethod, path,
pathParams, queryParams, entityParam, comments);
pathParams, queryParams, entityParam, comments, headers);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@

import cz.habarta.typescript.generator.parser.MethodParameterModel;
import cz.habarta.typescript.generator.parser.RestMethodModel;
import cz.habarta.typescript.generator.parser.RestQueryParam;
import cz.habarta.typescript.generator.parser.RestParam;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.List;

public interface RestMethodBuilder {

RestMethodModel build(Class<?> originClass, String name, Type returnType, Method originalMethod,
Class<?> rootResource, String httpMethod, String path, List<MethodParameterModel> pathParams, List<RestQueryParam> queryParams, MethodParameterModel entityParam,
List<String> comments);
Class<?> rootResource, String httpMethod, String path, List<MethodParameterModel> pathParams, List<RestParam> queryParams, MethodParameterModel entityParam,
List<String> comments, List<RestParam> headers);

}
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ public class Settings {
public String restResponseType = null;
public String restOptionsType = null;
public boolean restOptionsTypeIsGeneric;
public boolean restHeaderArgumentsParsed;
private List<RestApplicationParser.Factory> restApplicationParserFactories;
public TypeProcessor customTypeProcessor = null;
public RestMethodBuilder customRestMethodBuilder = null;
Expand Down Expand Up @@ -776,6 +777,10 @@ public void setRestOptionsType(String restOptionsType) {
}
}

public void setRestHeaderArgumentsParsed(boolean restHeaderArgumentsParsed) {
this.restHeaderArgumentsParsed = restHeaderArgumentsParsed;
}

public List<RestApplicationParser.Factory> getRestApplicationParserFactories() {
if (restApplicationParserFactories == null) {
final List<RestApplicationParser.Factory> factories = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
import cz.habarta.typescript.generator.parser.PropertyModel;
import cz.habarta.typescript.generator.parser.RestApplicationModel;
import cz.habarta.typescript.generator.parser.RestMethodModel;
import cz.habarta.typescript.generator.parser.RestQueryParam;
import cz.habarta.typescript.generator.parser.RestParam;
import cz.habarta.typescript.generator.type.JTypeWithNullability;
import cz.habarta.typescript.generator.util.GenericsResolver;
import cz.habarta.typescript.generator.util.Pair;
Expand Down Expand Up @@ -622,6 +622,7 @@ private void createRestClients(TsModel tsModel, SymbolTable symbolTable, List<Re
new TsProperty("queryParams", new TsType.OptionalType(TsType.Any)),
new TsProperty("data", new TsType.OptionalType(TsType.Any)),
new TsProperty("copyFn", new TsType.OptionalType(new TsType.FunctionType(Arrays.asList(new TsParameter("data", returnGenericVariable)), returnGenericVariable))),
new TsProperty("headers", new TsType.OptionalType(TsType.Any)),
optionsType != null ? new TsProperty("options", new TsType.OptionalType(optionsType)) : null
))
), new TsType.GenericReferenceType(responseSymbol, returnGenericVariable), null, null)
Expand Down Expand Up @@ -728,57 +729,14 @@ private TsMethodModel processRestMethod(TsModel tsModel, SymbolTable symbolTable
parameters.add(processParameter(symbolTable, method, method.getEntityParam()));
}
// query params
final List<RestQueryParam> queryParams = method.getQueryParams();
final TsParameterModel queryParameter;
if (queryParams != null && !queryParams.isEmpty()) {
final List<TsType> types = new ArrayList<>();
if (queryParams.stream().anyMatch(param -> param instanceof RestQueryParam.Map)) {
types.add(new TsType.IndexedArrayType(TsType.String, TsType.Any));
} else {
final List<TsProperty> currentSingles = new ArrayList<>();
final Runnable flushSingles = () -> {
if (!currentSingles.isEmpty()) {
types.add(new TsType.ObjectType(currentSingles));
currentSingles.clear();
}
};
for (RestQueryParam restQueryParam : queryParams) {
if (restQueryParam instanceof RestQueryParam.Single) {
final MethodParameterModel queryParam = ((RestQueryParam.Single) restQueryParam).getQueryParam();
final TsType type = typeFromJava(symbolTable, queryParam.getType(), method.getName(), method.getOriginClass());
currentSingles.add(new TsProperty(queryParam.getName(), restQueryParam.required ? type : new TsType.OptionalType(type)));
}
if (restQueryParam instanceof RestQueryParam.Bean) {
final BeanModel queryBean = ((RestQueryParam.Bean) restQueryParam).getBean();
flushSingles.run();
final Symbol queryParamsSymbol = symbolTable.getSymbol(queryBean.getOrigin(), "QueryParams");
if (tsModel.getBean(queryParamsSymbol) == null) {
tsModel.getBeans().add(new TsBeanModel(
queryBean.getOrigin(),
TsBeanCategory.Data,
/*isClass*/false,
queryParamsSymbol,
/*typeParameters*/null,
/*parent*/null,
/*extendsList*/null,
/*implementsList*/null,
processProperties(symbolTable, null, queryBean),
/*constructor*/null,
/*methods*/null,
/*comments*/null
));
}
types.add(new TsType.ReferenceType(queryParamsSymbol));
}
}
flushSingles.run();
}
boolean allQueryParamsOptional = queryParams.stream().noneMatch(queryParam -> queryParam.required);
TsType.IntersectionType queryParamType = new TsType.IntersectionType(types);
queryParameter = new TsParameterModel("queryParams", allQueryParamsOptional ? new TsType.OptionalType(queryParamType) : queryParamType);
final TsParameterModel queryParameter = convertRestParams(method.getQueryParams(), symbolTable, method, tsModel, "queryParams", "QueryParams");
if(queryParameter != null){
parameters.add(queryParameter);
} else {
queryParameter = null;
}
// body params
final TsParameterModel headersParameter = convertRestParams(method.getHeaders(), symbolTable, method, tsModel, "headers", "Headers");
if(headersParameter != null){
parameters.add(headersParameter);
}
if (optionsType != null) {
final TsParameterModel optionsParameter = new TsParameterModel("options", new TsType.OptionalType(optionsType));
Expand Down Expand Up @@ -808,6 +766,7 @@ private TsMethodModel processRestMethod(TsModel tsModel, SymbolTable symbolTable
new TsPropertyDefinition("url", processPathTemplate(pathTemplate)),
queryParameter != null ? new TsPropertyDefinition("queryParams", new TsIdentifierReference("queryParams")) : null,
method.getEntityParam() != null ? new TsPropertyDefinition("data", new TsIdentifierReference(method.getEntityParam().getName())) : null,
headersParameter != null ? new TsPropertyDefinition("headers", new TsIdentifierReference("headers")) : null,
optionsType != null ? new TsPropertyDefinition("options", new TsIdentifierReference("options")) : null
)
)
Expand All @@ -820,6 +779,57 @@ private TsMethodModel processRestMethod(TsModel tsModel, SymbolTable symbolTable
return tsMethodModel;
}

private TsParameterModel convertRestParams(List<RestParam> restParams, SymbolTable symbolTable, RestMethodModel method, TsModel tsModel, String parameterName, String beanSuffix){
if (restParams == null || restParams.isEmpty()){
return null;
}
final List<TsType> types = new ArrayList<>();
if (restParams.stream().anyMatch(param -> param instanceof RestParam.Map)) {
types.add(new TsType.IndexedArrayType(TsType.String, TsType.Any));
} else {
final List<TsProperty> currentSingles = new ArrayList<>();
final Runnable flushSingles = () -> {
if (!currentSingles.isEmpty()) {
types.add(new TsType.ObjectType(currentSingles));
currentSingles.clear();
}
};
for (RestParam restParam : restParams) {
if (restParam instanceof RestParam.Single) {
final MethodParameterModel restParamMethodParameterModel = ((RestParam.Single) restParam).getRestParam();
final TsType type = typeFromJava(symbolTable, restParamMethodParameterModel.getType(), method.getName(), method.getOriginClass());
currentSingles.add(new TsProperty(restParamMethodParameterModel.getName(), restParam.required ? type : new TsType.OptionalType(type)));
}
if (restParam instanceof RestParam.Bean) {
final BeanModel paramBean = ((RestParam.Bean) restParam).getBean();
flushSingles.run();
final Symbol paramsSymbol = symbolTable.getSymbol(paramBean.getOrigin(), beanSuffix);
if (tsModel.getBean(paramsSymbol) == null) {
tsModel.getBeans().add(new TsBeanModel(
paramBean.getOrigin(),
TsBeanCategory.Data,
/*isClass*/false,
paramsSymbol,
/*typeParameters*/null,
/*parent*/null,
/*extendsList*/null,
/*implementsList*/null,
processProperties(symbolTable, null, paramBean),
/*constructor*/null,
/*methods*/null,
/*comments*/null
));
}
types.add(new TsType.ReferenceType(paramsSymbol));
}
}
flushSingles.run();
}
boolean allParamsOptional = restParams.stream().noneMatch(param -> param.required);
TsType.IntersectionType paramType = new TsType.IntersectionType(types);
return new TsParameterModel(parameterName, allParamsOptional ? new TsType.OptionalType(paramType) : paramType);
}

private TsParameterModel processParameter(SymbolTable symbolTable, MethodModel method, MethodParameterModel parameter) {
final String parameterName = parameter.getName();
final TsType parameterType = typeFromJava(symbolTable, parameter.getType(), method.getName(), method.getOriginClass());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,25 +174,47 @@ private void parseResourceMethod(Result result, ResourceContext context, Class<?
}
}
// query parameters
final List<RestQueryParam> queryParams = new ArrayList<>();
final List<RestParam> queryParams = new ArrayList<>();
for (Parameter param : method.getParameters()) {
final QueryParam queryParamAnnotation = getRsAnnotation(param, QueryParam.class);
if (queryParamAnnotation != null) {
queryParams.add(new RestQueryParam.Single(new MethodParameterModel(queryParamAnnotation.value(), param.getParameterizedType()), false));
queryParams.add(new RestParam.Single(new MethodParameterModel(queryParamAnnotation.value(), param.getParameterizedType()), false));
foundType(result, param.getParameterizedType(), resourceClass, method.getName());
}
final BeanParam beanParamAnnotation = getRsAnnotation(param, BeanParam.class);
if (beanParamAnnotation != null) {
final Class<?> beanParamClass = param.getType();
final BeanModel paramBean = getQueryParameters(beanParamClass);
if (paramBean != null) {
queryParams.add(new RestQueryParam.Bean(paramBean));
queryParams.add(new RestParam.Bean(paramBean));
for (PropertyModel property : paramBean.getProperties()) {
foundType(result, property.getType(), beanParamClass, property.getName());
}
}
}
}
// header parameters
final List<RestParam> headers = new ArrayList<>();
if(settings.restHeaderArgumentsParsed){
for (Parameter param : method.getParameters()) {
final HeaderParam headerParamAnnotation = getRsAnnotation(param, HeaderParam.class);
if (headerParamAnnotation != null) {
headers.add(new RestParam.Single(new MethodParameterModel(headerParamAnnotation.value(), param.getParameterizedType()), false));
foundType(result, param.getParameterizedType(), resourceClass, method.getName());
}
final BeanParam beanParamAnnotation = getRsAnnotation(param, BeanParam.class);
if (beanParamAnnotation != null) {
final Class<?> beanParamClass = param.getType();
final BeanModel paramBean = getHeaderParameters(beanParamClass);
if (paramBean != null) {
headers.add(new RestParam.Bean(paramBean));
for (PropertyModel property : paramBean.getProperties()) {
foundType(result, property.getType(), beanParamClass, property.getName());
}
}
}
}
}
// JAX-RS specification - 3.3.2.1 Entity Parameters
final List<Type> parameterTypes = settings.getTypeParser().getMethodParameterTypes(method);
final List<Pair<Parameter, Type>> parameters = Utils.zip(Arrays.asList(method.getParameters()), parameterTypes);
Expand Down Expand Up @@ -234,7 +256,7 @@ private void parseResourceMethod(Result result, ResourceContext context, Class<?
final List<String> comments = Swagger.getOperationComments(swaggerOperation);
// create method
model.getMethods().add(restMethodBuilder.build(resourceClass, method.getName(), resolvedModelReturnType, method,
context.rootResource, httpMethod.value(), context.path, pathParams, queryParams, entityParameter, comments));
context.rootResource, httpMethod.value(), context.path, pathParams, queryParams, entityParameter, comments, headers));
}
// JAX-RS specification - 3.4.1 Sub Resources
if (pathAnnotation != null && httpMethod == null) {
Expand Down Expand Up @@ -282,6 +304,36 @@ private static BeanModel getQueryParameters(Class<?> paramBean) {
}
}

private static BeanModel getHeaderParameters(Class<?> paramBean) {
final List<PropertyModel> properties = new ArrayList<>();
final List<Field> fields = Utils.getAllFields(paramBean);
for (Field field : fields) {
final HeaderParam annotation = getRsAnnotation(field, HeaderParam.class);
if (annotation != null) {
properties.add(new PropertyModel(annotation.value(), field.getGenericType(), /*optional*/true, null, field, null, null, null));
}
}
try {
final BeanInfo beanInfo = Introspector.getBeanInfo(paramBean);
for (PropertyDescriptor propertyDescriptor : beanInfo.getPropertyDescriptors()) {
final Method writeMethod = propertyDescriptor.getWriteMethod();
if (writeMethod != null) {
final HeaderParam annotation = getRsAnnotation(writeMethod, HeaderParam.class);
if (annotation != null) {
properties.add(new PropertyModel(annotation.value(), propertyDescriptor.getPropertyType(), /*optional*/true, null, writeMethod, null, null, null));
}
}
}
} catch (IntrospectionException e) {
TypeScriptGenerator.getLogger().warning(String.format("Cannot introspect '%s' class: " + e.getMessage(), paramBean));
}
if (properties.isEmpty()) {
return null;
} else {
return new BeanModel(paramBean, null, null, null, null, null, properties, null);
}
}

private MethodParameterModel getEntityParameter(Class<?> resourceClass, Method method, List<Pair<Parameter, Type>> parameters) {
for (Pair<Parameter, Type> pair : parameters) {
if (!Utils.hasAnyAnnotation(annotationClass -> pair.getValue1().getAnnotation(annotationClass), Arrays.asList(
Expand Down
Loading

0 comments on commit 58b8c03

Please sign in to comment.