Search in sources :

Example 1 with PathTemplate

use of cz.habarta.typescript.generator.parser.PathTemplate in project typescript-generator by vojtechhabarta.

the class ModelCompiler method processRestMethod.

private TsMethodModel processRestMethod(TsModel tsModel, SymbolTable symbolTable, String pathPrefix, Symbol responseSymbol, RestMethodModel method, boolean createLongName, TsType optionsType, boolean implement) {
    final String path = Utils.joinPath(pathPrefix, method.getPath());
    final PathTemplate pathTemplate = PathTemplate.parse(path);
    final List<String> comments = Utils.concat(method.getComments(), Arrays.asList("HTTP " + method.getHttpMethod() + " /" + path, "Java method: " + method.getOriginClass().getName() + "." + method.getName()));
    final List<TsParameterModel> parameters = new ArrayList<>();
    // path params
    for (MethodParameterModel parameter : method.getPathParams()) {
        parameters.add(processParameter(symbolTable, method, parameter));
    }
    // entity param
    if (method.getEntityParam() != null) {
        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);
        parameters.add(queryParameter);
    } else {
        queryParameter = null;
    }
    if (optionsType != null) {
        final TsParameterModel optionsParameter = new TsParameterModel("options", new TsType.OptionalType(optionsType));
        parameters.add(optionsParameter);
    }
    // return type
    final TsType returnType = typeFromJava(symbolTable, method.getReturnType(), method.getName(), method.getOriginClass());
    final TsType wrappedReturnType = new TsType.GenericReferenceType(responseSymbol, returnType);
    // method name
    final String nameSuffix;
    if (createLongName) {
        nameSuffix = "$" + method.getHttpMethod() + "$" + pathTemplate.format("", "", false).replaceAll("/", "_").replaceAll("\\W", "");
    } else {
        nameSuffix = "";
    }
    // implementation
    final List<TsStatement> body;
    if (implement) {
        body = new ArrayList<>();
        body.add(new TsReturnStatement(new TsCallExpression(new TsMemberExpression(new TsMemberExpression(new TsThisExpression(), "httpClient"), "request"), new TsObjectLiteral(new TsPropertyDefinition("method", new TsStringLiteral(method.getHttpMethod())), 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, optionsType != null ? new TsPropertyDefinition("options", new TsIdentifierReference("options")) : null))));
    } else {
        body = null;
    }
    // method
    final TsMethodModel tsMethodModel = new TsMethodModel(method.getName() + nameSuffix, TsModifierFlags.None, null, parameters, wrappedReturnType, body, comments);
    return tsMethodModel;
}
Also used : TsThisExpression(cz.habarta.typescript.generator.emitter.TsThisExpression) TsObjectLiteral(cz.habarta.typescript.generator.emitter.TsObjectLiteral) ArrayList(java.util.ArrayList) PathTemplate(cz.habarta.typescript.generator.parser.PathTemplate) TsCallExpression(cz.habarta.typescript.generator.emitter.TsCallExpression) TsStringLiteral(cz.habarta.typescript.generator.emitter.TsStringLiteral) TsIdentifierReference(cz.habarta.typescript.generator.emitter.TsIdentifierReference) TsBeanModel(cz.habarta.typescript.generator.emitter.TsBeanModel) TsMethodModel(cz.habarta.typescript.generator.emitter.TsMethodModel) TsStatement(cz.habarta.typescript.generator.emitter.TsStatement) TsMemberExpression(cz.habarta.typescript.generator.emitter.TsMemberExpression) RestQueryParam(cz.habarta.typescript.generator.parser.RestQueryParam) TsBeanModel(cz.habarta.typescript.generator.emitter.TsBeanModel) BeanModel(cz.habarta.typescript.generator.parser.BeanModel) MethodParameterModel(cz.habarta.typescript.generator.parser.MethodParameterModel) TsType(cz.habarta.typescript.generator.TsType) TsProperty(cz.habarta.typescript.generator.TsProperty) TsReturnStatement(cz.habarta.typescript.generator.emitter.TsReturnStatement) TsPropertyDefinition(cz.habarta.typescript.generator.emitter.TsPropertyDefinition) TsParameterModel(cz.habarta.typescript.generator.emitter.TsParameterModel)

Example 2 with PathTemplate

use of cz.habarta.typescript.generator.parser.PathTemplate in project typescript-generator by vojtechhabarta.

the class ModelCompiler method processPathTemplate.

