diff --git a/typescript-generator-core/pom.xml b/typescript-generator-core/pom.xml
index 72ee81237..a0e49f622 100644
--- a/typescript-generator-core/pom.xml
+++ b/typescript-generator-core/pom.xml
@@ -59,6 +59,11 @@
javax.ws.rs-api
2.1.1
+
+ jakarta.ws.rs
+ jakarta.ws.rs-api
+ 3.0.0
+
io.github.classgraph
classgraph
diff --git a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/JakartaRsApplicationScanner.java b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/JakartaRsApplicationScanner.java
new file mode 100644
index 000000000..0f44be32d
--- /dev/null
+++ b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/JakartaRsApplicationScanner.java
@@ -0,0 +1,74 @@
+
+package cz.habarta.typescript.generator;
+
+import cz.habarta.typescript.generator.parser.SourceType;
+import io.github.classgraph.ScanResult;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.core.Application;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.function.Predicate;
+
+
+public class JakartaRsApplicationScanner {
+
+ public static List> scanJakartaRsApplication(Class> jaxrsApplicationClass, Predicate isClassNameExcluded) {
+ final ClassLoader originalContextClassLoader = Thread.currentThread().getContextClassLoader();
+ try {
+ Thread.currentThread().setContextClassLoader(jaxrsApplicationClass.getClassLoader());
+ TypeScriptGenerator.getLogger().info("Scanning JAX-RS application: " + jaxrsApplicationClass.getName());
+ final Constructor> constructor = jaxrsApplicationClass.getDeclaredConstructor();
+ constructor.setAccessible(true);
+ final Application application = (Application) constructor.newInstance();
+ final List> resourceClasses = new ArrayList<>();
+ for (Class> cls : application.getClasses()) {
+ if (cls.isAnnotationPresent(Path.class)) {
+ resourceClasses.add(cls);
+ }
+ }
+ return new JakartaRsApplicationScanner().scanJakartaRsApplication(jaxrsApplicationClass, resourceClasses, isClassNameExcluded);
+ } catch (ReflectiveOperationException e) {
+ throw reportError(e);
+ } finally {
+ Thread.currentThread().setContextClassLoader(originalContextClassLoader);
+ }
+ }
+
+ public static List> scanAutomaticJakartaRsApplication(ScanResult scanResult, Predicate isClassNameExcluded) {
+ final List namesOfResourceClasses = scanResult.getClassesWithAnnotation(Path.class.getName()).getNames();
+ final List> resourceClasses = Input.loadClasses(namesOfResourceClasses);
+ TypeScriptGenerator.getLogger().info(String.format("Found %d root resources.", resourceClasses.size()));
+ return new JakartaRsApplicationScanner().scanJakartaRsApplication(null, resourceClasses, isClassNameExcluded);
+ }
+
+ private static RuntimeException reportError(ReflectiveOperationException e) {
+ final String url = "https://github.com/vojtechhabarta/typescript-generator/wiki/JAX-RS-Application";
+ final String message = "Cannot load JAX-RS application. For more information see " + url + ".";
+ TypeScriptGenerator.getLogger().error(message);
+ return new RuntimeException(message, e);
+ }
+
+ List> scanJakartaRsApplication(Class> applicationClass, List> resourceClasses, Predicate isClassNameExcluded) {
+ Collections.sort(resourceClasses, new Comparator>() {
+ @Override
+ public int compare(Class> o1, Class> o2) {
+ return o1.getName().compareToIgnoreCase(o2.getName());
+ }
+ });
+ final List> sourceTypes = new ArrayList<>();
+ if (applicationClass != null) {
+ sourceTypes.add(new SourceType(applicationClass));
+ }
+ for (Class> resourceClass : resourceClasses) {
+ if (isClassNameExcluded == null || !isClassNameExcluded.test(resourceClass.getName())) {
+ sourceTypes.add(new SourceType(resourceClass));
+ }
+ }
+ return sourceTypes;
+ }
+
+}
diff --git a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/Settings.java b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/Settings.java
index 8abe8e53f..d8deeebd4 100644
--- a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/Settings.java
+++ b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/Settings.java
@@ -8,6 +8,7 @@
import cz.habarta.typescript.generator.compiler.SymbolTable.CustomTypeNamingFunction;
import cz.habarta.typescript.generator.emitter.EmitterExtension;
import cz.habarta.typescript.generator.emitter.EmitterExtensionFeatures;
+import cz.habarta.typescript.generator.parser.JakartaRsApplicationParser;
import cz.habarta.typescript.generator.parser.JaxrsApplicationParser;
import cz.habarta.typescript.generator.parser.RestApplicationParser;
import cz.habarta.typescript.generator.parser.TypeParser;
@@ -94,6 +95,8 @@ public class Settings {
public boolean disableTaggedUnions = false;
public boolean generateReadonlyAndWriteonlyJSDocTags = false;
public boolean ignoreSwaggerAnnotations = false;
+ public boolean generateJakartaRsApplicationInterface = false;
+ public boolean generateJakartaRsApplicationClient;
public boolean generateJaxrsApplicationInterface = false;
public boolean generateJaxrsApplicationClient = false;
public boolean generateSpringApplicationInterface = false;
@@ -408,6 +411,10 @@ public void validate() {
annotation.getName()));
}
}
+
+ if (generateJakartaRsApplicationClient && outputFileType != TypeScriptFileType.implementationFile) {
+ throw new RuntimeException("'generateJaxrsApplicationClient' can only be used when generating implementation file ('outputFileType' parameter is 'implementationFile').");
+ }
if (generateJaxrsApplicationClient && outputFileType != TypeScriptFileType.implementationFile) {
throw new RuntimeException("'generateJaxrsApplicationClient' can only be used when generating implementation file ('outputFileType' parameter is 'implementationFile').");
}
@@ -761,9 +768,13 @@ public void setRestOptionsType(String restOptionsType) {
public List getRestApplicationParserFactories() {
if (restApplicationParserFactories == null) {
final List factories = new ArrayList<>();
- if (isGenerateJaxrs() || !isGenerateSpring()) {
+ if (isGenerateJaxrs() || (!isGenerateSpring() && !isGenerateJakartaRs())) {
factories.add(new JaxrsApplicationParser.Factory());
}
+ if (isGenerateJakartaRs() || (!isGenerateSpring() && !isGenerateJaxrs())) {
+ factories.add(new JakartaRsApplicationParser.Factory());
+ }
+
if (isGenerateSpring()) {
final String springClassName = "cz.habarta.typescript.generator.spring.SpringApplicationParser$Factory";
final Class> springClass;
@@ -786,6 +797,10 @@ public List getRestApplicationParserFactories() {
}
return restApplicationParserFactories;
}
+
+ public boolean isGenerateJakartaRs() {
+ return generateJakartaRsApplicationInterface || generateJakartaRsApplicationClient;
+ }
public boolean isGenerateJaxrs() {
return generateJaxrsApplicationInterface || generateJaxrsApplicationClient;
@@ -796,7 +811,7 @@ public boolean isGenerateSpring() {
}
public boolean isGenerateRest() {
- return isGenerateJaxrs() || isGenerateSpring();
+ return isGenerateJakartaRs() || isGenerateJaxrs() || isGenerateSpring();
}
public boolean areDefaultStringEnumsOverriddenByExtension() {
diff --git a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/compiler/ModelCompiler.java b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/compiler/ModelCompiler.java
index a4362d272..cedd58dbf 100644
--- a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/compiler/ModelCompiler.java
+++ b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/compiler/ModelCompiler.java
@@ -637,7 +637,7 @@ private void createRestClients(TsModel tsModel, SymbolTable symbolTable, ListemptyList(),
null
);
- final boolean bothInterfacesAndClients = settings.generateJaxrsApplicationInterface || settings.generateSpringApplicationInterface;
+ final boolean bothInterfacesAndClients = settings.generateJakartaRsApplicationInterface || settings.generateJaxrsApplicationInterface || settings.generateSpringApplicationInterface;
final String groupingSuffix = bothInterfacesAndClients ? null : "Client";
final Map> groupedMethods = processRestMethods(tsModel, restApplications, symbolTable, groupingSuffix, responseSymbol, optionsType, true);
for (Map.Entry> entry : groupedMethods.entrySet()) {
diff --git a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/parser/JakartaRsApplicationParser.java b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/parser/JakartaRsApplicationParser.java
new file mode 100644
index 000000000..7a6a6020a
--- /dev/null
+++ b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/parser/JakartaRsApplicationParser.java
@@ -0,0 +1,346 @@
+
+package cz.habarta.typescript.generator.parser;
+
+import cz.habarta.typescript.generator.JakartaRsApplicationScanner;
+import cz.habarta.typescript.generator.Settings;
+import cz.habarta.typescript.generator.TsType;
+import cz.habarta.typescript.generator.TypeProcessor;
+import cz.habarta.typescript.generator.TypeScriptGenerator;
+import cz.habarta.typescript.generator.type.JTypeWithNullability;
+import cz.habarta.typescript.generator.util.GenericsResolver;
+import cz.habarta.typescript.generator.util.Pair;
+import cz.habarta.typescript.generator.util.Utils;
+import jakarta.ws.rs.ApplicationPath;
+import jakarta.ws.rs.BeanParam;
+import jakarta.ws.rs.CookieParam;
+import jakarta.ws.rs.FormParam;
+import jakarta.ws.rs.HeaderParam;
+import jakarta.ws.rs.HttpMethod;
+import jakarta.ws.rs.MatrixParam;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.PathParam;
+import jakarta.ws.rs.QueryParam;
+import jakarta.ws.rs.container.Suspended;
+import jakarta.ws.rs.core.Application;
+import jakarta.ws.rs.core.Context;
+import jakarta.ws.rs.core.GenericEntity;
+import jakarta.ws.rs.core.MultivaluedMap;
+import jakarta.ws.rs.core.Response;
+import jakarta.ws.rs.core.StreamingOutput;
+import java.beans.BeanInfo;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Stream;
+
+public class JakartaRsApplicationParser extends RestApplicationParser {
+
+ public static class Factory extends RestApplicationParser.Factory {
+
+ @Override
+ public TypeProcessor getSpecificTypeProcessor() {
+ return (javaType, context) -> {
+ final Class> rawClass = Utils.getRawClassOrNull(javaType);
+ if (rawClass != null) {
+ for (Map.Entry, TsType> entry : getStandardEntityClassesMapping().entrySet()) {
+ final Class> cls = entry.getKey();
+ final TsType type = entry.getValue();
+ if (cls.isAssignableFrom(rawClass)) {
+ return type != null ? new TypeProcessor.Result(type) : null;
+ }
+ }
+ if (getDefaultExcludedClassNames().contains(rawClass.getName())) {
+ return new TypeProcessor.Result(TsType.Any);
+ }
+ }
+ return null;
+ };
+ }
+
+ @Override
+ public JakartaRsApplicationParser create(Settings settings, TypeProcessor commonTypeProcessor) {
+ return new JakartaRsApplicationParser(settings, commonTypeProcessor);
+ }
+
+ };
+
+ public JakartaRsApplicationParser(Settings settings, TypeProcessor commonTypeProcessor) {
+ super(settings, commonTypeProcessor, new RestApplicationModel(RestApplicationType.JakartaRs));
+ }
+
+ @Override
+ public Result tryParse(SourceType> sourceType) {
+ if (!(sourceType.type instanceof Class>)) {
+ return null;
+ }
+ final Class> cls = (Class>) sourceType.type;
+
+ // application
+ if (Application.class.isAssignableFrom(cls)) {
+ final ApplicationPath applicationPathAnnotation = cls.getAnnotation(ApplicationPath.class);
+ if (applicationPathAnnotation != null) {
+ model.setApplicationPath(applicationPathAnnotation.value());
+ }
+ model.setApplicationName(cls.getSimpleName());
+ final List> discoveredTypes = JakartaRsApplicationScanner.scanJakartaRsApplication(cls, isClassNameExcluded);
+ return new Result(discoveredTypes);
+ }
+
+ // resource
+ final Path path = cls.getAnnotation(Path.class);
+ if (path != null) {
+ TypeScriptGenerator.getLogger().verbose("Parsing Jakarta RS resource: " + cls.getName());
+ final Result result = new Result();
+ parseResource(result, new ResourceContext(cls, path.value()), cls);
+ return result;
+ }
+
+ return null;
+ }
+
+ private void parseResource(Result result, ResourceContext context, Class> resourceClass) {
+ // subContext
+ final Map pathParamTypes = new LinkedHashMap<>();
+ for (Field field : resourceClass.getDeclaredFields()) {
+ final PathParam pathParamAnnotation = field.getAnnotation(PathParam.class);
+ if (pathParamAnnotation != null) {
+ pathParamTypes.put(pathParamAnnotation.value(), field.getType());
+ }
+ }
+ final ResourceContext subContext = context.subPathParamTypes(pathParamTypes);
+ // parse resource methods
+ final List methods = Arrays.asList(resourceClass.getMethods());
+ Collections.sort(methods, Utils.methodComparator());
+ for (Method method : methods) {
+ parseResourceMethod(result, subContext, resourceClass, method);
+ }
+ }
+
+ private void parseResourceMethod(Result result, ResourceContext context, Class> resourceClass, Method method) {
+ final Path pathAnnotation = method.getAnnotation(Path.class);
+ // subContext
+ context = context.subPath(pathAnnotation != null ? pathAnnotation.value() : null);
+ final Map pathParamTypes = new LinkedHashMap<>();
+ for (Parameter parameter : method.getParameters()) {
+ final PathParam pathParamAnnotation = parameter.getAnnotation(PathParam.class);
+ if (pathParamAnnotation != null) {
+ pathParamTypes.put(pathParamAnnotation.value(), parameter.getParameterizedType());
+ }
+ }
+ context = context.subPathParamTypes(pathParamTypes);
+ // JAX-RS specification - 3.3 Resource Methods
+ final HttpMethod httpMethod = getHttpMethod(method);
+ if (httpMethod != 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, resourceClass, method.getName());
+ }
+ }
+ }
+ if (swaggerOperation.hidden) {
+ return;
+ }
+ // path parameters
+ final List pathParams = new ArrayList<>();
+ final PathTemplate pathTemplate = PathTemplate.parse(context.path);
+ for (PathTemplate.Part part : pathTemplate.getParts()) {
+ if (part instanceof PathTemplate.Parameter) {
+ final PathTemplate.Parameter parameter = (PathTemplate.Parameter) part;
+ final Type type = context.pathParamTypes.get(parameter.getOriginalName());
+ final Type paramType = type != null ? type : String.class;
+ final Type resolvedParamType = GenericsResolver.resolveType(resourceClass, paramType, method.getDeclaringClass());
+ pathParams.add(new MethodParameterModel(parameter.getValidName(), resolvedParamType));
+ foundType(result, resolvedParamType, resourceClass, method.getName());
+ }
+ }
+ // query parameters
+ final List queryParams = new ArrayList<>();
+ for (Parameter param : method.getParameters()) {
+ final QueryParam queryParamAnnotation = param.getAnnotation(QueryParam.class);
+ if (queryParamAnnotation != null) {
+ queryParams.add(new RestQueryParam.Single(new MethodParameterModel(queryParamAnnotation.value(), param.getParameterizedType()), false));
+ foundType(result, param.getParameterizedType(), resourceClass, method.getName());
+ }
+ final BeanParam beanParamAnnotation = param.getAnnotation(BeanParam.class);
+ if (beanParamAnnotation != null) {
+ final Class> beanParamClass = param.getType();
+ final BeanModel paramBean = getQueryParameters(beanParamClass);
+ if (paramBean != null) {
+ queryParams.add(new RestQueryParam.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 parameterTypes = settings.getTypeParser().getMethodParameterTypes(method);
+ final List> parameters = Utils.zip(Arrays.asList(method.getParameters()), parameterTypes);
+ final MethodParameterModel entityParameter = getEntityParameter(resourceClass, method, parameters);
+ if (entityParameter != null) {
+ foundType(result, entityParameter.getType(), resourceClass, method.getName());
+ }
+ // JAX-RS specification - 3.3.3 Return Type
+ final Class> returnType = method.getReturnType();
+ final Type parsedReturnType = settings.getTypeParser().getMethodReturnType(method);
+ final Type plainReturnType = JTypeWithNullability.getPlainType(parsedReturnType);
+ final Type modelReturnType;
+ if (returnType == void.class) {
+ //for async response also use swagger
+ if (hasAnyAnnotation(method.getParameters(), Collections.singletonList(Suspended.class))) {
+ if (swaggerOperation.responseType != null) {
+ modelReturnType = swaggerOperation.responseType;
+ } else {
+ modelReturnType = Object.class;
+ }
+ } else {
+ modelReturnType = returnType;
+ }
+ } else if (returnType == Response.class) {
+ if (swaggerOperation.responseType != null) {
+ modelReturnType = swaggerOperation.responseType;
+ } else {
+ modelReturnType = Object.class;
+ }
+ } else if (plainReturnType instanceof ParameterizedType && returnType == GenericEntity.class) {
+ final ParameterizedType parameterizedReturnType = (ParameterizedType) plainReturnType;
+ modelReturnType = parameterizedReturnType.getActualTypeArguments()[0];
+ } else {
+ modelReturnType = parsedReturnType;
+ }
+ final Type resolvedModelReturnType = GenericsResolver.resolveType(resourceClass, modelReturnType, method.getDeclaringClass());
+ foundType(result, resolvedModelReturnType, resourceClass, method.getName());
+ // comments
+ final List comments = Swagger.getOperationComments(swaggerOperation);
+ // create method
+ model.getMethods().add(new RestMethodModel(resourceClass, method.getName(), resolvedModelReturnType, method,
+ context.rootResource, httpMethod.value(), context.path, pathParams, queryParams, entityParameter, comments));
+ }
+ // JAX-RS specification - 3.4.1 Sub Resources
+ if (pathAnnotation != null && httpMethod == null) {
+ parseResource(result, context, method.getReturnType());
+ }
+ }
+
+ private static HttpMethod getHttpMethod(Method method) {
+ for (Annotation annotation : method.getAnnotations()) {
+ final HttpMethod httpMethodAnnotation = annotation.annotationType().getAnnotation(HttpMethod.class);
+ if (httpMethodAnnotation != null) {
+ return httpMethodAnnotation;
+ }
+ }
+ return null;
+ }
+
+ private static BeanModel getQueryParameters(Class> paramBean) {
+ final List properties = new ArrayList<>();
+ final List fields = Utils.getAllFields(paramBean);
+ for (Field field : fields) {
+ final QueryParam annotation = field.getAnnotation(QueryParam.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 QueryParam annotation = writeMethod.getAnnotation(QueryParam.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> parameters) {
+ for (Pair pair : parameters) {
+ if (!Utils.hasAnyAnnotation(annotationClass -> pair.getValue1().getAnnotation(annotationClass), Arrays.asList(
+ MatrixParam.class,
+ QueryParam.class,
+ PathParam.class,
+ CookieParam.class,
+ HeaderParam.class,
+ Suspended.class,
+ Context.class,
+ FormParam.class,
+ BeanParam.class
+ ))) {
+ final Type resolvedType = GenericsResolver.resolveType(resourceClass, pair.getValue2(), method.getDeclaringClass());
+ return new MethodParameterModel(pair.getValue1().getName(), resolvedType);
+ }
+ }
+ return null;
+ }
+
+ private static boolean hasAnyAnnotation(Parameter[] parameters, List> annotationClasses) {
+ return Stream.of(parameters)
+ .anyMatch(parameter -> Utils.hasAnyAnnotation(parameter::getAnnotation, annotationClasses));
+ }
+
+ private static Map, TsType> getStandardEntityClassesMapping() {
+ // JAX-RS specification - 4.2.4 Standard Entity Providers
+ if (standardEntityClassesMapping == null) {
+ final Map, TsType> map = new LinkedHashMap<>();
+ // null value means that class is handled by DefaultTypeProcessor
+ map.put(byte[].class, TsType.Any);
+ map.put(java.lang.String.class, null);
+ map.put(java.io.InputStream.class, TsType.Any);
+ map.put(java.io.Reader.class, TsType.Any);
+ map.put(java.io.File.class, TsType.Any);
+ map.put(javax.activation.DataSource.class, TsType.Any);
+ map.put(javax.xml.transform.Source.class, TsType.Any);
+ map.put(javax.xml.bind.JAXBElement.class, null);
+ map.put(MultivaluedMap.class, TsType.Any);
+ map.put(StreamingOutput.class, TsType.Any);
+ map.put(java.lang.Boolean.class, null);
+ map.put(java.lang.Character.class, null);
+ map.put(java.lang.Number.class, null);
+ map.put(long.class, null);
+ map.put(int.class, null);
+ map.put(short.class, null);
+ map.put(byte.class, null);
+ map.put(double.class, null);
+ map.put(float.class, null);
+ map.put(boolean.class, null);
+ map.put(char.class, null);
+ standardEntityClassesMapping = map;
+ }
+ return standardEntityClassesMapping;
+ }
+
+ private static Map, TsType> standardEntityClassesMapping;
+
+ private static List getDefaultExcludedClassNames() {
+ return Arrays.asList(
+ "org.glassfish.jersey.media.multipart.FormDataBodyPart"
+ );
+ }
+
+}
diff --git a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/parser/RestApplicationType.java b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/parser/RestApplicationType.java
index 209538e18..ceb45acaa 100644
--- a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/parser/RestApplicationType.java
+++ b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/parser/RestApplicationType.java
@@ -8,7 +8,8 @@
public enum RestApplicationType {
Jaxrs(settings -> settings.generateJaxrsApplicationInterface, settings -> settings.generateJaxrsApplicationClient),
- Spring(settings -> settings.generateSpringApplicationInterface, settings -> settings.generateSpringApplicationClient);
+ Spring(settings -> settings.generateSpringApplicationInterface, settings -> settings.generateSpringApplicationClient),
+ JakartaRs(settings -> settings.generateJakartaRsApplicationInterface, settings -> settings.generateJakartaRsApplicationClient);
private RestApplicationType(Function generateInterface, Function generateClient) {
this.generateInterface = generateInterface;
diff --git a/typescript-generator-core/src/test/java/cz/habarta/typescript/generator/JakartaRsApplicationTest.java b/typescript-generator-core/src/test/java/cz/habarta/typescript/generator/JakartaRsApplicationTest.java
new file mode 100644
index 000000000..253d4e324
--- /dev/null
+++ b/typescript-generator-core/src/test/java/cz/habarta/typescript/generator/JakartaRsApplicationTest.java
@@ -0,0 +1,736 @@
+
+package cz.habarta.typescript.generator;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import cz.habarta.typescript.generator.compiler.ModelCompiler;
+import cz.habarta.typescript.generator.parser.BeanModel;
+import cz.habarta.typescript.generator.parser.JakartaRsApplicationParser;
+import cz.habarta.typescript.generator.parser.Model;
+import cz.habarta.typescript.generator.parser.SourceType;
+import cz.habarta.typescript.generator.type.JGenericArrayType;
+import cz.habarta.typescript.generator.type.JTypeWithNullability;
+import io.github.classgraph.ClassGraph;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+import jakarta.ws.rs.ApplicationPath;
+import jakarta.ws.rs.BeanParam;
+import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.CookieParam;
+import jakarta.ws.rs.FormParam;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.HeaderParam;
+import jakarta.ws.rs.MatrixParam;
+import jakarta.ws.rs.POST;
+import jakarta.ws.rs.PUT;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.PathParam;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.QueryParam;
+import jakarta.ws.rs.container.AsyncResponse;
+import jakarta.ws.rs.container.Suspended;
+import jakarta.ws.rs.core.Application;
+import jakarta.ws.rs.core.Context;
+import jakarta.ws.rs.core.GenericEntity;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.MultivaluedMap;
+import jakarta.ws.rs.core.Response;
+import jakarta.ws.rs.core.StreamingOutput;
+import java.io.File;
+import java.io.InputStream;
+import java.io.Reader;
+import java.lang.reflect.Type;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Predicate;
+import javax.activation.DataSource;
+import javax.xml.bind.JAXBElement;
+import javax.xml.transform.Source;
+import javax.xml.transform.dom.DOMSource;
+import org.glassfish.jersey.jackson.JacksonFeature;
+import org.glassfish.jersey.jdkhttp.JdkHttpServerFactory;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.junit.Assert;
+import org.junit.Test;
+
+
+@SuppressWarnings("unused")
+public class JakartaRsApplicationTest {
+
+ @Test
+ public void testReturnedTypesFromApplication() {
+ final List> sourceTypes = JakartaRsApplicationScanner.scanJakartaRsApplication(TestApplication.class, null);
+ List types = getTypes(sourceTypes);
+ final List expectedTypes = Arrays.asList(
+ TestApplication.class,
+ TestResource1.class
+ );
+ assertHasSameItems(expectedTypes, types);
+ }
+
+ @Test
+ public void testReturnedTypesFromResource() {
+ Settings settings = TestUtils.settings();
+ settings.generateJakartaRsApplicationInterface = true;
+
+ JakartaRsApplicationParser jakartaRsApplicationParser = createJakartaRsApplicationParser(settings);
+ final JakartaRsApplicationParser.Result result = jakartaRsApplicationParser.tryParse(new SourceType<>(TestResource1.class));
+ Assert.assertNotNull(result);
+ List types = getTypes(result.discoveredTypes);
+ final List expectedTypes = Arrays.asList(
+ A.class,
+ new TypeReference>(){}.getType(),
+ C.class,
+ new TypeReference>(){}.getType(),
+ List.class,
+ E.class,
+ new TypeReference>(){}.getType(),
+ G.class,
+ new TypeReference
+
+
+
+
+ Returns person with specified ID.
+
+
+
+
+
+
+
+
+
+ address-id
+
+
+
+
+
+
+
+
+ address/{address-id}
+
+
+
+
+
+
+ people/{personId}
+
+
+
+
+
+
+
+ personId
+
+
+
+
diff --git a/typescript-generator-gradle-plugin/src/main/java/cz/habarta/typescript/generator/gradle/GenerateTask.java b/typescript-generator-gradle-plugin/src/main/java/cz/habarta/typescript/generator/gradle/GenerateTask.java
index a8fb841a1..12d43310b 100644
--- a/typescript-generator-gradle-plugin/src/main/java/cz/habarta/typescript/generator/gradle/GenerateTask.java
+++ b/typescript-generator-gradle-plugin/src/main/java/cz/habarta/typescript/generator/gradle/GenerateTask.java
@@ -90,6 +90,8 @@ public class GenerateTask extends DefaultTask {
public boolean disableTaggedUnions;
public boolean generateReadonlyAndWriteonlyJSDocTags;
public boolean ignoreSwaggerAnnotations;
+ public boolean generateJakartaRsApplicationInterface;
+ public boolean generateJakartaRsApplicationClient;
public boolean generateJaxrsApplicationInterface;
public boolean generateJaxrsApplicationClient;
public boolean generateSpringApplicationInterface;
@@ -179,6 +181,8 @@ private Settings createSettings(URLClassLoader classLoader) {
settings.disableTaggedUnions = disableTaggedUnions;
settings.generateReadonlyAndWriteonlyJSDocTags = generateReadonlyAndWriteonlyJSDocTags;
settings.ignoreSwaggerAnnotations = ignoreSwaggerAnnotations;
+ settings.generateJakartaRsApplicationInterface = generateJakartaRsApplicationInterface;
+ settings.generateJakartaRsApplicationClient = generateJakartaRsApplicationClient;
settings.generateJaxrsApplicationInterface = generateJaxrsApplicationInterface;
settings.generateJaxrsApplicationClient = generateJaxrsApplicationClient;
settings.generateSpringApplicationInterface = generateSpringApplicationInterface;
diff --git a/typescript-generator-maven-plugin/src/main/java/cz/habarta/typescript/generator/maven/GenerateMojo.java b/typescript-generator-maven-plugin/src/main/java/cz/habarta/typescript/generator/maven/GenerateMojo.java
index 9bd014eba..9f1613782 100644
--- a/typescript-generator-maven-plugin/src/main/java/cz/habarta/typescript/generator/maven/GenerateMojo.java
+++ b/typescript-generator-maven-plugin/src/main/java/cz/habarta/typescript/generator/maven/GenerateMojo.java
@@ -526,6 +526,18 @@ public class GenerateMojo extends AbstractMojo {
*/
@Parameter
private boolean ignoreSwaggerAnnotations;
+
+ /**
+ * If true
interface for Jakarta-RS REST application will be generated.
+ */
+ @Parameter
+ private boolean generateJakartaRsApplicationInterface;
+
+ /**
+ * If true
client for Jakarta-RS REST application will be generated.
+ */
+ @Parameter
+ private boolean generateJakartaRsApplicationClient;
/**
* If true
interface for JAX-RS REST application will be generated.
@@ -937,6 +949,8 @@ private Settings createSettings(URLClassLoader classLoader) {
settings.disableTaggedUnions = disableTaggedUnions;
settings.generateReadonlyAndWriteonlyJSDocTags = generateReadonlyAndWriteonlyJSDocTags;
settings.ignoreSwaggerAnnotations = ignoreSwaggerAnnotations;
+ settings.generateJakartaRsApplicationInterface = generateJakartaRsApplicationInterface;
+ settings.generateJakartaRsApplicationClient = generateJakartaRsApplicationClient;
settings.generateJaxrsApplicationInterface = generateJaxrsApplicationInterface;
settings.generateJaxrsApplicationClient = generateJaxrsApplicationClient;
settings.generateSpringApplicationInterface = generateSpringApplicationInterface;