diff --git a/http-api/src/main/java/io/avaje/http/api/Headers.java b/http-api/src/main/java/io/avaje/http/api/Headers.java
new file mode 100644
index 000000000..47486a084
--- /dev/null
+++ b/http-api/src/main/java/io/avaje/http/api/Headers.java
@@ -0,0 +1,32 @@
+package io.avaje.http.api;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Headers for an Http @Client interface method.
+ *
+ *
We can put this on a method or the interface to add preset headers to the generated
+ * implementation bean property.
+ *
+ *
{@code
+ * @Headers({
+ * "Accept: application/vnd.github.v3.full+json",
+ * "User-Agent: Avaje-Sample-App"
+ * })
+ * @Get("users/{username}")
+ * User getUser(@Path("username") String username);
+ *
+ * }
+ */
+@Retention(RUNTIME)
+@Target({TYPE, METHOD})
+public @interface Headers {
+
+ /** The array of headers */
+ String[] value();
+}
diff --git a/http-generator-client/src/main/java/io/avaje/http/generator/client/ClientMethodWriter.java b/http-generator-client/src/main/java/io/avaje/http/generator/client/ClientMethodWriter.java
index a9175d406..ed838d217 100644
--- a/http-generator-client/src/main/java/io/avaje/http/generator/client/ClientMethodWriter.java
+++ b/http-generator-client/src/main/java/io/avaje/http/generator/client/ClientMethodWriter.java
@@ -7,11 +7,15 @@
import javax.lang.model.util.ElementFilter;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
+import java.util.function.Function;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
import static io.avaje.http.generator.core.ProcessingContext.*;
+import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap;
/**
@@ -35,6 +39,7 @@ final class ClientMethodWriter {
private final boolean useConfig;
private final Map segmentPropertyMap;
private final Set propertyConstants;
+ private final List> presetHeaders;
ClientMethodWriter(MethodReader method, Append writer, boolean useJsonb, Set propertyConstants) {
this.method = method;
@@ -50,6 +55,24 @@ final class ClientMethodWriter {
.filter(Segment::isProperty)
.collect(toMap(Segment::name, s -> Util.sanitizeName(s.name()).toUpperCase()));
this.propertyConstants = propertyConstants;
+ var element = method.element();
+
+ this.presetHeaders =
+ Stream.concat(
+ HeadersPrism.getOptionalOn(element).stream(),
+ HeadersPrism.getOptionalOn(element.getEnclosingElement()).stream())
+ .map(HeadersPrism::value)
+ .map(List::stream)
+ .flatMap(Function.identity())
+ .peek(
+ s -> {
+ if (!s.contains(":")) {
+ logError(element, "@Headers value must have a \":\"", method);
+ }
+ })
+ .map(s -> s.split(":", 2))
+ .filter(a -> a.length == 2)
+ .map(a -> Map.entry(a[0].trim(), a[1].trim())).collect(toList());
}
void addImportTypes(ControllerReader reader) {
@@ -272,6 +295,8 @@ private void writeHeaders() {
}
}
}
+ presetHeaders.forEach(e ->
+ writer.append(" .header(\"%s\", \"%s\")", e.getKey(), e.getValue().replace("\\", "\\\\")).eol());
}
private void writeBeanParams(PathSegments segments) {
diff --git a/http-generator-client/src/main/java/io/avaje/http/generator/client/ClientProcessor.java b/http-generator-client/src/main/java/io/avaje/http/generator/client/ClientProcessor.java
index 05b14fc04..99a3d2512 100644
--- a/http-generator-client/src/main/java/io/avaje/http/generator/client/ClientProcessor.java
+++ b/http-generator-client/src/main/java/io/avaje/http/generator/client/ClientProcessor.java
@@ -21,7 +21,9 @@
import io.avaje.http.generator.core.ControllerReader;
import io.avaje.http.generator.core.ImportPrism;
import io.avaje.http.generator.core.ProcessingContext;
+import io.avaje.prism.GeneratePrism;
+@GeneratePrism(io.avaje.http.api.Headers.class)
@SupportedAnnotationTypes({ClientPrism.PRISM_TYPE, ImportPrism.PRISM_TYPE})
public class ClientProcessor extends AbstractProcessor {
diff --git a/http-generator-client/src/test/java/io/avaje/http/generator/client/clients/TitanFall.java b/http-generator-client/src/test/java/io/avaje/http/generator/client/clients/TitanFall.java
index 918c685fa..64d32e84f 100644
--- a/http-generator-client/src/test/java/io/avaje/http/generator/client/clients/TitanFall.java
+++ b/http-generator-client/src/test/java/io/avaje/http/generator/client/clients/TitanFall.java
@@ -2,14 +2,18 @@
import io.avaje.http.api.Client;
import io.avaje.http.api.Get;
+import io.avaje.http.api.Headers;
@Client
+@Headers("Content-Type: applicaton/json")
public interface TitanFall {
@Get("/${titan}/${drop.point}")
+ @Headers("Something: \\invalid\n\t")
Titan titanFall();
@Get("/${titan}/copium")
+ @Headers(" Accept : applicaton/json")
Titan titanFall3();
}
\ No newline at end of file