Skip to content

Commit ea3ebb1

Browse files
committed
Merge remote-tracking branch 'upstream/master' into multival
2 parents 6bc5897 + 797ec6c commit ea3ebb1

File tree

20 files changed

+523
-249
lines changed

20 files changed

+523
-249
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
[![Build](https://github.com/avaje/avaje-http/actions/workflows/build.yml/badge.svg)](https://github.com/avaje/avaje-http/actions/workflows/build.yml)
33
<img src="https://img.shields.io/maven-central/v/io.avaje/avaje-http-api.svg?label=Maven%20Central">
44
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/avaje/avaje-inject/blob/master/LICENSE)
5+
[![Discord](https://img.shields.io/discord/1074074312421683250?color=%237289da&label=discord)](https://discord.gg/Qcqf9R27BR)
56

67
HTTP server and client libraries via code generation.
78

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package io.avaje.http.api;
2+
3+
import static java.lang.annotation.ElementType.METHOD;
4+
import static java.lang.annotation.RetentionPolicy.RUNTIME;
5+
6+
import java.lang.annotation.Retention;
7+
import java.lang.annotation.Target;
8+
import java.time.temporal.ChronoUnit;
9+
10+
/**
11+
* Overrides global request timeout for this endpoint.
12+
*
13+
* <pre>{@code
14+
* @Client
15+
* interface CustomerApi {
16+
* @Get("/{id}")
17+
* @RequestTimeout(value = 1, ChronoUnit.SECONDS)
18+
* Customer getById(long id);
19+
* }
20+
*
21+
* }</pre>
22+
*/
23+
@Target(METHOD)
24+
@Retention(RUNTIME)
25+
public @interface RequestTimeout {
26+
long value();
27+
28+
ChronoUnit chronoUnit() default ChronoUnit.MILLIS;
29+
}

http-client/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@
8383
<dependency>
8484
<groupId>io.avaje</groupId>
8585
<artifactId>avaje-http-api</artifactId>
86-
<version>1.20</version>
86+
<version>${project.version}</version>
8787
<scope>test</scope>
8888
</dependency>
8989

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

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import io.avaje.http.generator.core.*;
44

55
import javax.lang.model.element.TypeElement;
6+
import java.util.Optional;
67
import java.util.Set;
78
import java.util.stream.Collectors;
89

@@ -24,6 +25,7 @@ class ClientMethodWriter {
2425
private MethodParam bodyHandlerParam;
2526
private String methodGenericParams = "";
2627
private final boolean useJsonb;
28+
private final Optional<RequestTimeoutPrism> timeout;
2729

2830
ClientMethodWriter(MethodReader method, Append writer, ProcessingContext ctx, boolean useJsonb) {
2931
this.method = method;
@@ -32,6 +34,7 @@ class ClientMethodWriter {
3234
this.ctx = ctx;
3335
this.returnType = Util.parseType(method.returnType());
3436
this.useJsonb = useJsonb;
37+
this.timeout = method.timeout();
3538
}
3639

3740
void addImportTypes(ControllerReader reader) {
@@ -86,12 +89,18 @@ void write() {
8689
writeQueryParams(pathSegments);
8790
writeBeanParams(pathSegments);
8891
writeFormParams(pathSegments);
92+
timeout.ifPresent(this::writeTimeout);
8993
writeBody();
9094
writeEnd();
9195
}
9296

93-
private void writeEnd() {
94-
WebMethod webMethod = method.webMethod();
97+
private void writeTimeout(RequestTimeoutPrism p) {
98+
99+
writer.append(" .requestTimeout(of(%s, %s))", p.value(), p.chronoUnit()).eol();
100+
}
101+
102+
private void writeEnd() {
103+
final var webMethod = method.webMethod();
95104
writer.append(" .%s()", webMethod.name()).eol();
96105
if (returnType == UType.VOID) {
97106
writer.append(" .asVoid();").eol();

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

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,14 @@
33
import java.io.IOException;
44
import java.io.Writer;
55
import java.util.LinkedHashSet;
6-
import java.util.List;
6+
import java.util.Objects;
77
import java.util.Set;
88

99
import javax.annotation.processing.AbstractProcessor;
1010
import javax.annotation.processing.ProcessingEnvironment;
1111
import javax.annotation.processing.RoundEnvironment;
1212
import javax.annotation.processing.SupportedAnnotationTypes;
1313
import javax.lang.model.SourceVersion;
14-
import javax.lang.model.element.AnnotationMirror;
15-
import javax.lang.model.element.AnnotationValue;
1614
import javax.lang.model.element.Element;
1715
import javax.lang.model.element.TypeElement;
1816
import javax.tools.FileObject;
@@ -84,22 +82,11 @@ private void writeServicesFile() {
8482
}
8583

8684
private void writeForImported(Element importedElement) {
87-
for (AnnotationMirror annotationMirror : importedElement.getAnnotationMirrors()) {
88-
for (AnnotationValue value : annotationMirror.getElementValues().values()) {
89-
for (Object apiClassDef : (List<?>) value.getValue()) {
90-
writeImported(apiClassDef.toString());
91-
}
92-
}
93-
}
94-
}
9585

96-
private void writeImported(String fullName) {
97-
// trim .class suffix
98-
String apiClassName = fullName.substring(0, fullName.length() - 6);
99-
TypeElement typeElement = ctx.typeElement(apiClassName);
100-
if (typeElement != null) {
101-
writeClient(typeElement);
102-
}
86+
ImportPrism.getInstanceOn(importedElement).types().stream()
87+
.map(ctx::asElement)
88+
.filter(Objects::nonNull)
89+
.forEach(this::writeClient);
10390
}
10491

10592
private void writeClient(Element controller) {

http-generator-core/pom.xml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,7 @@
1111
<relativePath>..</relativePath>
1212
</parent>
1313

14-
<properties>
15-
<swagger.version>2.0.8</swagger.version>
16-
</properties>
17-
1814
<dependencies>
19-
20-
2115
<dependency>
2216
<groupId>io.avaje</groupId>
2317
<artifactId>avaje-prisms</artifactId>
@@ -34,6 +28,12 @@
3428
<scope>provided</scope>
3529
</dependency>
3630

31+
<dependency>
32+
<groupId>io.swagger.core.v3</groupId>
33+
<artifactId>swagger-annotations</artifactId>
34+
<version>${swagger.version}</version>
35+
<scope>provided</scope>
36+
</dependency>
3737
<dependency>
3838
<groupId>io.swagger.core.v3</groupId>
3939
<artifactId>swagger-models</artifactId>

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

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import java.io.IOException;
44
import java.util.Set;
5-
65
import javax.annotation.processing.AbstractProcessor;
76
import javax.annotation.processing.ProcessingEnvironment;
87
import javax.annotation.processing.RoundEnvironment;
@@ -41,6 +40,7 @@ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment
4140
if (ctx.isOpenApiAvailable()) {
4241
readOpenApiDefinition(round);
4342
readTagDefinitions(round);
43+
readSecuritySchemes(round);
4444
}
4545

4646
final Set<? extends Element> controllers =
@@ -75,7 +75,19 @@ private void readTagDefinitions(RoundEnvironment round) {
7575
ctx.doc().addTagsDefinition(element);
7676
}
7777
}
78-
78+
79+
private void readSecuritySchemes(RoundEnvironment round) {
80+
Set<? extends Element> elements = round.getElementsAnnotatedWith(ctx.typeElement(SecuritySchemePrism.PRISM_TYPE));
81+
for (Element element : elements) {
82+
ctx.doc().addSecurityScheme(element);
83+
}
84+
85+
elements = round.getElementsAnnotatedWith(ctx.typeElement(SecuritySchemesPrism.PRISM_TYPE));
86+
for (Element element : elements) {
87+
ctx.doc().addSecuritySchemes(element);
88+
}
89+
}
90+
7991
private void writeOpenAPI() {
8092
ctx.doc().writeApi();
8193
}

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

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,24 @@
11
package io.avaje.http.generator.core;
22

3+
import io.avaje.http.generator.core.javadoc.Javadoc;
4+
import io.avaje.http.generator.core.openapi.MethodDocBuilder;
35
import java.util.ArrayList;
6+
import java.util.HashMap;
47
import java.util.List;
58
import java.util.Optional;
9+
import java.util.function.Consumer;
610
import java.util.function.Function;
711
import java.util.function.Predicate;
812
import java.util.stream.Collectors;
913
import java.util.stream.Stream;
10-
14+
import javax.lang.model.element.AnnotationMirror;
1115
import javax.lang.model.element.Element;
1216
import javax.lang.model.element.ExecutableElement;
1317
import javax.lang.model.element.VariableElement;
1418
import javax.lang.model.type.ExecutableType;
1519
import javax.lang.model.type.TypeKind;
1620
import javax.lang.model.type.TypeMirror;
1721

18-
import io.avaje.http.generator.core.javadoc.Javadoc;
19-
import io.avaje.http.generator.core.openapi.MethodDocBuilder;
20-
2122
public class MethodReader {
2223

2324
private final ProcessingContext ctx;
@@ -31,12 +32,14 @@ public class MethodReader {
3132
*/
3233
private final List<String> methodRoles;
3334
private final Optional<ProducesPrism> producesAnnotation;
35+
private final List<SecurityRequirementPrism> securityRequirements;
3436
private final List<OpenAPIResponsePrism> apiResponses;
3537
private final ExecutableType actualExecutable;
3638
private final List<? extends TypeMirror> actualParams;
3739
private final PathSegments pathSegments;
3840
private final boolean hasValid;
3941
private final List<ExecutableElement> superMethods;
42+
private final Optional<RequestTimeoutPrism> timeout;
4043

4144
private WebMethod webMethod;
4245
private String webMethodPath;
@@ -57,9 +60,15 @@ public class MethodReader {
5760
ctx.superMethods(element.getEnclosingElement(), element.getSimpleName().toString());
5861
superMethods.forEach(m -> methodRoles.addAll(Util.findRoles(m)));
5962

63+
this.securityRequirements = readSecurityRequirements();
6064
this.apiResponses = buildApiResponses();
6165
this.javadoc = buildJavadoc(element, ctx);
62-
66+
this.timeout = RequestTimeoutPrism.getOptionalOn(element);
67+
timeout.ifPresent(
68+
p -> {
69+
bean.addStaticImportType("java.time.temporal.ChronoUnit." + p.chronoUnit());
70+
bean.addStaticImportType("java.time.Duration.of");
71+
});
6372
if (isWebMethod()) {
6473
this.hasValid = initValid();
6574
this.pathSegments = PathSegments.parse(Util.combinePath(bean.path(), webMethodPath));
@@ -130,6 +139,40 @@ public Javadoc javadoc() {
130139
return javadoc;
131140
}
132141

142+
private List<SecurityRequirementPrism> readSecurityRequirements() {
143+
var list = new ArrayList<SecurityRequirementPrism>();
144+
145+
readSecurityRequirements(element, list);
146+
for (ExecutableElement superMethod : superMethods) {
147+
readSecurityRequirements(superMethod, list);
148+
}
149+
readSecurityRequirements(bean.beanType(), list);
150+
151+
var map = new HashMap<String, SecurityRequirementPrism>();
152+
for (SecurityRequirementPrism p : list) {
153+
if (!map.containsKey(p.name())) {
154+
map.put(p.name(), p);
155+
}
156+
}
157+
return List.copyOf(map.values());
158+
}
159+
160+
private void readSecurityRequirements(Element element, List<SecurityRequirementPrism> list) {
161+
Consumer<Element> f = e -> {
162+
Optional.ofNullable(SecurityRequirementsPrism.getInstanceOn(e))
163+
.map(SecurityRequirementsPrism::value)
164+
.ifPresent(list::addAll);
165+
Optional.ofNullable(SecurityRequirementPrism.getAllInstancesOn(e))
166+
.ifPresent(list::addAll);
167+
};
168+
f.accept(element);
169+
170+
for (AnnotationMirror annotationMirror : element.getAnnotationMirrors()) {
171+
// find only one level
172+
f.accept(annotationMirror.getAnnotationType().asElement());
173+
}
174+
}
175+
133176
private List<OpenAPIResponsePrism> buildApiResponses() {
134177

135178
final var container =
@@ -260,6 +303,10 @@ public String produces() {
260303
return producesAnnotation.map(ProducesPrism::value).orElseGet(bean::produces);
261304
}
262305

306+
public List<SecurityRequirementPrism> securityRequirements() {
307+
return securityRequirements;
308+
}
309+
263310
public List<OpenAPIResponsePrism> apiResponses() {
264311
return apiResponses;
265312
}
@@ -325,4 +372,8 @@ public String bodyName() {
325372
}
326373
return "body";
327374
}
375+
376+
public Optional<RequestTimeoutPrism> timeout() {
377+
return timeout;
378+
}
328379
}

0 commit comments

Comments
 (0)