private static TsTemplateLiteral processPathTemplate(PathTemplate pathTemplate) {
    final List<TsExpression> spans = new ArrayList<>();
    for (PathTemplate.Part part : pathTemplate.getParts()) {
        if (part instanceof PathTemplate.Literal) {
            final PathTemplate.Literal literal = (PathTemplate.Literal) part;
            spans.add(new TsStringLiteral(literal.getLiteral()));
        }
        if (part instanceof PathTemplate.Parameter) {
            final PathTemplate.Parameter parameter = (PathTemplate.Parameter) part;
            spans.add(new TsIdentifierReference(parameter.getValidName()));
        }
    }
    return new TsTaggedTemplateLiteral(new TsIdentifierReference("uriEncoding"), spans);
}
Also used : TsExpression(cz.habarta.typescript.generator.emitter.TsExpression) TsStringLiteral(cz.habarta.typescript.generator.emitter.TsStringLiteral) TsTaggedTemplateLiteral(cz.habarta.typescript.generator.emitter.TsTaggedTemplateLiteral) TsTaggedTemplateLiteral(cz.habarta.typescript.generator.emitter.TsTaggedTemplateLiteral) TsTemplateLiteral(cz.habarta.typescript.generator.emitter.TsTemplateLiteral) TsStringLiteral(cz.habarta.typescript.generator.emitter.TsStringLiteral) TsObjectLiteral(cz.habarta.typescript.generator.emitter.TsObjectLiteral) ArrayList(java.util.ArrayList) TsParameter(cz.habarta.typescript.generator.TsParameter) TsIdentifierReference(cz.habarta.typescript.generator.emitter.TsIdentifierReference) PathTemplate(cz.habarta.typescript.generator.parser.PathTemplate)

Example 3 with PathTemplate

use of cz.habarta.typescript.generator.parser.PathTemplate in project typescript-generator by vojtechhabarta.

the class SpringApplicationParser method parseControllerMethod.

// https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-ann-methods
private void parseControllerMethod(JaxrsApplicationParser.Result result, JaxrsApplicationParser.ResourceContext context, Class<?> controllerClass, Method method) {
    final RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(method, RequestMapping.class);
    if (requestMapping != null) {
        // swagger
        final SwaggerOperation swaggerOperation = settings.ignoreSwaggerAnnotations ? new SwaggerOperation() : Swagger.parseSwaggerAnnotations(method);
        if (swaggerOperation.possibleResponses != null) {
            for (SwaggerResponse response : swaggerOperation.possibleResponses) {
                if (response.responseType != null) {
                    foundType(result, response.responseType, controllerClass, method.getName());
                }
            }
        }
        if (swaggerOperation.hidden) {
            return;
        }
        // subContext
        context = context.subPath(requestMapping.path().length == 0 ? "" : requestMapping.path()[0]);
        final Map<String, Type> pathParamTypes = new LinkedHashMap<>();
        for (Parameter parameter : method.getParameters()) {
            final PathVariable pathVariableAnnotation = AnnotationUtils.findAnnotation(parameter, PathVariable.class);
            if (pathVariableAnnotation != null) {
                String pathVariableName = pathVariableAnnotation.value();
                // Can be empty if the URI template variable matches the method argument
                if (pathVariableName.isEmpty()) {
                    pathVariableName = parameter.getName();
                }
                pathParamTypes.put(pathVariableName, parameter.getParameterizedType());
            }
        }
        context = context.subPathParamTypes(pathParamTypes);
        final RequestMethod httpMethod = requestMapping.method().length == 0 ? RequestMethod.GET : requestMapping.method()[0];
        // path parameters
        final PathTemplate pathTemplate = PathTemplate.parse(context.path);
        final Map<String, Type> contextPathParamTypes = context.pathParamTypes;
        final List<MethodParameterModel> pathParams = pathTemplate.getParts().stream().filter(PathTemplate.Parameter.class::isInstance).map(PathTemplate.Parameter.class::cast).map(parameter -> {
            final Type type = contextPathParamTypes.get(parameter.getOriginalName());
            final Type paramType = type != null ? type : String.class;
            foundType(result, paramType, controllerClass, method.getName());
            return new MethodParameterModel(parameter.getValidName(), paramType);
        }).collect(Collectors.toList());
        // query parameters
        final List<RestQueryParam> queryParams = new ArrayList<>();
        for (Parameter parameter : method.getParameters()) {
            if (parameter.getType() == Pageable.class) {
                queryParams.add(new RestQueryParam.Single(new MethodParameterModel("page", Long.class), false));
                queryParams.add(new RestQueryParam.Single(new MethodParameterModel("size", Long.class), false));
                queryParams.add(new RestQueryParam.Single(new MethodParameterModel("sort", String.class), false));
            } else {
                final RequestParam requestParamAnnotation = AnnotationUtils.findAnnotation(parameter, RequestParam.class);
                if (requestParamAnnotation != null) {
                    if (parameter.getType() == MultiValueMap.class) {
                        queryParams.add(new RestQueryParam.Map(false));
                    } else {
                        final boolean isRequired = requestParamAnnotation.required() && requestParamAnnotation.defaultValue().equals(ValueConstants.DEFAULT_NONE);
                        queryParams.add(new RestQueryParam.Single(new MethodParameterModel(firstOf(requestParamAnnotation.value(), parameter.getName()), parameter.getParameterizedType()), isRequired));
                        foundType(result, parameter.getParameterizedType(), controllerClass, method.getName());
                    }
                }
                final ModelAttribute modelAttributeAnnotation = AnnotationUtils.findAnnotation(parameter, ModelAttribute.class);
                if (modelAttributeAnnotation != null) {
                    try {
                        final BeanInfo beanInfo = Introspector.getBeanInfo(parameter.getType());
                        for (PropertyDescriptor propertyDescriptor : beanInfo.getPropertyDescriptors()) {
                            final Method writeMethod = propertyDescriptor.getWriteMethod();
                            if (writeMethod != null) {
                                queryParams.add(new RestQueryParam.Single(new MethodParameterModel(propertyDescriptor.getName(), propertyDescriptor.getPropertyType()), false));
                                foundType(result, propertyDescriptor.getPropertyType(), controllerClass, method.getName());
                            }
                        }
                    } catch (IntrospectionException e) {
                        TypeScriptGenerator.getLogger().warning(String.format("Cannot introspect '%s' class: " + e.getMessage(), parameter.getAnnotatedType()));
                    }
                }
            }
        }
        // entity parameter
        final MethodParameterModel entityParameter = getEntityParameter(controllerClass, method);
        if (entityParameter != null) {
            foundType(result, entityParameter.getType(), controllerClass, method.getName());
        }
        final Type modelReturnType = parseReturnType(controllerClass, method);
        foundType(result, modelReturnType, controllerClass, method.getName());
        model.getMethods().add(new RestMethodModel(controllerClass, method.getName(), modelReturnType, method, controllerClass, httpMethod.name(), context.path, pathParams, queryParams, entityParameter, null));
    }
}
Also used : PathVariable(org.springframework.web.bind.annotation.PathVariable) Arrays(java.util.Arrays) RequestParam(org.springframework.web.bind.annotation.RequestParam) GenericsResolver(cz.habarta.typescript.generator.util.GenericsResolver) SwaggerResponse(cz.habarta.typescript.generator.parser.SwaggerResponse) SpringApplication(org.springframework.boot.SpringApplication) Map(java.util.Map) ConfigurableApplicationContext(org.springframework.context.ConfigurableApplicationContext) Pageable(org.springframework.data.domain.Pageable) RestMethodModel(cz.habarta.typescript.generator.parser.RestMethodModel) Method(java.lang.reflect.Method) JaxrsApplicationParser(cz.habarta.typescript.generator.parser.JaxrsApplicationParser) RestApplicationModel(cz.habarta.typescript.generator.parser.RestApplicationModel) AnnotationUtils(org.springframework.core.annotation.AnnotationUtils) RequestMethod(org.springframework.web.bind.annotation.RequestMethod) Collectors(java.util.stream.Collectors) IntrospectionException(java.beans.IntrospectionException) TypeScriptGenerator(cz.habarta.typescript.generator.TypeScriptGenerator) Objects(java.util.Objects) List(java.util.List) Stream(java.util.stream.Stream) Utils.getInheritanceChain(cz.habarta.typescript.generator.util.Utils.getInheritanceChain) Type(java.lang.reflect.Type) PropertyDescriptor(java.beans.PropertyDescriptor) RestApplicationType(cz.habarta.typescript.generator.parser.RestApplicationType) SourceType(cz.habarta.typescript.generator.parser.SourceType) RestApplicationParser(cz.habarta.typescript.generator.parser.RestApplicationParser) SwaggerOperation(cz.habarta.typescript.generator.parser.SwaggerOperation) AnnotatedElementUtils(org.springframework.core.annotation.AnnotatedElementUtils) RequestMapping(org.springframework.web.bind.annotation.RequestMapping) MethodParameterModel(cz.habarta.typescript.generator.parser.MethodParameterModel) BridgeMethodResolver(org.springframework.core.BridgeMethodResolver) JTypeWithNullability(cz.habarta.typescript.generator.type.JTypeWithNullability) ArrayList(java.util.ArrayList) LinkedHashMap(java.util.LinkedHashMap) RequestBody(org.springframework.web.bind.annotation.RequestBody) Introspector(java.beans.Introspector) ModelAttribute(org.springframework.web.bind.annotation.ModelAttribute) Parameter(java.lang.reflect.Parameter) BeanInfo(java.beans.BeanInfo) SpringBootApplication(org.springframework.boot.autoconfigure.SpringBootApplication) TypeProcessor(cz.habarta.typescript.generator.TypeProcessor) MultiValueMap(org.springframework.util.MultiValueMap) RestQueryParam(cz.habarta.typescript.generator.parser.RestQueryParam) Settings(cz.habarta.typescript.generator.Settings) Component(org.springframework.stereotype.Component) ParameterizedType(java.lang.reflect.ParameterizedType) Pair(cz.habarta.typescript.generator.util.Pair) PathTemplate(cz.habarta.typescript.generator.parser.PathTemplate) Swagger(cz.habarta.typescript.generator.parser.Swagger) ResponseEntity(org.springframework.http.ResponseEntity) TsType(cz.habarta.typescript.generator.TsType) Utils(cz.habarta.typescript.generator.util.Utils) ValueConstants(org.springframework.web.bind.annotation.ValueConstants) RequestParam(org.springframework.web.bind.annotation.RequestParam) RequestMethod(org.springframework.web.bind.annotation.RequestMethod) BeanInfo(java.beans.BeanInfo) ArrayList(java.util.ArrayList) IntrospectionException(java.beans.IntrospectionException) ModelAttribute(org.springframework.web.bind.annotation.ModelAttribute) PathTemplate(cz.habarta.typescript.generator.parser.PathTemplate) RequestMapping(org.springframework.web.bind.annotation.RequestMapping) LinkedHashMap(java.util.LinkedHashMap) SwaggerOperation(cz.habarta.typescript.generator.parser.SwaggerOperation) RestQueryParam(cz.habarta.typescript.generator.parser.RestQueryParam) PropertyDescriptor(java.beans.PropertyDescriptor) SwaggerResponse(cz.habarta.typescript.generator.parser.SwaggerResponse) MethodParameterModel(cz.habarta.typescript.generator.parser.MethodParameterModel) Method(java.lang.reflect.Method) RequestMethod(org.springframework.web.bind.annotation.RequestMethod) Type(java.lang.reflect.Type) RestApplicationType(cz.habarta.typescript.generator.parser.RestApplicationType) SourceType(cz.habarta.typescript.generator.parser.SourceType) ParameterizedType(java.lang.reflect.ParameterizedType) TsType(cz.habarta.typescript.generator.TsType) RestMethodModel(cz.habarta.typescript.generator.parser.RestMethodModel) Parameter(java.lang.reflect.Parameter) PathVariable(org.springframework.web.bind.annotation.PathVariable)

