-
Notifications
You must be signed in to change notification settings - Fork 242
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
JAX RS with generic #219
Comments
It is probably some limitation of the playground, how it parses the input. If I put just import javax.ws.rs.*;
@Path("/account")
interface AccountResource {
@GET
@Path("/test")
void test();
} it successfully generated export class AccountResourceClient {
constructor(protected httpClient: HttpClient) {
}
/**
* HTTP GET /account/test
* Java method: AccountResource.test
*/
test(options?: Object): RestResponse<void> {
return this.httpClient.request({ method: "GET", url: uriEncoding`account/test`, options: options });
}
} @jechlin do you have any comments how groovy parses the input? |
Ok, in online example it can be groovy bug. But in real app typescript generator still don't want to resolve generics. I have tried with version 2.1.406. Source: import java.io.Serializable;
import java.util.List;
import javax.ws.rs.*;
public class AccountDto {
public Integer id;
public String login;
}
public interface AbstractCrudResource<ENTITY, ID extends Serializable> {
@GET
@Path("{id}")
ENTITY get(@PathParam("id") ID id);
@POST
@Path("")
ENTITY save(ENTITY entity);
/**
* Delete entity
*/
@DELETE
@Path("{id}")
void delete(@PathParam("id") ID id);
}
@Path("/accounts/")
public interface AccountResource extends AbstractCrudResource<AccountDto,Integer>{
@GET
@Path("")
List<AccountDto> list(
@QueryParam("start") Long offset,
@QueryParam("limit") Integer limit,
@QueryParam("sort") List<String> sort);
} Result: // Generated using typescript-generator version 2.1.406 on 2018-02-13 20:45:54.
import { Observable } from 'rxjs/Observable';;
export interface HttpClient {
request<R>(requestConfig: { method: string; url: string; queryParams?: any; data?: any; copyFn?: (data: R) => R; options?: Object; }): RestResponse<R>;
}
export interface AccountResource {
/**
* HTTP DELETE /accounts/{id}
* Java method: com.test.api.providerapi.test.AccountResource.delete
*/
delete(id: ID, options?: Object): RestResponse<void>;
/**
* HTTP GET /accounts/{id}
* Java method: com.test.api.providerapi.test.AccountResource.get
*/
get(id: ID, options?: Object): RestResponse<ENTITY>;
/**
* HTTP GET /accounts
* Java method: com.test.api.providerapi.test.AccountResource.list
*/
list(queryParams?: { start?: number; limit?: number; sort?: string[]; }, options?: Object): RestResponse<AccountDto[]>;
/**
* HTTP POST /accounts
* Java method: com.test.api.providerapi.test.AccountResource.save
*/
save(arg0: ENTITY, options?: Object): RestResponse<ENTITY>;
}
export class AccountResourceClient implements AccountResource {
constructor(protected httpClient: HttpClient) {
}
/**
* HTTP DELETE /accounts/{id}
* Java method: com.test.api.providerapi.test.AccountResource.delete
*/
delete(id: ID, options?: Object): RestResponse<void> {
return this.httpClient.request({ method: "DELETE", url: uriEncoding`accounts/${id}`, options: options });
}
/**
* HTTP GET /accounts/{id}
* Java method: com.test.api.providerapi.test.AccountResource.get
*/
get(id: ID, options?: Object): RestResponse<ENTITY> {
return this.httpClient.request({ method: "GET", url: uriEncoding`accounts/${id}`, options: options });
}
/**
* HTTP GET /accounts
* Java method: com.test.api.providerapi.test.AccountResource.list
*/
list(queryParams?: { start?: number; limit?: number; sort?: string[]; }, options?: Object): RestResponse<AccountDto[]> {
return this.httpClient.request({ method: "GET", url: uriEncoding`accounts`, queryParams: queryParams, options: options });
}
/**
* HTTP POST /accounts
* Java method: com.test.api.providerapi.test.AccountResource.save
*/
save(arg0: ENTITY, options?: Object): RestResponse<ENTITY> {
return this.httpClient.request({ method: "POST", url: uriEncoding`accounts`, data: arg0, options: options });
}
}
export interface AbstractCrudResource<ENTITY, ID> {
}
export interface AccountDto {
id: number;
login: string;
}
export type RestResponse<R> = Observable<R>;
function uriEncoding(template: TemplateStringsArray, ...substitutions: any[]): string {
let result = "";
for (let i = 0; i < substitutions.length; i++) {
result += template[i];
result += encodeURIComponent(substitutions[i]);
}
result += template[template.length - 1];
return result;
} Config: <plugin>
<groupId>cz.habarta.typescript-generator</groupId>
<artifactId>typescript-generator-maven-plugin</artifactId>
<version>${maven.typescript.generator.version}</version>
<configuration>
<!--Common configuration-->
<jsonLibrary>jackson2</jsonLibrary>
<outputKind>module</outputKind>
<!--<removeTypeNameSuffix>Dto</removeTypeNameSuffix>-->
<sortDeclarations>true</sortDeclarations>
<sortTypeDeclarations>true</sortTypeDeclarations>
</configuration>
<executions>
<execution>
<id>providerapi-generate-rest</id>
<phase>prepare-package</phase>
<goals><goal>generate</goal></goals>
<configuration>
<jsonLibrary>jackson2</jsonLibrary>
<outputFileType>implementationFile</outputFileType>
<outputFile>${providerapi.ts.dir}/src/providerapi.ts</outputFile>
<outputKind>module</outputKind>
<generateJaxrsApplicationInterface>true</generateJaxrsApplicationInterface>
<generateJaxrsApplicationClient>true</generateJaxrsApplicationClient>
<jaxrsNamespacing>perResource</jaxrsNamespacing>
<classPatterns>
<pattern>com.test.api.providerapi.test.**</pattern>
</classPatterns>
<importDeclarations>
<importDeclaration>import { Observable } from 'rxjs/Observable';</importDeclaration>
</importDeclarations>
<restOptionsType>Object</restOptionsType>
<restResponseType>Observable<R></restResponseType>
</configuration>
</execution>
</executions>
</plugin> |
Now I understand what you mean. Thanks for the example. And how does it work when |
Actually, I have separted all interfaces for my REST API in the shared maven module. |
So, @vojtechhabarta , how do you think about my idea? Can we expect such functionality of your generator in near future? |
I would add this functionality but I am still thinking how to resolve generic variables in inherited methods. It seems that it is not possible to get resolved types directly using reflections. It is needed to 1. find recursively path from processed class to ancestor class which declares inherited method and 2. manually resolve generic variables on this path. Consider this example: interface Parent1<T> {
T get1();
}
interface Parent2<T> {
T get2();
}
interface Intermediate<T, U, V> extends Parent1<U>, Parent2<V> {
}
interface Child<Z> extends Comparable<Double>, Intermediate<Number, List<String>, Z> {
} When resolving return type of
Or do you think there is an easier way how to resolve generic variables correctly? |
Currently I don't have plans to implement this since it is too complex for such special (but perfectly valid) use case. |
I ran into the same issue. One way would be to use guava's TypeToken. Either by adding a dependency on guava (guess you are reluctant to this), or by shading that class and it's dependencies (Guava is under the Apache 2.0 license). Using that, it should not be too complicated. |
I was hoping a temporary workaround to this would be the following: import javax.ws.rs.*;
public class AccountDto {
public Integer id;
public String name;
}
interface AbstractCrudResource<ENTITY, ID> {
@GET
@Path("{id}")
public ENTITY get(@PathParam("id") ID id);
}
@Path("/account")
interface AccountResource extends AbstractCrudResource<AccountDto, Integer> {
@GET
@Path("/test")
void test();
@Override
public AccountDto get(Integer id); // <-- added this
} Unfortunately, this doesn't do anything as the JAX annotations aren't annotated with (This would probably not be of any help for #380, but for JAX RS users it's at least something) Edit: tried adding the annotations to the overridden method, then it generates a duplicate method with a weird name. In my case: |
I pushed generics resolution in JAX-RS resources. |
Thanks! I will try it in my project tomorrow! |
Yes it works! Thanks a lot! |
Released in version 2.17.558. |
Hello!
Seems that there is bug when generating JAX RS. (I have tried it online on https://jechlin.github.io/ts-gen-aws/)
JAVA source:
Config:
Output:
So, whats wrong?
The text was updated successfully, but these errors were encountered: