Skip to content

Commit 5679853

Browse files
committed
extendable clients
1 parent 8dcb19f commit 5679853

File tree

5 files changed

+79
-27
lines changed

5 files changed

+79
-27
lines changed

http-api/src/main/java/io/avaje/http/api/Client.java

Lines changed: 33 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,40 +11,54 @@
1111
* Marker annotation for client.
1212
*
1313
* <pre>{@code
14+
* @Client
15+
* interface CustomerApi {
16+
* ...
17+
* @Get("/{id}")
18+
* Customer getById(long id);
1419
*
15-
* @Client
16-
* interface CustomerApi {
17-
* ...
18-
* @Get("/{id}")
19-
* Customer getById(long id);
20-
*
21-
* @Post
22-
* long save(Customer customer);
23-
* }
20+
* @Post
21+
* long save(Customer customer);
22+
* }
2423
*
2524
* }</pre>
2625
*
2726
* <h3>Client.Import</h3>
28-
* <p>
29-
* When the client interface already exists in another module we
30-
* use <code>Client.Import</code> to generate the client.
31-
* <p>
32-
* Specify the <code>@Client.Import</code> on the package or class
33-
* to refer to the client interface we want to generate.
3427
*
35-
* <pre>{@code
28+
* <p>When the client interface already exists in another module we use <code>Client.Import</code>
29+
* to generate the client.
3630
*
37-
* @Client.Import(types = OtherApi.class)
38-
* package org.example;
31+
* <p>Specify the <code>@Client.Import</code> on the package or class to refer to the client
32+
* interface we want to generate.
33+
*
34+
* <pre>{@code
35+
* @Client.Import(types = OtherApi.class)
36+
* package org.example;
3937
*
4038
* }</pre>
4139
*/
4240
@Target(value = TYPE)
4341
@Retention(value = RUNTIME)
4442
public @interface Client {
4543

44+
/**
45+
* Flag to set whether to generate a Client Implementation. Set false if the interface exists merely to be extended by
46+
* other client interfaces
47+
*/
48+
boolean generate() default true;
49+
50+
/**
51+
* Specify <code>@Client.Import</code> on a package or class to refer to the client interface we
52+
* want to generate.
53+
*
54+
* <pre>{@code
55+
* @Client.Import(types = OtherApi.class)
56+
* package org.example;
57+
*
58+
* }</pre>
59+
*/
4660
@Target(value = {TYPE, PACKAGE})
47-
@Retention(value = RUNTIME)
61+
@Retention(RUNTIME)
4862
@interface Import {
4963

5064
/**

http-generator-client/src/main/java/io/avaje/http/generator/client/ClientProcessor.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,9 @@ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment
6565
readModule();
6666
for (final Element controller :
6767
round.getElementsAnnotatedWith(typeElement(ClientPrism.PRISM_TYPE))) {
68-
writeClient(controller);
68+
if (ClientPrism.getInstanceOn(controller).generate()) {
69+
writeClient(controller);
70+
}
6971
}
7072
for (final var importedElement : round.getElementsAnnotatedWith(typeElement(ImportPrism.PRISM_TYPE))) {
7173
writeForImported(importedElement);
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package io.avaje.http.generator.client.clients;
2+
3+
import io.avaje.http.api.Client;
4+
5+
@Client
6+
public interface ExampleClient extends UserClient {}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package io.avaje.http.generator.client.clients;
2+
3+
import io.avaje.http.api.BodyString;
4+
import io.avaje.http.api.Client;
5+
import io.avaje.http.api.Get;
6+
import io.avaje.http.api.Post;
7+
8+
@Client(generate = false)
9+
public interface UserClient {
10+
11+
@Post("/users")
12+
String createUser(@BodyString String body);
13+
14+
@Get("/users/{userId}")
15+
String getUserById(String userId);
16+
}

http-generator-core/src/main/java/io/avaje/http/generator/core/ControllerReader.java

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
public final class ControllerReader {
3232

3333
private final TypeElement beanType;
34-
private final List<Element> interfaces;
34+
private final List<TypeElement> interfaces;
3535
private final List<ExecutableElement> interfaceMethods;
3636
private final List<String> roles;
3737
private final List<MethodReader> methods = new ArrayList<>();
@@ -115,17 +115,18 @@ void addImports(boolean withSingleton) {
115115
}
116116
}
117117

118-
private List<Element> initInterfaces() {
119-
final List<Element> interfaces = new ArrayList<>();
118+
private List<TypeElement> initInterfaces() {
119+
final List<TypeElement> superInterfaces = new ArrayList<>();
120120
for (final TypeMirror anInterface : beanType.getInterfaces()) {
121-
final Element ifaceElement = asElement(anInterface);
121+
final var ifaceElement = asElement(anInterface);
122122
final var controller = ControllerPrism.getInstanceOn(ifaceElement);
123123
if (controller != null && !controller.value().isBlank()
124-
|| PathPrism.isPresent(ifaceElement)) {
125-
interfaces.add(ifaceElement);
124+
|| PathPrism.isPresent(ifaceElement)
125+
|| ClientPrism.isPresent(ifaceElement)) {
126+
superInterfaces.add(ifaceElement);
126127
}
127128
}
128-
return interfaces;
129+
return superInterfaces;
129130
}
130131

131132
private List<ExecutableElement> initInterfaceMethods() {
@@ -221,6 +222,10 @@ public void read(boolean withSingleton) {
221222
}
222223
}
223224
readSuper(beanType);
225+
226+
if (platform().getClass().getSimpleName().contains("Client")) {
227+
readInterfaces();
228+
}
224229
deriveIncludeValidation();
225230
addImports(withSingleton);
226231
}
@@ -268,6 +273,15 @@ private void readSuper(TypeElement beanType) {
268273
}
269274
}
270275

276+
/** Read methods from interfaces taking into account generics. */
277+
private void readInterfaces() {
278+
for (final var superInterfaces : interfaces) {
279+
for (final var element : ElementFilter.methodsIn(superInterfaces.getEnclosedElements())) {
280+
readMethod(element, (DeclaredType) superInterfaces.asType());
281+
}
282+
}
283+
}
284+
271285
private void readMethod(ExecutableElement element) {
272286
readMethod(element, null);
273287
}

0 commit comments

Comments
 (0)