Aggregations

PathTemplate (cz.habarta.typescript.generator.parser.PathTemplate)3 ArrayList (java.util.ArrayList)3 TsType (cz.habarta.typescript.generator.TsType)2 TsIdentifierReference (cz.habarta.typescript.generator.emitter.TsIdentifierReference)2 TsObjectLiteral (cz.habarta.typescript.generator.emitter.TsObjectLiteral)2 TsStringLiteral (cz.habarta.typescript.generator.emitter.TsStringLiteral)2 MethodParameterModel (cz.habarta.typescript.generator.parser.MethodParameterModel)2 RestQueryParam (cz.habarta.typescript.generator.parser.RestQueryParam)2 Settings (cz.habarta.typescript.generator.Settings)1 TsParameter (cz.habarta.typescript.generator.TsParameter)1 TsProperty (cz.habarta.typescript.generator.TsProperty)1 TypeProcessor (cz.habarta.typescript.generator.TypeProcessor)1 TypeScriptGenerator (cz.habarta.typescript.generator.TypeScriptGenerator)1 TsBeanModel (cz.habarta.typescript.generator.emitter.TsBeanModel)1 TsCallExpression (cz.habarta.typescript.generator.emitter.TsCallExpression)1 TsExpression (cz.habarta.typescript.generator.emitter.TsExpression)1 TsMemberExpression (cz.habarta.typescript.generator.emitter.TsMemberExpression)1 TsMethodModel (cz.habarta.typescript.generator.emitter.TsMethodModel)1 TsParameterModel (cz.habarta.typescript.generator.emitter.TsParameterModel)1 TsPropertyDefinition (cz.habarta.typescript.generator.emitter.TsPropertyDefinition)1