diff --git a/Dialects.md b/Dialects.md
new file mode 100644
index 0000000..83168c4
--- /dev/null
+++ b/Dialects.md
@@ -0,0 +1,11 @@
+# Custom dialects
+
+Defining a new dialect is possible by depending on rest-ahead-processor. Required steps are as following:
+
+1. Create a class implementing `io.github.zskamljic.restahead.polyglot.Dialect`.
+2. Create a file in `main/resources/META-INF/services` named `io.github.zskamljic.restahead.polyglot.Dialect` (note that
+ this is a file name, not a Java package)
+3. In created file add the line with FQCN of the class created in #1.
+4. In project where you want the dialect to be used add the dependency with at least `provided` scope.
+
+For sample implementation see Spring Dialect.
\ No newline at end of file
diff --git a/Readme.md b/Readme.md
index 29528df..a1ed166 100644
--- a/Readme.md
+++ b/Readme.md
@@ -21,6 +21,7 @@ approach.
- [Query](#queries)
- [Responses](#response-types)
- [Spring Boot](#spring-boot)
+- [Dialects](#dialects)
## Introduction
@@ -357,6 +358,40 @@ public interface DemoService {
injection. URL property needs to be provided to have a baseUrl configured, converter property is optional and is
required only if the service requires one, see [response types](#response-types).
+### Dialects
+
+The code generator allows for usage of multiple dialects (Default being RestAhead). For example, Spring dialect can be
+used, by adding the dependency:
+
+```xml
+
+
+ io.github.zskamljic
+ rest-ahead-spring-dialect
+ ${rest.ahead.version}
+
+```
+
+It can then be used as following:
+
+```java
+interface SpringService {
+ @GetMappin("/get")
+ Response performGet(@RequestHeader String header, @RequestParam String query);
+
+ @RequestMapping(method = RequestMethod.GET, value = "/{param}")
+ HttpBinResponse get2(@PathVariable String param);
+
+ @PostMapping("/multipart")
+ HttpBinResponse postFile(@RequestPart MultiPartFile file);
+
+ @PostMapping("/customBody")
+ HttpBinResponse postFormData(@RequestPart Map body);
+}
+```
+
+Info on how to declare a new dialect can be seen in [Dialects](Dialects.md)
+
## Adding to project
Add the dependencies as following:
diff --git a/demo/pom.xml b/demo/pom.xml
index 983a6ad..0ea5e5e 100644
--- a/demo/pom.xml
+++ b/demo/pom.xml
@@ -23,6 +23,12 @@
0.3.0-SNAPSHOT
provided
+
+ io.github.zskamljic
+ rest-ahead-spring-dialect
+ 0.3.0-SNAPSHOT
+ provided
+
io.github.zskamljic
rest-ahead-jackson-converter
diff --git a/pom.xml b/pom.xml
index c9c3e89..e17c96a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -22,6 +22,7 @@
rest-ahead-jackson-converter
test-report-aggregator
rest-ahead-spring
+ rest-ahead-spring-dialect
@@ -29,8 +30,8 @@
17
17
5.8.2
- 4.2.0
- 3.8.1
+ 4.3.1
+ 3.9.0
2.22.2
0.8.7
@@ -42,6 +43,10 @@
java
zskamljic-github
https://sonarcloud.io
+ 1.1.3
+ 0.19
+
+ 5.3.15
https://github.com/zskamljic/rest-ahead
diff --git a/rest-ahead-client/src/main/java/io/github/zskamljic/restahead/conversion/MapFormConverter.java b/rest-ahead-client/src/main/java/io/github/zskamljic/restahead/conversion/MapFormConverter.java
new file mode 100644
index 0000000..714d5e2
--- /dev/null
+++ b/rest-ahead-client/src/main/java/io/github/zskamljic/restahead/conversion/MapFormConverter.java
@@ -0,0 +1,31 @@
+package io.github.zskamljic.restahead.conversion;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * The default converter for Map classes.
+ */
+public final class MapFormConverter {
+ private MapFormConverter() {
+ }
+
+ /**
+ * Encodes the given value in format [key]=[URL encoded value] separated by &
+ * @param value the values to encode
+ * @param type of the key
+ * @param type of the value
+ * @return the {@link InputStream} with encoded data
+ */
+ public static InputStream formEncode(Map value) {
+ var stringValue = value.entrySet()
+ .stream()
+ .map(entry -> entry.getKey() + "=" + URLEncoder.encode(String.valueOf(entry.getValue()), StandardCharsets.UTF_8))
+ .collect(Collectors.joining("&"));
+ return new ByteArrayInputStream(stringValue.getBytes(StandardCharsets.UTF_8));
+ }
+}
diff --git a/rest-ahead-processor/pom.xml b/rest-ahead-processor/pom.xml
index 3dff921..a080bd4 100644
--- a/rest-ahead-processor/pom.xml
+++ b/rest-ahead-processor/pom.xml
@@ -27,18 +27,6 @@
-
- com.google.truth
- truth
- 1.1.3
- test
-
-
- com.google.testing.compile
- compile-testing
- 0.19
- test
-
org.junit.jupiter
junit-jupiter-engine
@@ -87,17 +75,4 @@
-
-
-
- testing only
-
- [9,)
-
-
- --add-opens jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED
-
-
-
-
\ No newline at end of file
diff --git a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/encoding/FormBodyEncoding.java b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/encoding/FormBodyEncoding.java
index c25c5c0..b9c074c 100644
--- a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/encoding/FormBodyEncoding.java
+++ b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/encoding/FormBodyEncoding.java
@@ -1,6 +1,6 @@
package io.github.zskamljic.restahead.encoding;
-import io.github.zskamljic.restahead.encoding.generation.GenerationStrategy;
+import io.github.zskamljic.restahead.encoding.generation.FormConversionStrategy;
/**
* Specifies that the type should use form encoding.
@@ -8,5 +8,5 @@
* @param parameterName the name of parameter to encode
* @param strategy the strategy to use when generating the conversion code
*/
-public record FormBodyEncoding(String parameterName, GenerationStrategy strategy) implements BodyEncoding {
+public record FormBodyEncoding(String parameterName, FormConversionStrategy strategy) implements BodyEncoding {
}
diff --git a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/encoding/MultiPartParameter.java b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/encoding/MultiPartParameter.java
index 87d2198..663df89 100644
--- a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/encoding/MultiPartParameter.java
+++ b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/encoding/MultiPartParameter.java
@@ -7,13 +7,15 @@
/**
* A parameter that specifies a part of multipart request.
*
- * @param httpName the name to use in http transport
- * @param name the name of function parameter
- * @param type which type to use when generating the code, empty if it's already an appropriate type
+ * @param httpName the name to use in http transport
+ * @param name the name of function parameter
+ * @param type which type to use when generating the code, empty if it's already an appropriate type
+ * @param extraParameters extra parameters that should be sent to the constructor
*/
public record MultiPartParameter(
String httpName,
String name,
- Optional> type
+ Optional> type,
+ Optional extraParameters
) {
}
diff --git a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/encoding/generation/ClassGenerationStrategy.java b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/encoding/generation/ClassGenerationStrategy.java
index cb16bd0..872fc8a 100644
--- a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/encoding/generation/ClassGenerationStrategy.java
+++ b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/encoding/generation/ClassGenerationStrategy.java
@@ -20,9 +20,8 @@
/**
* Used to generate class to form encoded string conversion.
*/
-public record ClassGenerationStrategy(TypeMirror type) implements GenerationStrategy {
- @Override
- public MethodSpec generateMethod() {
+public record ClassGenerationStrategy(TypeMirror type) implements FormConversionStrategy {
+ public MethodSpec generate() {
var builder = MethodSpec.methodBuilder(Variables.FORM_ENCODE)
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.addParameter(TypeName.get(type), "value")
@@ -44,7 +43,7 @@ public MethodSpec generateMethod() {
* @param mirror the type for which to find a strategy
* @return generation strategy if no issues were discovered, empty otherwise
*/
- public static Optional getIfSupported(Messager messager, Elements elements, Types types, TypeMirror mirror) {
+ public static Optional getIfSupported(Messager messager, Elements elements, Types types, TypeMirror mirror) {
if (!(mirror instanceof DeclaredType declaredType)) return Optional.empty();
var getters = findGetters(declaredType);
diff --git a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/encoding/generation/GenerationStrategy.java b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/encoding/generation/FormConversionStrategy.java
similarity index 70%
rename from rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/encoding/generation/GenerationStrategy.java
rename to rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/encoding/generation/FormConversionStrategy.java
index 32f3df5..3aec652 100644
--- a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/encoding/generation/GenerationStrategy.java
+++ b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/encoding/generation/FormConversionStrategy.java
@@ -1,7 +1,5 @@
package io.github.zskamljic.restahead.encoding.generation;
-import com.squareup.javapoet.MethodSpec;
-
import javax.annotation.processing.Messager;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
@@ -12,7 +10,7 @@
/**
* Outlines the generation strategy for some type.
*/
-public sealed interface GenerationStrategy permits ClassGenerationStrategy, MapGenerationStrategy, RecordGenerationStrategy {
+public sealed interface FormConversionStrategy permits ClassGenerationStrategy, MapConversionStrategy, RecordGenerationStrategy {
/**
* The type that this strategy applies to. Return from this value will be used to ensure that only one converter
* will be generated for each type.
@@ -21,13 +19,6 @@ public sealed interface GenerationStrategy permits ClassGenerationStrategy, MapG
*/
TypeMirror type();
- /**
- * Generate the method for this type and strategy.
- *
- * @return the generated convert method.
- */
- MethodSpec generateMethod();
-
/**
* Selects an appropriate generation strategy for given type.
*
@@ -37,9 +28,9 @@ public sealed interface GenerationStrategy permits ClassGenerationStrategy, MapG
* @param mirror the type for which to find a strategy
* @return the strategy or empty if none was found
*/
- static Optional select(Messager messager, Elements elements, Types types, TypeMirror mirror) {
+ static Optional select(Messager messager, Elements elements, Types types, TypeMirror mirror) {
Stream providers = Stream.of(
- MapGenerationStrategy::getIfSupported,
+ MapConversionStrategy::getIfSupported,
RecordGenerationStrategy::getIfSupported,
ClassGenerationStrategy::getIfSupported
);
@@ -53,6 +44,6 @@ static Optional select(Messager messager, Elements elements,
*/
@FunctionalInterface
interface OptionalStrategyProvider {
- Optional getIfSupported(Messager messager, Elements elements, Types types, TypeMirror mirror);
+ Optional getIfSupported(Messager messager, Elements elements, Types types, TypeMirror mirror);
}
}
diff --git a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/encoding/generation/MapConversionStrategy.java b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/encoding/generation/MapConversionStrategy.java
new file mode 100644
index 0000000..2394a55
--- /dev/null
+++ b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/encoding/generation/MapConversionStrategy.java
@@ -0,0 +1,48 @@
+package io.github.zskamljic.restahead.encoding.generation;
+
+import io.github.zskamljic.restahead.modeling.TypeValidator;
+
+import javax.annotation.processing.Messager;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
+import javax.tools.Diagnostic;
+import java.util.Map;
+import java.util.Optional;
+
+/**
+ * Generates a form converter for maps.
+ */
+public record MapConversionStrategy(TypeMirror type) implements FormConversionStrategy {
+
+ /**
+ * Checks if provided type is a Map or one of the subclasses that has string representable keys and values.
+ *
+ * @param elements the elements to fetch type information from
+ * @param types the types utility to use for typing info
+ * @param mirror the type for which to find a strategy
+ * @return a strategy if data is valid, empty otherwise
+ */
+ public static Optional getIfSupported(Messager messager, Elements elements, Types types, TypeMirror mirror) {
+ var type = elements.getTypeElement(Map.class.getCanonicalName())
+ .asType();
+ if (!types.isAssignable(types.erasure(mirror), type)) {
+ return Optional.empty();
+ }
+ var mapType = (DeclaredType) mirror;
+ var genericArguments = mapType.getTypeArguments();
+ if (genericArguments.size() != 2) return Optional.empty();
+
+ var stringValidator = new TypeValidator(elements, types);
+ var key = genericArguments.get(0);
+ var value = genericArguments.get(1);
+
+ if (stringValidator.isUnsupportedType(key) || stringValidator.isUnsupportedType(value)) {
+ messager.printMessage(Diagnostic.Kind.ERROR, "Maps must consist of string representable values to be formEncoded", mapType.asElement());
+ return Optional.empty();
+ }
+
+ return Optional.of(new MapConversionStrategy(types.erasure(type)));
+ }
+}
diff --git a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/encoding/generation/MapGenerationStrategy.java b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/encoding/generation/MapGenerationStrategy.java
deleted file mode 100644
index e526abf..0000000
--- a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/encoding/generation/MapGenerationStrategy.java
+++ /dev/null
@@ -1,91 +0,0 @@
-package io.github.zskamljic.restahead.encoding.generation;
-
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.MethodSpec;
-import com.squareup.javapoet.ParameterizedTypeName;
-import com.squareup.javapoet.TypeName;
-import com.squareup.javapoet.TypeVariableName;
-import io.github.zskamljic.restahead.generation.Variables;
-import io.github.zskamljic.restahead.modeling.TypeValidator;
-
-import javax.annotation.processing.Messager;
-import javax.lang.model.element.Modifier;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.util.Elements;
-import javax.lang.model.util.Types;
-import javax.tools.Diagnostic;
-import java.io.ByteArrayInputStream;
-import java.io.InputStream;
-import java.net.URLEncoder;
-import java.nio.charset.StandardCharsets;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.stream.Collectors;
-
-/**
- * Generates a form converter for maps.
- */
-public record MapGenerationStrategy(TypeMirror type) implements GenerationStrategy {
-
- /**
- * Generates the map converter, mapping keys to value.
- *
- * @return the generated method
- */
- @Override
- public MethodSpec generateMethod() {
- var keyParameter = TypeVariableName.get("Key");
- var valueParameter = TypeVariableName.get("Value");
- var builder = MethodSpec.methodBuilder(Variables.FORM_ENCODE)
- .addModifiers(Modifier.STATIC, Modifier.PUBLIC)
- .addParameter(ParameterizedTypeName.get((ClassName) TypeName.get(type), keyParameter, valueParameter), "value")
- .addTypeVariables(List.of(keyParameter, valueParameter))
- .returns(InputStream.class);
-
- return builder.addStatement(
- """
- var stringValue = value.entrySet()
- .stream()
- .map(entry -> entry.getKey() + "=" + $T.encode($T.valueOf(entry.getValue()), $T.UTF_8))
- .collect($T.joining("&"))""",
- URLEncoder.class,
- String.class,
- StandardCharsets.class,
- Collectors.class
- )
- .addStatement("return new $T(stringValue.getBytes())", ByteArrayInputStream.class)
- .build();
- }
-
- /**
- * Checks if provided type is a Map or one of the subclasses that has string representable keys and values.
- *
- * @param elements the elements to fetch type information from
- * @param types the types utility to use for typing info
- * @param mirror the type for which to find a strategy
- * @return a strategy if data is valid, empty otherwise
- */
- public static Optional getIfSupported(Messager messager, Elements elements, Types types, TypeMirror mirror) {
- var type = elements.getTypeElement(Map.class.getCanonicalName())
- .asType();
- if (!types.isAssignable(types.erasure(mirror), type)) {
- return Optional.empty();
- }
- var mapType = (DeclaredType) mirror;
- var genericArguments = mapType.getTypeArguments();
- if (genericArguments.size() != 2) return Optional.empty();
-
- var stringValidator = new TypeValidator(elements, types);
- var key = genericArguments.get(0);
- var value = genericArguments.get(1);
-
- if (stringValidator.isUnsupportedType(key) || stringValidator.isUnsupportedType(value)) {
- messager.printMessage(Diagnostic.Kind.ERROR, "Maps must consist of string representable values to be formEncoded", mapType.asElement());
- return Optional.empty();
- }
-
- return Optional.of(new MapGenerationStrategy(types.erasure(type)));
- }
-}
diff --git a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/encoding/generation/RecordGenerationStrategy.java b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/encoding/generation/RecordGenerationStrategy.java
index 7351dd4..7bcb54a 100644
--- a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/encoding/generation/RecordGenerationStrategy.java
+++ b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/encoding/generation/RecordGenerationStrategy.java
@@ -24,14 +24,9 @@
/**
* Generates a converter for the given record.
*/
-public record RecordGenerationStrategy(TypeMirror type) implements GenerationStrategy {
- /**
- * The generated value, using component names as keys and their values as values.
- *
- * @return the generated method
- */
- @Override
- public MethodSpec generateMethod() {
+public record RecordGenerationStrategy(TypeMirror type) implements FormConversionStrategy {
+
+ public MethodSpec generate() {
var builder = MethodSpec.methodBuilder(Variables.FORM_ENCODE)
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.addParameter(TypeName.get(type), "value")
@@ -52,7 +47,7 @@ public MethodSpec generateMethod() {
* @param mirror the type for which to find a strategy
* @return the strategy if it can be applied, empty otherwise
*/
- public static Optional getIfSupported(Messager messager, Elements elements, Types types, TypeMirror mirror) {
+ public static Optional getIfSupported(Messager messager, Elements elements, Types types, TypeMirror mirror) {
if (!(mirror instanceof DeclaredType declaredType)) return Optional.empty();
var element = declaredType.asElement();
diff --git a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/generation/FormConverterGenerator.java b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/generation/FormConverterGenerator.java
deleted file mode 100644
index fa98af0..0000000
--- a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/generation/FormConverterGenerator.java
+++ /dev/null
@@ -1,88 +0,0 @@
-package io.github.zskamljic.restahead.generation;
-
-import com.squareup.javapoet.JavaFile;
-import com.squareup.javapoet.TypeSpec;
-import io.github.zskamljic.restahead.encoding.FormBodyEncoding;
-import io.github.zskamljic.restahead.encoding.generation.GenerationStrategy;
-import io.github.zskamljic.restahead.modeling.declaration.CallDeclaration;
-import io.github.zskamljic.restahead.modeling.declaration.ParameterDeclaration;
-import io.github.zskamljic.restahead.modeling.declaration.ServiceDeclaration;
-
-import javax.annotation.processing.Filer;
-import javax.annotation.processing.Messager;
-import javax.lang.model.element.Modifier;
-import javax.lang.model.type.TypeMirror;
-import javax.tools.Diagnostic;
-import java.io.IOException;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Optional;
-
-/**
- * Generates the FormConverter class if necessary.
- */
-public class FormConverterGenerator {
- private final Messager messager;
- private final Filer filer;
-
- public FormConverterGenerator(Messager messager, Filer filer) {
- this.messager = messager;
- this.filer = filer;
- }
-
- /**
- * Checks if the class needs to be generated and generate it if needed.
- *
- * @param serviceDeclarations the services to check for any form data.
- */
- public void generateFormEncoderIfNeeded(List serviceDeclarations) {
- var formEncodableParameters = serviceDeclarations.stream()
- .map(ServiceDeclaration::calls)
- .flatMap(Collection::stream)
- .map(CallDeclaration::parameters)
- .map(ParameterDeclaration::body)
- .flatMap(Optional::stream)
- .filter(FormBodyEncoding.class::isInstance)
- .map(FormBodyEncoding.class::cast)
- .toList();
- if (formEncodableParameters.isEmpty()) {
- return;
- }
-
- var encoder = generateFormEncoder(formEncodableParameters);
- var javaFile = JavaFile.builder(FormConverterGenerator.class.getPackageName(), encoder)
- .indent(" ")
- .build();
-
- try {
- javaFile.writeTo(filer);
- messager.printMessage(Diagnostic.Kind.NOTE, "Generated " + encoder.name);
- } catch (IOException e) {
- messager.printMessage(Diagnostic.Kind.ERROR, "Unable to write class: " + e.getMessage());
- }
- }
-
- /**
- * Generates the actual implementation.
- *
- * @param parameters the parts that require generation
- * @return the generated type.
- */
- private TypeSpec generateFormEncoder(List parameters) {
- var typeToStrategy = new HashMap();
- for (var parameter : parameters) {
- typeToStrategy.put(parameter.strategy().type(), parameter.strategy());
- }
-
- var typeBuilder = TypeSpec.classBuilder(Variables.FORM_CONVERTER)
- .addModifiers(Modifier.FINAL, Modifier.PUBLIC);
-
- var methods = typeToStrategy.values()
- .stream()
- .map(GenerationStrategy::generateMethod);
- typeBuilder.addMethods(methods::iterator);
-
- return typeBuilder.build();
- }
-}
diff --git a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/generation/MethodGenerator.java b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/generation/MethodGenerator.java
index 8ed3966..77c9fc1 100644
--- a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/generation/MethodGenerator.java
+++ b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/generation/MethodGenerator.java
@@ -1,25 +1,34 @@
package io.github.zskamljic.restahead.generation;
-import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.MethodSpec;
import io.github.zskamljic.restahead.client.requests.MultiPartRequest;
import io.github.zskamljic.restahead.client.requests.Request;
import io.github.zskamljic.restahead.client.requests.Verb;
+import io.github.zskamljic.restahead.client.requests.parts.MultiPart;
+import io.github.zskamljic.restahead.conversion.MapFormConverter;
import io.github.zskamljic.restahead.encoding.BodyEncoding;
import io.github.zskamljic.restahead.encoding.ConvertBodyEncoding;
import io.github.zskamljic.restahead.encoding.FormBodyEncoding;
import io.github.zskamljic.restahead.encoding.MultiPartBodyEncoding;
+import io.github.zskamljic.restahead.encoding.MultiPartParameter;
+import io.github.zskamljic.restahead.encoding.generation.ClassGenerationStrategy;
+import io.github.zskamljic.restahead.encoding.generation.FormConversionStrategy;
+import io.github.zskamljic.restahead.encoding.generation.MapConversionStrategy;
+import io.github.zskamljic.restahead.encoding.generation.RecordGenerationStrategy;
import io.github.zskamljic.restahead.modeling.declaration.CallDeclaration;
import io.github.zskamljic.restahead.modeling.declaration.ParameterDeclaration;
import io.github.zskamljic.restahead.modeling.declaration.RequestParameterSpec;
-import io.github.zskamljic.restahead.requests.request.RequestLine;
-import io.github.zskamljic.restahead.requests.request.path.TemplatedPath;
+import io.github.zskamljic.restahead.request.RequestLine;
+import io.github.zskamljic.restahead.request.path.TemplatedPath;
import javax.lang.model.element.Modifier;
import javax.lang.model.type.TypeMirror;
import java.util.List;
+import java.util.Optional;
+import java.util.function.Predicate;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
/**
* Used to generate methods annotated with HTTP annotations.
@@ -35,9 +44,36 @@ public class MethodGenerator {
* @return the generated methods
*/
public List generateMethods(List calls) {
- return calls.stream()
- .map(this::generateMethodBody)
- .toList();
+ var callMethods = calls.stream()
+ .map(this::generateMethodBody);
+ var convertCalls = calls.stream()
+ .map(CallDeclaration::parameters)
+ .map(ParameterDeclaration::body)
+ .flatMap(Optional::stream)
+ .filter(FormBodyEncoding.class::isInstance)
+ .map(FormBodyEncoding.class::cast)
+ .map(FormBodyEncoding::strategy)
+ .filter(Predicate.not(MapConversionStrategy.class::isInstance))
+ .distinct()
+ .map(this::generateConverterBody);
+
+ return Stream.concat(callMethods, convertCalls).toList();
+ }
+
+ /**
+ * Generate the method that will handle type conversion for form parameter.
+ *
+ * @param strategy the strategy to use
+ * @return the generated method
+ */
+ private MethodSpec generateConverterBody(FormConversionStrategy strategy) {
+ if (strategy instanceof ClassGenerationStrategy classStrategy) {
+ return classStrategy.generate();
+ } else if (strategy instanceof RecordGenerationStrategy recordStrategy) {
+ return recordStrategy.generate();
+ } else {
+ throw new IllegalStateException(strategy.getClass() + " can does not generate code.");
+ }
}
/**
@@ -76,7 +112,7 @@ private void addSendBodyStatement(
if (encoding instanceof ConvertBodyEncoding convertEncoding) {
addConvertEncoding(builder, declaredExceptions, convertEncoding.exceptions(), convertEncoding.parameterName());
} else if (encoding instanceof FormBodyEncoding formEncoding) {
- addFormEncoding(builder, formEncoding.parameterName());
+ addFormEncoding(builder, formEncoding);
} else if (encoding instanceof MultiPartBodyEncoding multipart) {
addMultipartEncoding(builder, declaredExceptions, multipart);
}
@@ -107,16 +143,23 @@ private void addConvertEncoding(
/**
* Adds form encoding using the generated type and adds a Content-Type header for this body.
*
- * @param builder the builder to add the code to
- * @param parameterName the name of the parameter
+ * @param builder the builder to add the code to
+ * @param formEncoding the encoding to use for parameter
*/
- private void addFormEncoding(MethodSpec.Builder builder, String parameterName) {
- var className = ClassName.get(MethodGenerator.class.getPackageName(), Variables.FORM_CONVERTER);
- builder.addStatement("$L.addHeader(\"Content-Type\", \"application/x-www-form-urlencoded\")", Variables.REQUEST_BUILDER)
- .addStatement(
+ private void addFormEncoding(MethodSpec.Builder builder, FormBodyEncoding formEncoding) {
+ builder.addStatement("$L.addHeader(\"Content-Type\", \"application/x-www-form-urlencoded\")", Variables.REQUEST_BUILDER);
+ var strategy = formEncoding.strategy();
+ if (strategy instanceof MapConversionStrategy) {
+ builder.addStatement(
"$L.setBody($T.$L($L))",
- Variables.REQUEST_BUILDER, className, Variables.FORM_ENCODE, parameterName
+ Variables.REQUEST_BUILDER, MapFormConverter.class, Variables.FORM_ENCODE, formEncoding.parameterName()
);
+ } else {
+ builder.addStatement(
+ "$L.setBody($L($L))",
+ Variables.REQUEST_BUILDER, Variables.FORM_ENCODE, formEncoding.parameterName()
+ );
+ }
}
/**
@@ -139,7 +182,7 @@ private void addMultipartEncoding(
builder.addCode("$T.builder()\n", MultiPartRequest.class);
for (var part : multipart.parts()) {
part.type().ifPresentOrElse(
- type -> builder.addCode("\t.addPart(new $T($S, $L))\n", type, part.httpName(), part.name()),
+ type -> addMultipartStatement(builder, type, part),
() -> builder.addCode("\t.addPart($L)\n", part.name())
);
}
@@ -148,6 +191,24 @@ private void addMultipartEncoding(
);
}
+ /**
+ * Add a multipart statement, choosing the code to add based on extra parameters
+ *
+ * @param builder the builder to add the code to
+ * @param type the type to use
+ * @param part the part from which to get the data
+ */
+ private void addMultipartStatement(
+ MethodSpec.Builder builder,
+ Class extends MultiPart> type,
+ MultiPartParameter part
+ ) {
+ part.extraParameters().ifPresentOrElse(
+ extra -> builder.addCode("\t.addPart(new $T($S, $L, $L))\n", type, part.httpName(), part.name(), extra),
+ () -> builder.addCode("\t.addPart(new $T($S, $L))\n", type, part.httpName(), part.name())
+ );
+ }
+
/**
* Add request initialization lines.
*
@@ -213,7 +274,7 @@ private void addTemplatedPath(
List paths
) {
var pathToVariable = paths.stream()
- .collect(Collectors.toMap(RequestParameterSpec::httpName, RequestParameterSpec::httpName));
+ .collect(Collectors.toMap(RequestParameterSpec::httpName, RequestParameterSpec::codeName));
var replaceBlocks = CodeBlock.builder()
.add(".setPath($S", path);
diff --git a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/generation/Variables.java b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/generation/Variables.java
index 9fed6d1..02b2434 100644
--- a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/generation/Variables.java
+++ b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/generation/Variables.java
@@ -4,7 +4,6 @@
* The names of the variables used in generated code, collected to prevent duplication and declaration in multiple places.
*/
public final class Variables {
-
private Variables() {
}
@@ -14,10 +13,10 @@ private Variables() {
public static final String CONVERTED_NAME = "convertedResponse";
public static final String CONVERTER = "converter";
public static final String DESERIALIZED = "deserializedResponse";
- public static final String FORM_CONVERTER = "FormConverter";
public static final String FORM_ENCODE = "formEncode";
public static final String HEADER_ITEM = "headerItem";
public static final String QUERY_ITEM = "queryItem";
public static final String REQUEST_BUILDER = "httpRequestBuilder";
public static final String RESPONSE = "response";
+ public static final String VALUE = "value";
}
diff --git a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/modeling/MethodModeler.java b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/modeling/MethodModeler.java
index 245062a..043619d 100644
--- a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/modeling/MethodModeler.java
+++ b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/modeling/MethodModeler.java
@@ -4,9 +4,9 @@
import io.github.zskamljic.restahead.modeling.declaration.CallDeclaration;
import io.github.zskamljic.restahead.modeling.declaration.RequestParameterSpec;
import io.github.zskamljic.restahead.modeling.validation.PathValidator;
-import io.github.zskamljic.restahead.requests.VerbMapping;
-import io.github.zskamljic.restahead.requests.request.RequestLine;
-import io.github.zskamljic.restahead.requests.request.path.TemplatedPath;
+import io.github.zskamljic.restahead.polyglot.Dialects;
+import io.github.zskamljic.restahead.request.RequestLine;
+import io.github.zskamljic.restahead.request.path.TemplatedPath;
import javax.annotation.processing.Messager;
import javax.lang.model.element.ExecutableElement;
@@ -28,11 +28,13 @@ public class MethodModeler {
private final ParameterModeler parameterModeler;
private final PathValidator pathValidator;
private final ReturnTypeModeler returnTypeModeler;
+ private final Dialects dialects;
- public MethodModeler(Messager messager, Elements elements, Types types) {
+ public MethodModeler(Messager messager, Elements elements, Types types, Dialects dialects) {
this.messager = messager;
+ this.dialects = dialects;
pathValidator = new PathValidator(messager, elements, types);
- this.parameterModeler = new ParameterModeler(messager, elements, types, pathValidator);
+ this.parameterModeler = new ParameterModeler(messager, elements, dialects, types, pathValidator);
returnTypeModeler = new ReturnTypeModeler(messager, elements, types);
}
@@ -47,7 +49,7 @@ public Optional getCallDeclaration(
ExecutableElement function,
List adapters
) {
- var presentAnnotations = VerbMapping.ANNOTATION_VERBS.stream()
+ var presentAnnotations = dialects.verbAnnotations()
.map(function::getAnnotation)
.filter(Objects::nonNull)
.toList();
@@ -58,7 +60,7 @@ public Optional getCallDeclaration(
}
var annotation = presentAnnotations.get(0);
- var requestLine = VerbMapping.annotationToVerb(annotation);
+ var requestLine = dialects.basicRequestLine(annotation);
var parameters = parameterModeler.getMethodParameters(function, requestLine.allowsBody());
var updatedLine = pathValidator.validatePathAndExtractQuery(function, requestLine, parameters);
diff --git a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/modeling/ParameterModeler.java b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/modeling/ParameterModeler.java
index a5f0725..bf9cdec 100644
--- a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/modeling/ParameterModeler.java
+++ b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/modeling/ParameterModeler.java
@@ -1,11 +1,6 @@
package io.github.zskamljic.restahead.modeling;
import io.github.zskamljic.restahead.annotations.form.FormUrlEncoded;
-import io.github.zskamljic.restahead.annotations.form.Part;
-import io.github.zskamljic.restahead.annotations.request.Body;
-import io.github.zskamljic.restahead.annotations.request.Header;
-import io.github.zskamljic.restahead.annotations.request.Path;
-import io.github.zskamljic.restahead.annotations.request.Query;
import io.github.zskamljic.restahead.client.requests.parts.FieldPart;
import io.github.zskamljic.restahead.client.requests.parts.FilePart;
import io.github.zskamljic.restahead.encoding.BodyEncoding;
@@ -13,13 +8,14 @@
import io.github.zskamljic.restahead.encoding.FormBodyEncoding;
import io.github.zskamljic.restahead.encoding.MultiPartBodyEncoding;
import io.github.zskamljic.restahead.encoding.MultiPartParameter;
-import io.github.zskamljic.restahead.encoding.generation.GenerationStrategy;
+import io.github.zskamljic.restahead.encoding.generation.FormConversionStrategy;
import io.github.zskamljic.restahead.modeling.declaration.BodyParameter;
import io.github.zskamljic.restahead.modeling.declaration.ParameterDeclaration;
import io.github.zskamljic.restahead.modeling.declaration.RequestParameterSpec;
import io.github.zskamljic.restahead.modeling.validation.HeaderValidator;
import io.github.zskamljic.restahead.modeling.validation.PathValidator;
import io.github.zskamljic.restahead.modeling.validation.QueryValidator;
+import io.github.zskamljic.restahead.polyglot.Dialects;
import javax.annotation.processing.Messager;
import javax.lang.model.element.ExecutableElement;
@@ -40,13 +36,6 @@
* Used to extract parameter info from the declaration.
*/
public class ParameterModeler {
- private static final List> REQUEST_ANNOTATIONS = List.of(
- Header.class, Path.class, Query.class
- );
- private static final List> BODY_ANNOTATIONS = List.of(
- Body.class, FormUrlEncoded.class, Part.class
- );
-
private final Messager messager;
private final PathValidator pathValidator;
private final Elements elements;
@@ -54,12 +43,20 @@ public class ParameterModeler {
private final HeaderValidator headerValidator;
private final QueryValidator queryValidator;
private final TypeMirror ioException;
-
- public ParameterModeler(Messager messager, Elements elements, Types types, PathValidator pathValidator) {
+ private final Dialects dialects;
+
+ public ParameterModeler(
+ Messager messager,
+ Elements elements,
+ Dialects dialects,
+ Types types,
+ PathValidator pathValidator
+ ) {
this.messager = messager;
- this.pathValidator = pathValidator;
this.elements = elements;
+ this.dialects = dialects;
this.types = types;
+ this.pathValidator = pathValidator;
headerValidator = new HeaderValidator(messager, elements, types);
queryValidator = new QueryValidator(messager, elements, types);
ioException = elements.getTypeElement(IOException.class.getCanonicalName())
@@ -81,11 +78,11 @@ public ParameterDeclaration getMethodParameters(ExecutableElement function, bool
var bodies = new ArrayList();
for (var parameter : parameters) {
- var requestAnnotations = REQUEST_ANNOTATIONS.stream()
+ var requestAnnotations = dialects.requestAnnotations()
.map(parameter::getAnnotation)
.filter(Objects::nonNull)
.toList();
- var bodyAnnotations = BODY_ANNOTATIONS.stream()
+ var bodyAnnotations = dialects.bodyAnnotations()
.map(parameter::getAnnotation)
.filter(Objects::nonNull)
.toList();
@@ -133,7 +130,7 @@ private Optional createBodyDeclaration(ArrayList bo
var parameter = body.parameter();
var parameterName = parameter.getSimpleName().toString();
if (body.type() == BodyParameter.Type.FORM) {
- var strategy = GenerationStrategy.select(messager, elements, types, parameter.asType());
+ var strategy = FormConversionStrategy.select(messager, elements, types, parameter.asType());
if (strategy.isEmpty()) {
messager.printMessage(Diagnostic.Kind.ERROR, "Form encoding for type " + parameter.asType() + " is not supported.", parameter);
return Optional.empty();
@@ -151,13 +148,20 @@ private Optional createBodyDeclaration(ArrayList bo
var type = body.parameter().asType();
if (typeValidator.isFileType(type)) {
exceptions.addAll(typeValidator.getPossibleException(type));
- partMap.add(new MultiPartParameter(body.httpName(), body.name(), Optional.of(FilePart.class)));
+ partMap.add(new MultiPartParameter(body.httpName(), body.name(), Optional.of(FilePart.class), Optional.empty()));
} else if (!typeValidator.isUnsupportedType(type)) {
- partMap.add(new MultiPartParameter(body.httpName(), body.name(), Optional.of(FieldPart.class)));
+ partMap.add(new MultiPartParameter(body.httpName(), body.name(), Optional.of(FieldPart.class), Optional.empty()));
} else if (typeValidator.isDirectMultipartType(type)) {
- partMap.add(new MultiPartParameter(body.httpName(), body.name(), Optional.empty()));
+ partMap.add(new MultiPartParameter(body.httpName(), body.name(), Optional.empty(), Optional.empty()));
} else {
- messager.printMessage(Diagnostic.Kind.ERROR, "Type is not supported for multipart body.", body.parameter());
+ dialects.createBodyPart(elements, types, body, type)
+ .ifPresentOrElse(
+ paramWithException -> {
+ partMap.add(paramWithException.parameter());
+ exceptions.addAll(paramWithException.exceptions());
+ },
+ () -> messager.printMessage(Diagnostic.Kind.ERROR, "Type is not supported for multipart body.", body.parameter())
+ );
}
}
return Optional.of(new MultiPartBodyEncoding(partMap, exceptions.stream().toList()));
@@ -185,12 +189,16 @@ private void handleRequestAnnotations(
}
var annotation = requestAnnotations.get(0);
- if (annotation instanceof Header header) {
- headerValidator.getHeaderSpec(header.value(), parameter).ifPresent(headers::add);
- } else if (annotation instanceof Query query) {
- queryValidator.getQuerySpec(query.value(), parameter).ifPresent(queries::add);
- } else if (annotation instanceof Path path) {
- pathValidator.getPathSpec(path.value(), parameter).ifPresent(paths::add);
+ var requestParameter = dialects.extractRequestAnnotation(annotation);
+ if (requestParameter.isEmpty()) {
+ messager.printMessage(Diagnostic.Kind.ERROR, "No dialect could parse this parameter.", parameter);
+ return;
+ }
+ var parameterValue = requestParameter.get();
+ switch (parameterValue.type()) {
+ case HEADER -> headerValidator.getHeaderSpec(parameterValue.value(), parameter).ifPresent(headers::add);
+ case QUERY -> queryValidator.getQuerySpec(parameterValue.value(), parameter).ifPresent(queries::add);
+ case PATH -> pathValidator.getPathSpec(parameterValue.value(), parameter).ifPresent(paths::add);
}
}
@@ -208,10 +216,7 @@ private void handleBodyAnnotations(
) {
var hasFormUrlEncoded = bodyAnnotations.stream()
.anyMatch(FormUrlEncoded.class::isInstance);
- var part = bodyAnnotations.stream()
- .filter(Part.class::isInstance)
- .map(Part.class::cast)
- .findFirst();
+ var part = dialects.extractParts(bodyAnnotations);
if (hasFormUrlEncoded && part.isPresent()) {
messager.printMessage(Diagnostic.Kind.ERROR, "Request can't be both multipart and form encoded", parameter);
return;
@@ -219,8 +224,8 @@ private void handleBodyAnnotations(
var parameterName = parameter.getSimpleName().toString();
if (part.isPresent()) {
- var partAnnotation = part.get();
- var value = partAnnotation.value();
+ var partData = part.get();
+ var value = partData.value();
if (value.isBlank()) {
value = parameterName;
}
diff --git a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/modeling/ServiceModeler.java b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/modeling/ServiceModeler.java
index ea0fcb8..140ea74 100644
--- a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/modeling/ServiceModeler.java
+++ b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/modeling/ServiceModeler.java
@@ -3,7 +3,7 @@
import io.github.zskamljic.restahead.modeling.declaration.AdapterClassDeclaration;
import io.github.zskamljic.restahead.modeling.declaration.CallDeclaration;
import io.github.zskamljic.restahead.modeling.declaration.ServiceDeclaration;
-import io.github.zskamljic.restahead.requests.VerbMapping;
+import io.github.zskamljic.restahead.polyglot.Dialects;
import javax.annotation.processing.Messager;
import javax.annotation.processing.RoundEnvironment;
@@ -30,11 +30,13 @@ public class ServiceModeler {
private final Messager messager;
private final Elements elements;
private final MethodModeler methodModeler;
+ private final Dialects dialects;
- public ServiceModeler(Messager messager, Elements elements, Types types) {
+ public ServiceModeler(Messager messager, Elements elements, Types types, Dialects dialects) {
this.messager = messager;
this.elements = elements;
- methodModeler = new MethodModeler(messager, elements, types);
+ this.dialects = dialects;
+ methodModeler = new MethodModeler(messager, elements, types, dialects);
}
/**
@@ -80,7 +82,7 @@ private boolean hasInvalidDeclarations(Map>
.map(ExecutableElement.class::cast)
.toList();
for (var function : functions) {
- var annotation = VerbMapping.ANNOTATION_VERBS.stream()
+ var annotation = dialects.verbAnnotations()
.map(function::getAnnotation)
.filter(Objects::nonNull)
.toList();
@@ -109,9 +111,19 @@ private Optional createServiceDeclaration(
List functions,
List adapters
) {
+ var originalFunctions = typeElement.getEnclosedElements()
+ .stream()
+ .filter(ExecutableElement.class::isInstance)
+ .map(ExecutableElement.class::cast)
+ .toList();
var calls = functions.stream()
.map(function -> methodModeler.getCallDeclaration(function, adapters))
.flatMap(Optional::stream)
+ .sorted((o1, o2) -> {
+ var f1 = o1.function();
+ var f2 = o2.function();
+ return originalFunctions.indexOf(f1) - originalFunctions.indexOf(f2);
+ })
.toList();
// There were errors in creation of the service declaration
@@ -150,22 +162,20 @@ private void findDeclaringElements(
continue;
}
- var modifiers = executableElement.getModifiers();
- if (!modifiers.contains(Modifier.ABSTRACT)) {
- messager.printMessage(Diagnostic.Kind.ERROR, "Only abstract methods can be generated.", element);
- continue;
- }
-
var parent = executableElement.getEnclosingElement();
if (!(parent instanceof TypeElement declaringType)) {
messager.printMessage(Diagnostic.Kind.ERROR, "Only methods in classes can be generated", element);
continue;
}
- if (!(declaringType.getSuperclass() instanceof NoType)) {
- messager.printMessage(Diagnostic.Kind.ERROR, "Only interfaces support code generation at this time", element);
+ var modifiers = executableElement.getModifiers();
+ var isAbstract = modifiers.contains(Modifier.ABSTRACT);
+ var isInterface = declaringType.getSuperclass() instanceof NoType;
+ if (!isAbstract && isInterface) {
+ messager.printMessage(Diagnostic.Kind.ERROR, "Default methods in interfaces are not supported.", element);
continue;
}
+ if (!isAbstract || !isInterface) continue;
declaringElements.compute(declaringType, (typeElement, executableElements) -> {
if (executableElements == null) {
diff --git a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/modeling/declaration/CallDeclaration.java b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/modeling/declaration/CallDeclaration.java
index dcc742f..a820fa8 100644
--- a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/modeling/declaration/CallDeclaration.java
+++ b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/modeling/declaration/CallDeclaration.java
@@ -1,7 +1,7 @@
package io.github.zskamljic.restahead.modeling.declaration;
import io.github.zskamljic.restahead.encoding.FormBodyEncoding;
-import io.github.zskamljic.restahead.requests.request.RequestLine;
+import io.github.zskamljic.restahead.request.RequestLine;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.type.TypeMirror;
diff --git a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/modeling/declaration/ParameterDeclaration.java b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/modeling/declaration/ParameterDeclaration.java
index bd0731e..05e15c9 100644
--- a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/modeling/declaration/ParameterDeclaration.java
+++ b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/modeling/declaration/ParameterDeclaration.java
@@ -1,7 +1,7 @@
package io.github.zskamljic.restahead.modeling.declaration;
import io.github.zskamljic.restahead.encoding.BodyEncoding;
-import io.github.zskamljic.restahead.requests.request.PresetQuery;
+import io.github.zskamljic.restahead.request.PresetQuery;
import java.util.ArrayList;
import java.util.List;
diff --git a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/modeling/parameters/ParameterWithExceptions.java b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/modeling/parameters/ParameterWithExceptions.java
new file mode 100644
index 0000000..8be4673
--- /dev/null
+++ b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/modeling/parameters/ParameterWithExceptions.java
@@ -0,0 +1,18 @@
+package io.github.zskamljic.restahead.modeling.parameters;
+
+import io.github.zskamljic.restahead.encoding.MultiPartParameter;
+
+import javax.lang.model.type.TypeMirror;
+import java.util.Set;
+
+/**
+ * Represents a parameter with exceptions that can be thrown when it's used
+ *
+ * @param parameter the parameter that is added
+ * @param exceptions the exceptions that can be thrown
+ */
+public record ParameterWithExceptions(
+ MultiPartParameter parameter,
+ Set exceptions
+) {
+}
diff --git a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/modeling/parameters/PartData.java b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/modeling/parameters/PartData.java
new file mode 100644
index 0000000..9ba1c84
--- /dev/null
+++ b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/modeling/parameters/PartData.java
@@ -0,0 +1,7 @@
+package io.github.zskamljic.restahead.modeling.parameters;
+
+/**
+ * Contains name of the part.
+ */
+public record PartData(String value) {
+}
diff --git a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/modeling/parameters/RequestParameter.java b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/modeling/parameters/RequestParameter.java
new file mode 100644
index 0000000..456d8ea
--- /dev/null
+++ b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/modeling/parameters/RequestParameter.java
@@ -0,0 +1,7 @@
+package io.github.zskamljic.restahead.modeling.parameters;
+
+public record RequestParameter(Type type, String value) {
+ public enum Type {
+ HEADER, QUERY, PATH
+ }
+}
diff --git a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/modeling/validation/CommonParameterValidator.java b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/modeling/validation/CommonParameterValidator.java
index c03c02a..fefb38c 100644
--- a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/modeling/validation/CommonParameterValidator.java
+++ b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/modeling/validation/CommonParameterValidator.java
@@ -35,7 +35,7 @@ protected CommonParameterValidator(Messager messager, Elements elements, Types t
*
* @param parameter the parameter to fetch info from
* @param value the value used for HTTP name
- * @return empty for invalid setup, non empty for valid config
+ * @return empty for invalid setup, non-empty for valid config
*/
protected Optional extractSpec(VariableElement parameter, String value) {
var type = isInvalidType(parameter.asType());
diff --git a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/modeling/validation/PathValidator.java b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/modeling/validation/PathValidator.java
index cf7f925..cac6cfb 100644
--- a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/modeling/validation/PathValidator.java
+++ b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/modeling/validation/PathValidator.java
@@ -2,11 +2,11 @@
import io.github.zskamljic.restahead.modeling.declaration.ParameterDeclaration;
import io.github.zskamljic.restahead.modeling.declaration.RequestParameterSpec;
-import io.github.zskamljic.restahead.requests.request.BasicRequestLine;
-import io.github.zskamljic.restahead.requests.request.PresetQuery;
-import io.github.zskamljic.restahead.requests.request.RequestLine;
-import io.github.zskamljic.restahead.requests.request.path.RequestPath;
-import io.github.zskamljic.restahead.requests.request.path.StringPath;
+import io.github.zskamljic.restahead.request.BasicRequestLine;
+import io.github.zskamljic.restahead.request.PresetQuery;
+import io.github.zskamljic.restahead.request.RequestLine;
+import io.github.zskamljic.restahead.request.path.RequestPath;
+import io.github.zskamljic.restahead.request.path.StringPath;
import javax.annotation.processing.Messager;
import javax.lang.model.element.ExecutableElement;
diff --git a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/polyglot/Dialect.java b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/polyglot/Dialect.java
new file mode 100644
index 0000000..4980bcd
--- /dev/null
+++ b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/polyglot/Dialect.java
@@ -0,0 +1,93 @@
+package io.github.zskamljic.restahead.polyglot;
+
+import io.github.zskamljic.restahead.modeling.declaration.BodyParameter;
+import io.github.zskamljic.restahead.modeling.parameters.ParameterWithExceptions;
+import io.github.zskamljic.restahead.modeling.parameters.PartData;
+import io.github.zskamljic.restahead.modeling.parameters.RequestParameter;
+import io.github.zskamljic.restahead.request.BasicRequestLine;
+
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
+import java.lang.annotation.Annotation;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * Represents a dialect to use with RestAhead. If META-INF/services/io.github.zskamljic.restahead.polyglot.Dialect is
+ * discovered with a valid subclass of Dialect then the processor will additionally use that dialect to generate the
+ * source for all valid services.
+ */
+public interface Dialect {
+ /**
+ * Return a list of all the annotations supported by this class.
+ *
+ * @return the full list of annotations.
+ */
+ default List> allAnnotations() {
+ var annotations = new ArrayList<>(requestAnnotations());
+ annotations.addAll(bodyAnnotations());
+ annotations.addAll(verbAnnotations());
+ return annotations;
+ }
+
+ /**
+ * Return a list of request annotations, such as Query, Header, Path etc.
+ *
+ * @return the list of request annotations.
+ */
+ List> requestAnnotations();
+
+ /**
+ * Return a list of body annotations, such as Body, FormName, Part etc.
+ *
+ * @return the list of body annotations.
+ */
+ List> bodyAnnotations();
+
+ /**
+ * Return a list of verb annotations, such as Delete, Get, Post etc.
+ *
+ * @return the verb annotations.
+ */
+ List> verbAnnotations();
+
+ /**
+ * Attempt to extract a {@link BasicRequestLine} from the annotation. Can be called with annotations from other
+ * dialects. If no data can be extracted (unknown annotation, invalid data etc.) Optional.empty() can be returned.
+ *
+ * @param annotation the annotation to get the request line from
+ * @return request line if annotation is valid and recognized, empty otherwise
+ */
+ Optional getRequestLine(Annotation annotation);
+
+ /**
+ * Attempts to extract a {@link RequestParameter} from the annotation. Can be called with annotations from other
+ * dialects. If no data can be extracted (unknown annotation, invalid data etc.) Optional.empty() can be returned.
+ *
+ * @param annotation the annotation to get the parameter from
+ * @return the parameter if parsed, empty otherwise
+ */
+ Optional extractRequestAnnotation(Annotation annotation);
+
+ /**
+ * Attempt to extract a {@link PartData} from the annotation. Can be called with annotations from other
+ * dialects. If no data can be extracted (unknown annotation, invalid data etc.) Optional.empty() can be returned.
+ *
+ * @param bodyAnnotations body annotations present on the parameter
+ * @return the extracted PartData if applicable
+ */
+ Optional extractPart(List extends Annotation> bodyAnnotations);
+
+ /**
+ * Create a new body part if this dialect is familiar with the type.
+ *
+ * @param elements the elements utility to obtain references from
+ * @param types the types utility to help with type decision
+ * @param body the body information parsed from the parameter
+ * @param type the type of the parameter
+ * @return full parameter info or empty
+ */
+ Optional createBodyPart(Elements elements, Types types, BodyParameter body, TypeMirror type);
+}
diff --git a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/polyglot/Dialects.java b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/polyglot/Dialects.java
new file mode 100644
index 0000000..a71d55a
--- /dev/null
+++ b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/polyglot/Dialects.java
@@ -0,0 +1,170 @@
+package io.github.zskamljic.restahead.polyglot;
+
+import io.github.zskamljic.restahead.annotations.Adapter;
+import io.github.zskamljic.restahead.modeling.declaration.BodyParameter;
+import io.github.zskamljic.restahead.modeling.parameters.ParameterWithExceptions;
+import io.github.zskamljic.restahead.modeling.parameters.PartData;
+import io.github.zskamljic.restahead.modeling.parameters.RequestParameter;
+import io.github.zskamljic.restahead.processor.RequestsProcessor;
+import io.github.zskamljic.restahead.request.BasicRequestLine;
+
+import javax.annotation.processing.Messager;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
+import javax.tools.Diagnostic;
+import java.lang.annotation.Annotation;
+import java.util.Collection;
+import java.util.List;
+import java.util.Optional;
+import java.util.ServiceLoader;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * Utility class that handles all dialects that are discovered by {@link ServiceLoader}.
+ */
+public class Dialects {
+ private final List availableDialects = ServiceLoader.load(Dialect.class, RequestsProcessor.class.getClassLoader())
+ .stream()
+ .map(ServiceLoader.Provider::get)
+ .toList();
+
+ public Dialects(Messager messager) {
+ messager.printMessage(Diagnostic.Kind.NOTE, "Detected dialects: " + createNameString());
+ }
+
+ /**
+ * Returns all verb annotations from discovered dialects.
+ *
+ * @return a stream of annotation classes
+ */
+ public Stream> verbAnnotations() {
+ return availableDialects.stream()
+ .map(Dialect::verbAnnotations)
+ .flatMap(Collection::stream);
+ }
+
+ /**
+ * Returns all request annotations from discovered dialects.
+ *
+ * @return a stream of annotation classes
+ */
+ public Stream> requestAnnotations() {
+ return availableDialects.stream()
+ .map(Dialect::requestAnnotations)
+ .flatMap(Collection::stream);
+ }
+
+ /**
+ * Returns all body annotations from discovered dialects.
+ *
+ * @return a stream of annotation classes
+ */
+ public Stream> bodyAnnotations() {
+ return availableDialects.stream()
+ .map(Dialect::bodyAnnotations)
+ .flatMap(Collection::stream);
+ }
+
+ /**
+ * Attempts to create a basic request line for given annotation.
+ *
+ * @param annotation the annotation with required data
+ * @return the request line based on data
+ * @throws IllegalArgumentException if no valid {@link BasicRequestLine} could be created
+ */
+ public BasicRequestLine basicRequestLine(Annotation annotation) {
+ return availableDialects.stream()
+ .map(dialect -> dialect.getRequestLine(annotation))
+ .flatMap(Optional::stream)
+ .findFirst()
+ .orElseThrow(() -> new IllegalArgumentException("Annotation was not a valid verb: " + annotation));
+ }
+
+ /**
+ * Checks if the element provided is a verb annotation.
+ *
+ * @param typeElement the element to check
+ * @return true if the element is a verb, false otherwise
+ */
+ public boolean isVerbAnnotation(TypeElement typeElement) {
+ var name = typeElement.getSimpleName().toString();
+ return availableDialects.stream()
+ .map(Dialect::verbAnnotations)
+ .flatMap(Collection::stream)
+ .map(Class::getSimpleName)
+ .anyMatch(name::equals);
+ }
+
+ /**
+ * Get a set of all supported annotations in string form.
+ *
+ * @return the full set of annotations
+ */
+ public Set supportedAnnotationTypes() {
+ return Stream.concat(
+ availableDialects.stream()
+ .map(Dialect::allAnnotations)
+ .flatMap(List::stream),
+ Stream.of(Adapter.class)
+ )
+ .map(Class::getCanonicalName)
+ .collect(Collectors.toSet());
+ }
+
+ /**
+ * Formats all the dialects by name and returns a comma separated list.
+ *
+ * @return the comma separated list of Dialect names
+ */
+ private String createNameString() {
+ return availableDialects.stream()
+ .map(dialect -> dialect.getClass().getSimpleName())
+ .collect(Collectors.joining(", "));
+ }
+
+ /**
+ * Get request annotation from annotation (GET, POST etc.)
+ *
+ * @param annotation the annotation
+ * @return request or empty
+ */
+ public Optional extractRequestAnnotation(Annotation annotation) {
+ return availableDialects.stream()
+ .map(dialect -> dialect.extractRequestAnnotation(annotation))
+ .flatMap(Optional::stream)
+ .findFirst();
+ }
+
+ /**
+ * Extract parts of body from annotation
+ *
+ * @param bodyAnnotations the annotations
+ * @return part info or empty
+ */
+ public Optional extractParts(List extends Annotation> bodyAnnotations) {
+ return availableDialects.stream()
+ .map(dialect -> dialect.extractPart(bodyAnnotations))
+ .flatMap(Optional::stream)
+ .findFirst();
+ }
+
+ /**
+ * Delegate body part creation to all detected dialect, returning first valid one
+ *
+ * @param elements the elements to get type info from
+ * @param types the types utility
+ * @param body the body to process
+ * @param type the type of the body
+ * @return first processed body or empty if no dialects return a valid value
+ */
+ public Optional createBodyPart(Elements elements, Types types, BodyParameter body, TypeMirror type) {
+ return availableDialects.stream()
+ .map(dialect -> dialect.createBodyPart(elements, types, body, type))
+ .flatMap(Optional::stream)
+ .findFirst();
+ }
+}
diff --git a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/polyglot/RestAheadDialect.java b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/polyglot/RestAheadDialect.java
new file mode 100644
index 0000000..c393378
--- /dev/null
+++ b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/polyglot/RestAheadDialect.java
@@ -0,0 +1,116 @@
+package io.github.zskamljic.restahead.polyglot;
+
+import io.github.zskamljic.restahead.annotations.form.FormName;
+import io.github.zskamljic.restahead.annotations.form.FormUrlEncoded;
+import io.github.zskamljic.restahead.annotations.form.Part;
+import io.github.zskamljic.restahead.annotations.request.Body;
+import io.github.zskamljic.restahead.annotations.request.Header;
+import io.github.zskamljic.restahead.annotations.request.Path;
+import io.github.zskamljic.restahead.annotations.request.Query;
+import io.github.zskamljic.restahead.annotations.verbs.Delete;
+import io.github.zskamljic.restahead.annotations.verbs.Get;
+import io.github.zskamljic.restahead.annotations.verbs.Patch;
+import io.github.zskamljic.restahead.annotations.verbs.Post;
+import io.github.zskamljic.restahead.annotations.verbs.Put;
+import io.github.zskamljic.restahead.client.requests.Verb;
+import io.github.zskamljic.restahead.modeling.declaration.BodyParameter;
+import io.github.zskamljic.restahead.modeling.parameters.ParameterWithExceptions;
+import io.github.zskamljic.restahead.modeling.parameters.PartData;
+import io.github.zskamljic.restahead.modeling.parameters.RequestParameter;
+import io.github.zskamljic.restahead.request.BasicRequestLine;
+
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
+import java.lang.annotation.Annotation;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * The default dialect of RestAhead.
+ */
+public class RestAheadDialect implements Dialect {
+ @Override
+ public List> requestAnnotations() {
+ return List.of(
+ Header.class, Path.class, Query.class
+ );
+ }
+
+ @Override
+ public List> bodyAnnotations() {
+ return List.of(
+ Body.class, FormName.class, FormUrlEncoded.class, Part.class
+ );
+ }
+
+ @Override
+ public List> verbAnnotations() {
+ return List.of(
+ Delete.class, Get.class, Patch.class, Post.class, Put.class
+ );
+ }
+
+ @Override
+ public Optional getRequestLine(Annotation annotation) {
+ Verb verb;
+ String path;
+ if (annotation instanceof Delete delete) {
+ verb = Verb.DELETE;
+ path = delete.value();
+ } else if (annotation instanceof Get get) {
+ verb = Verb.GET;
+ path = get.value();
+ } else if (annotation instanceof Patch patch) {
+ verb = Verb.PATCH;
+ path = patch.value();
+ } else if (annotation instanceof Post post) {
+ verb = Verb.POST;
+ path = post.value();
+ } else if (annotation instanceof Put put) {
+ verb = Verb.PUT;
+ path = put.value();
+ } else {
+ return Optional.empty();
+ }
+ return Optional.of(new BasicRequestLine(verb, path));
+ }
+
+ @Override
+ public Optional extractRequestAnnotation(Annotation annotation) {
+ RequestParameter.Type type;
+ String value;
+ if (annotation instanceof Header header) {
+ type = RequestParameter.Type.HEADER;
+ value = header.value();
+ } else if (annotation instanceof Query query) {
+ type = RequestParameter.Type.QUERY;
+ value = query.value();
+ } else if (annotation instanceof Path path) {
+ type = RequestParameter.Type.PATH;
+ value = path.value();
+ } else {
+ return Optional.empty();
+ }
+ return Optional.of(new RequestParameter(type, value));
+ }
+
+ @Override
+ public Optional extractPart(List extends Annotation> bodyAnnotations) {
+ return bodyAnnotations.stream()
+ .filter(Part.class::isInstance)
+ .map(Part.class::cast)
+ .map(part -> new PartData(part.value()))
+ .findFirst();
+ }
+
+ @Override
+ public Optional createBodyPart(
+ Elements elements,
+ Types types,
+ BodyParameter body,
+ TypeMirror type
+ ) {
+ return Optional.empty();
+ }
+}
diff --git a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/processor/RequestsProcessor.java b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/processor/RequestsProcessor.java
index 0c93bc4..aeac998 100644
--- a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/processor/RequestsProcessor.java
+++ b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/processor/RequestsProcessor.java
@@ -1,18 +1,9 @@
package io.github.zskamljic.restahead.processor;
-import io.github.zskamljic.restahead.annotations.Adapter;
-import io.github.zskamljic.restahead.annotations.form.FormName;
-import io.github.zskamljic.restahead.annotations.form.FormUrlEncoded;
-import io.github.zskamljic.restahead.annotations.form.Part;
-import io.github.zskamljic.restahead.annotations.request.Body;
-import io.github.zskamljic.restahead.annotations.request.Header;
-import io.github.zskamljic.restahead.annotations.request.Path;
-import io.github.zskamljic.restahead.annotations.request.Query;
-import io.github.zskamljic.restahead.generation.FormConverterGenerator;
import io.github.zskamljic.restahead.generation.ServiceGenerator;
import io.github.zskamljic.restahead.modeling.AdapterModeler;
import io.github.zskamljic.restahead.modeling.ServiceModeler;
-import io.github.zskamljic.restahead.requests.VerbMapping;
+import io.github.zskamljic.restahead.polyglot.Dialects;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Messager;
@@ -23,24 +14,18 @@
import javax.tools.Diagnostic;
import java.io.PrintWriter;
import java.io.StringWriter;
-import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
-import java.util.stream.Stream;
/**
* Processor entry point for HTTP annotations.
*/
public class RequestsProcessor extends AbstractProcessor {
- private static final List> NON_VERB_ANNOTATIONS = List.of(
- Adapter.class, Body.class, Header.class, Path.class, Query.class, FormName.class, FormUrlEncoded.class, Part.class
- );
-
- private FormConverterGenerator formConverterGenerator;
- private ServiceModeler serviceModeler;
- private ServiceGenerator serviceGenerator;
- private AdapterModeler adapterModeler;
private Messager messager;
+ private Dialects dialects;
+ private AdapterModeler adapterModeler;
+ private ServiceGenerator serviceGenerator;
+ private ServiceModeler serviceModeler;
/**
* Initialize the implementation, extracting required fields from {@link ProcessingEnvironment}.
@@ -54,10 +39,10 @@ public synchronized void init(ProcessingEnvironment processingEnv) {
var filer = processingEnv.getFiler();
var elements = processingEnv.getElementUtils();
var types = processingEnv.getTypeUtils();
- serviceModeler = new ServiceModeler(messager, elements, types);
+ dialects = new Dialects(messager);
adapterModeler = new AdapterModeler(messager, elements, types);
serviceGenerator = new ServiceGenerator(messager, filer);
- formConverterGenerator = new FormConverterGenerator(messager, filer);
+ serviceModeler = new ServiceModeler(messager, elements, types, dialects);
}
/**
@@ -73,7 +58,6 @@ public boolean process(Set extends TypeElement> annotations, RoundEnvironment
var adapters = adapterModeler.findAdapters(roundEnv);
var verbs = filterVerbAnnotations(annotations);
var serviceDeclarations = serviceModeler.collectServices(verbs, roundEnv, adapters);
- formConverterGenerator.generateFormEncoderIfNeeded(serviceDeclarations);
serviceDeclarations.forEach(service -> serviceGenerator.generateService(service));
} catch (IllegalArgumentException e) {
var stringWriter = new StringWriter();
@@ -91,11 +75,8 @@ public boolean process(Set extends TypeElement> annotations, RoundEnvironment
* @return the filtered set
*/
private Set extends TypeElement> filterVerbAnnotations(Set extends TypeElement> annotations) {
- var names = NON_VERB_ANNOTATIONS.stream()
- .map(Class::getSimpleName)
- .toList();
return annotations.stream()
- .filter(type -> !names.contains(type.getSimpleName().toString()))
+ .filter(dialects::isVerbAnnotation)
.collect(Collectors.toSet());
}
@@ -116,11 +97,6 @@ public SourceVersion getSupportedSourceVersion() {
*/
@Override
public Set getSupportedAnnotationTypes() {
- return Stream.concat(
- VerbMapping.ANNOTATION_VERBS.stream(),
- NON_VERB_ANNOTATIONS.stream()
- )
- .map(Class::getCanonicalName)
- .collect(Collectors.toSet());
+ return dialects.supportedAnnotationTypes();
}
}
diff --git a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/requests/request/BasicRequestLine.java b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/request/BasicRequestLine.java
similarity index 85%
rename from rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/requests/request/BasicRequestLine.java
rename to rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/request/BasicRequestLine.java
index 19ad909..44d92f6 100644
--- a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/requests/request/BasicRequestLine.java
+++ b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/request/BasicRequestLine.java
@@ -1,4 +1,4 @@
-package io.github.zskamljic.restahead.requests.request;
+package io.github.zskamljic.restahead.request;
import io.github.zskamljic.restahead.client.requests.Verb;
diff --git a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/requests/request/PresetQuery.java b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/request/PresetQuery.java
similarity index 76%
rename from rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/requests/request/PresetQuery.java
rename to rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/request/PresetQuery.java
index b7e5684..bffe291 100644
--- a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/requests/request/PresetQuery.java
+++ b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/request/PresetQuery.java
@@ -1,4 +1,4 @@
-package io.github.zskamljic.restahead.requests.request;
+package io.github.zskamljic.restahead.request;
/**
* Preset query information.
diff --git a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/requests/request/RequestLine.java b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/request/RequestLine.java
similarity index 64%
rename from rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/requests/request/RequestLine.java
rename to rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/request/RequestLine.java
index 054c5f4..3600a6e 100644
--- a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/requests/request/RequestLine.java
+++ b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/request/RequestLine.java
@@ -1,7 +1,7 @@
-package io.github.zskamljic.restahead.requests.request;
+package io.github.zskamljic.restahead.request;
import io.github.zskamljic.restahead.client.requests.Verb;
-import io.github.zskamljic.restahead.requests.request.path.RequestPath;
+import io.github.zskamljic.restahead.request.path.RequestPath;
/**
* The processed request line.
diff --git a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/requests/request/RequestSpec.java b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/request/RequestSpec.java
similarity index 85%
rename from rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/requests/request/RequestSpec.java
rename to rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/request/RequestSpec.java
index 93a2053..af26034 100644
--- a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/requests/request/RequestSpec.java
+++ b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/request/RequestSpec.java
@@ -1,4 +1,4 @@
-package io.github.zskamljic.restahead.requests.request;
+package io.github.zskamljic.restahead.request;
import io.github.zskamljic.restahead.modeling.declaration.ParameterDeclaration;
diff --git a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/requests/request/path/RequestPath.java b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/request/path/RequestPath.java
similarity index 95%
rename from rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/requests/request/path/RequestPath.java
rename to rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/request/path/RequestPath.java
index 808fe8b..fad5e57 100644
--- a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/requests/request/path/RequestPath.java
+++ b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/request/path/RequestPath.java
@@ -1,4 +1,4 @@
-package io.github.zskamljic.restahead.requests.request.path;
+package io.github.zskamljic.restahead.request.path;
import java.net.URI;
import java.net.URISyntaxException;
diff --git a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/requests/request/path/StringPath.java b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/request/path/StringPath.java
similarity index 89%
rename from rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/requests/request/path/StringPath.java
rename to rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/request/path/StringPath.java
index e2bb7df..76b4488 100644
--- a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/requests/request/path/StringPath.java
+++ b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/request/path/StringPath.java
@@ -1,4 +1,4 @@
-package io.github.zskamljic.restahead.requests.request.path;
+package io.github.zskamljic.restahead.request.path;
import java.net.URI;
import java.net.URISyntaxException;
diff --git a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/requests/request/path/TemplatedPath.java b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/request/path/TemplatedPath.java
similarity index 95%
rename from rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/requests/request/path/TemplatedPath.java
rename to rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/request/path/TemplatedPath.java
index 6d86c0c..f7206c6 100644
--- a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/requests/request/path/TemplatedPath.java
+++ b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/request/path/TemplatedPath.java
@@ -1,4 +1,4 @@
-package io.github.zskamljic.restahead.requests.request.path;
+package io.github.zskamljic.restahead.request.path;
import java.net.URI;
import java.net.URISyntaxException;
diff --git a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/requests/VerbMapping.java b/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/requests/VerbMapping.java
deleted file mode 100644
index b913654..0000000
--- a/rest-ahead-processor/src/main/java/io/github/zskamljic/restahead/requests/VerbMapping.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package io.github.zskamljic.restahead.requests;
-
-import io.github.zskamljic.restahead.annotations.verbs.Delete;
-import io.github.zskamljic.restahead.annotations.verbs.Get;
-import io.github.zskamljic.restahead.annotations.verbs.Patch;
-import io.github.zskamljic.restahead.annotations.verbs.Post;
-import io.github.zskamljic.restahead.annotations.verbs.Put;
-import io.github.zskamljic.restahead.client.requests.Verb;
-import io.github.zskamljic.restahead.requests.request.BasicRequestLine;
-import io.github.zskamljic.restahead.requests.request.RequestSpec;
-
-import java.lang.annotation.Annotation;
-import java.util.List;
-
-/**
- * Utility to provide mappers for annotations, requests and specifications.
- */
-public class VerbMapping {
- public static final List> ANNOTATION_VERBS = List.of(
- Delete.class,
- Get.class,
- Patch.class,
- Post.class,
- Put.class
- );
-
- private VerbMapping() {
- }
-
- /**
- * Extracts {@link RequestSpec} from given annotation. Only HTTP verb annotations are supported.
- *
- * @param annotation the annotation from which to extract the verb and path
- * @return the request specification
- */
- public static BasicRequestLine annotationToVerb(Annotation annotation) {
- Verb verb;
- String path;
- if (annotation instanceof Delete delete) {
- verb = Verb.DELETE;
- path = delete.value();
- } else if (annotation instanceof Get get) {
- verb = Verb.GET;
- path = get.value();
- } else if (annotation instanceof Patch patch) {
- verb = Verb.PATCH;
- path = patch.value();
- } else if (annotation instanceof Post post) {
- verb = Verb.POST;
- path = post.value();
- } else if (annotation instanceof Put put) {
- verb = Verb.PUT;
- path = put.value();
- } else {
- throw new IllegalArgumentException("Annotation was not a valid verb: " + annotation);
- }
- return new BasicRequestLine(verb, path);
- }
-}
diff --git a/rest-ahead-processor/src/main/resources/META-INF/services/io.github.zskamljic.restahead.polyglot.Dialect b/rest-ahead-processor/src/main/resources/META-INF/services/io.github.zskamljic.restahead.polyglot.Dialect
new file mode 100644
index 0000000..3ff23b1
--- /dev/null
+++ b/rest-ahead-processor/src/main/resources/META-INF/services/io.github.zskamljic.restahead.polyglot.Dialect
@@ -0,0 +1 @@
+io.github.zskamljic.restahead.polyglot.RestAheadDialect
\ No newline at end of file
diff --git a/rest-ahead-processor/src/test/java/io/github/zskamljic/restahead/generation/methods/PathValidatorTest.java b/rest-ahead-processor/src/test/java/io/github/zskamljic/restahead/generation/methods/PathValidatorTest.java
index 2eeafa5..9a2568a 100644
--- a/rest-ahead-processor/src/test/java/io/github/zskamljic/restahead/generation/methods/PathValidatorTest.java
+++ b/rest-ahead-processor/src/test/java/io/github/zskamljic/restahead/generation/methods/PathValidatorTest.java
@@ -3,7 +3,7 @@
import io.github.zskamljic.restahead.client.requests.Verb;
import io.github.zskamljic.restahead.modeling.declaration.ParameterDeclaration;
import io.github.zskamljic.restahead.modeling.validation.PathValidator;
-import io.github.zskamljic.restahead.requests.request.BasicRequestLine;
+import io.github.zskamljic.restahead.request.BasicRequestLine;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
diff --git a/rest-ahead-processor/src/test/java/io/github/zskamljic/restahead/requests/request/path/TemplatedPathTest.java b/rest-ahead-processor/src/test/java/io/github/zskamljic/restahead/request/path/TemplatedPathTest.java
similarity index 95%
rename from rest-ahead-processor/src/test/java/io/github/zskamljic/restahead/requests/request/path/TemplatedPathTest.java
rename to rest-ahead-processor/src/test/java/io/github/zskamljic/restahead/request/path/TemplatedPathTest.java
index 958b865..39c79ce 100644
--- a/rest-ahead-processor/src/test/java/io/github/zskamljic/restahead/requests/request/path/TemplatedPathTest.java
+++ b/rest-ahead-processor/src/test/java/io/github/zskamljic/restahead/request/path/TemplatedPathTest.java
@@ -1,4 +1,4 @@
-package io.github.zskamljic.restahead.requests.request.path;
+package io.github.zskamljic.restahead.request.path;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
diff --git a/rest-ahead-spring-dialect/pom.xml b/rest-ahead-spring-dialect/pom.xml
new file mode 100644
index 0000000..d7560c3
--- /dev/null
+++ b/rest-ahead-spring-dialect/pom.xml
@@ -0,0 +1,66 @@
+
+
+
+ RestAhead
+ io.github.zskamljic
+ 0.3.0-SNAPSHOT
+
+ 4.0.0
+
+ rest-ahead-spring-dialect
+
+
+ 17
+ 17
+
+
+
+
+ io.github.zskamljic
+ rest-ahead-processor
+ 0.3.0-SNAPSHOT
+
+
+ org.springframework
+ spring-web
+ ${spring.version}
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ ${compiler.plugin.version}
+
+
+ default-compile
+
+ -proc:none
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ ${surefire.version}
+
+
+
+
+
+
+ testing only
+
+ [9,)
+
+
+ --add-opens jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED
+
+
+
+
\ No newline at end of file
diff --git a/rest-ahead-spring-dialect/src/main/java/io/github/zskamljic/restahead/spring/dialect/SpringDialect.java b/rest-ahead-spring-dialect/src/main/java/io/github/zskamljic/restahead/spring/dialect/SpringDialect.java
new file mode 100644
index 0000000..49977b4
--- /dev/null
+++ b/rest-ahead-spring-dialect/src/main/java/io/github/zskamljic/restahead/spring/dialect/SpringDialect.java
@@ -0,0 +1,158 @@
+package io.github.zskamljic.restahead.spring.dialect;
+
+import io.github.zskamljic.restahead.client.requests.Verb;
+import io.github.zskamljic.restahead.client.requests.parts.FilePart;
+import io.github.zskamljic.restahead.encoding.MultiPartParameter;
+import io.github.zskamljic.restahead.modeling.declaration.BodyParameter;
+import io.github.zskamljic.restahead.modeling.parameters.ParameterWithExceptions;
+import io.github.zskamljic.restahead.modeling.parameters.PartData;
+import io.github.zskamljic.restahead.modeling.parameters.RequestParameter;
+import io.github.zskamljic.restahead.polyglot.Dialect;
+import io.github.zskamljic.restahead.request.BasicRequestLine;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PatchMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestHeader;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RequestPart;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+
+/**
+ * Represents the spring dialect for RestAhead.
+ */
+public class SpringDialect implements Dialect {
+ @Override
+ public List> requestAnnotations() {
+ return List.of(
+ RequestHeader.class, PathVariable.class, RequestParam.class
+ );
+ }
+
+ @Override
+ public List> bodyAnnotations() {
+ return List.of(
+ RequestBody.class, RequestPart.class
+ );
+ }
+
+ @Override
+ public List> verbAnnotations() {
+ return List.of(
+ DeleteMapping.class, GetMapping.class, PatchMapping.class, PostMapping.class, PutMapping.class, RequestMapping.class
+ );
+ }
+
+ @Override
+ public Optional getRequestLine(Annotation annotation) {
+ Verb verb;
+ String path;
+ if (annotation instanceof DeleteMapping deleteMapping) {
+ verb = Verb.DELETE;
+ path = deleteMapping.value()[0];
+ } else if (annotation instanceof GetMapping getMapping) {
+ verb = Verb.GET;
+ path = getMapping.value()[0];
+ } else if (annotation instanceof PatchMapping patchMapping) {
+ verb = Verb.PATCH;
+ path = patchMapping.value()[0];
+ } else if (annotation instanceof PostMapping postMapping) {
+ verb = Verb.POST;
+ path = postMapping.value()[0];
+ } else if (annotation instanceof PutMapping putMapping) {
+ verb = Verb.PUT;
+ path = putMapping.value()[0];
+ } else if (annotation instanceof RequestMapping requestMapping) {
+ var requestVerb = getVerb(requestMapping.method());
+ if (requestVerb.isEmpty()) return Optional.empty();
+
+ verb = requestVerb.get();
+ path = requestMapping.value()[0];
+ } else {
+ return Optional.empty();
+ }
+ return Optional.of(new BasicRequestLine(verb, path));
+ }
+
+ @Override
+ public Optional extractRequestAnnotation(Annotation annotation) {
+ RequestParameter.Type type;
+ String value;
+ if (annotation instanceof RequestHeader header) {
+ type = RequestParameter.Type.HEADER;
+ value = header.value();
+ } else if (annotation instanceof RequestParam query) {
+ type = RequestParameter.Type.QUERY;
+ value = query.value();
+ } else if (annotation instanceof PathVariable path) {
+ type = RequestParameter.Type.PATH;
+ value = path.value();
+ } else {
+ return Optional.empty();
+ }
+ return Optional.of(new RequestParameter(type, value));
+ }
+
+ @Override
+ public Optional extractPart(List extends Annotation> bodyAnnotations) {
+ return bodyAnnotations.stream()
+ .filter(RequestPart.class::isInstance)
+ .map(RequestPart.class::cast)
+ .map(part -> new PartData(part.value()))
+ .findFirst();
+ }
+
+ @Override
+ public Optional createBodyPart(
+ Elements elements,
+ Types types,
+ BodyParameter body,
+ TypeMirror type
+ ) {
+ var multiPartType = elements.getTypeElement(MultipartFile.class.getName()).asType();
+ if (!types.isSameType(type, multiPartType)) return Optional.empty();
+
+ var part = new MultiPartParameter(
+ body.httpName(),
+ body.name() + ".getOriginalFilename()",
+ Optional.of(FilePart.class),
+ Optional.of(body.name() + ".getInputStream()")
+ );
+ var exceptions = elements.getTypeElement(IOException.class.getName()).asType();
+ return Optional.of(new ParameterWithExceptions(part, Set.of(exceptions)));
+ }
+
+ /**
+ * Used to map {@link RequestMethod} to {@link Verb}. If more than one is provided no verb is returned.
+ *
+ * @param methods the methods to check
+ * @return the verb if applicable, empty otherwise
+ */
+ private Optional getVerb(RequestMethod[] methods) {
+ if (methods.length != 1) return Optional.empty();
+
+ var verb = switch (methods[0]) {
+ case DELETE -> Verb.DELETE;
+ case GET -> Verb.GET;
+ case PATCH -> Verb.PATCH;
+ case POST -> Verb.POST;
+ case PUT -> Verb.PUT;
+ default -> null;
+ };
+ return Optional.ofNullable(verb);
+ }
+}
diff --git a/rest-ahead-spring-dialect/src/main/resources/META-INF/services/io.github.zskamljic.restahead.polyglot.Dialect b/rest-ahead-spring-dialect/src/main/resources/META-INF/services/io.github.zskamljic.restahead.polyglot.Dialect
new file mode 100644
index 0000000..cd91d20
--- /dev/null
+++ b/rest-ahead-spring-dialect/src/main/resources/META-INF/services/io.github.zskamljic.restahead.polyglot.Dialect
@@ -0,0 +1 @@
+io.github.zskamljic.restahead.spring.dialect.SpringDialect
\ No newline at end of file
diff --git a/rest-ahead-spring/pom.xml b/rest-ahead-spring/pom.xml
index c00edc7..c5fc250 100644
--- a/rest-ahead-spring/pom.xml
+++ b/rest-ahead-spring/pom.xml
@@ -20,7 +20,7 @@
org.springframework
spring-context
- 5.3.15
+ ${spring.version}
io.github.zskamljic
diff --git a/rest-ahead-spring/src/main/java/io/github/zskamljic/restahead/spring/RestAheadRegistrar.java b/rest-ahead-spring/src/main/java/io/github/zskamljic/restahead/spring/RestAheadRegistrar.java
index 0dbbc62..63c4db6 100644
--- a/rest-ahead-spring/src/main/java/io/github/zskamljic/restahead/spring/RestAheadRegistrar.java
+++ b/rest-ahead-spring/src/main/java/io/github/zskamljic/restahead/spring/RestAheadRegistrar.java
@@ -117,7 +117,7 @@ private T instantiateService(BeanDefinitionRegistry registry, Maprest-ahead-spring
0.3.0-SNAPSHOT
+
+ io.github.zskamljic
+ rest-ahead-spring-dialect
+ 0.3.0-SNAPSHOT
+
+
+
+
+ com.google.truth
+ truth
+ ${truth.version}
+ test
+
+
+ com.google.testing.compile
+ compile-testing
+ ${testing.compile.version}
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ ${junit.version}
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-params
+ ${junit.version}
+ test
+
+
+ org.mockito
+ mockito-core
+ ${mockito.version}
+ test
+
+
+ org.mockito
+ mockito-junit-jupiter
+ ${mockito.version}
+ test
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ ${compiler.plugin.version}
+
org.apache.maven.plugins
maven-surefire-plugin
@@ -67,4 +115,16 @@
+
+
+
+ testing only
+
+ [9,)
+
+
+ --add-opens jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED
+
+
+
\ No newline at end of file
diff --git a/rest-ahead-processor/src/test/java/io/github/zskamljic/restahead/processor/CommonProcessorTest.java b/test-report-aggregator/src/test/java/io/github/zskamljic/restahead/processor/CommonProcessorTest.java
similarity index 100%
rename from rest-ahead-processor/src/test/java/io/github/zskamljic/restahead/processor/CommonProcessorTest.java
rename to test-report-aggregator/src/test/java/io/github/zskamljic/restahead/processor/CommonProcessorTest.java
diff --git a/rest-ahead-processor/src/test/java/io/github/zskamljic/restahead/processor/UnclaimedProcessor.java b/test-report-aggregator/src/test/java/io/github/zskamljic/restahead/processor/UnclaimedProcessor.java
similarity index 100%
rename from rest-ahead-processor/src/test/java/io/github/zskamljic/restahead/processor/UnclaimedProcessor.java
rename to test-report-aggregator/src/test/java/io/github/zskamljic/restahead/processor/UnclaimedProcessor.java
diff --git a/test-report-aggregator/src/test/java/io/github/zskamljic/restahead/processor/spring/SpringDialectTest.java b/test-report-aggregator/src/test/java/io/github/zskamljic/restahead/processor/spring/SpringDialectTest.java
new file mode 100644
index 0000000..ba89d8a
--- /dev/null
+++ b/test-report-aggregator/src/test/java/io/github/zskamljic/restahead/processor/spring/SpringDialectTest.java
@@ -0,0 +1,15 @@
+package io.github.zskamljic.restahead.processor.spring;
+
+import com.google.testing.compile.JavaFileObjects;
+import io.github.zskamljic.restahead.processor.CommonProcessorTest;
+import org.junit.jupiter.api.Test;
+
+class SpringDialectTest extends CommonProcessorTest {
+ @Test
+ void processorGeneratesForSpring() {
+ commonCompilationAssertion("spring/SpringService.java")
+ .compilesWithoutWarnings()
+ .and()
+ .generatesSources(JavaFileObjects.forResource("spring/SpringService$Impl.java"));
+ }
+}
diff --git a/rest-ahead-processor/src/test/java/io/github/zskamljic/restahead/processor/AdapterProcessorTest.java b/test-report-aggregator/src/test/java/io/github/zskamljic/restahead/processor/stock/AdapterProcessorTest.java
similarity index 77%
rename from rest-ahead-processor/src/test/java/io/github/zskamljic/restahead/processor/AdapterProcessorTest.java
rename to test-report-aggregator/src/test/java/io/github/zskamljic/restahead/processor/stock/AdapterProcessorTest.java
index 715fd10..281e364 100644
--- a/rest-ahead-processor/src/test/java/io/github/zskamljic/restahead/processor/AdapterProcessorTest.java
+++ b/test-report-aggregator/src/test/java/io/github/zskamljic/restahead/processor/stock/AdapterProcessorTest.java
@@ -1,6 +1,7 @@
-package io.github.zskamljic.restahead.processor;
+package io.github.zskamljic.restahead.processor.stock;
import com.google.testing.compile.JavaFileObjects;
+import io.github.zskamljic.restahead.processor.CommonProcessorTest;
import org.junit.jupiter.api.Test;
class AdapterProcessorTest extends CommonProcessorTest {
diff --git a/rest-ahead-processor/src/test/java/io/github/zskamljic/restahead/processor/BodyProcessorTest.java b/test-report-aggregator/src/test/java/io/github/zskamljic/restahead/processor/stock/BodyProcessorTest.java
similarity index 85%
rename from rest-ahead-processor/src/test/java/io/github/zskamljic/restahead/processor/BodyProcessorTest.java
rename to test-report-aggregator/src/test/java/io/github/zskamljic/restahead/processor/stock/BodyProcessorTest.java
index 5552652..9e3e6e9 100644
--- a/rest-ahead-processor/src/test/java/io/github/zskamljic/restahead/processor/BodyProcessorTest.java
+++ b/test-report-aggregator/src/test/java/io/github/zskamljic/restahead/processor/stock/BodyProcessorTest.java
@@ -1,6 +1,7 @@
-package io.github.zskamljic.restahead.processor;
+package io.github.zskamljic.restahead.processor.stock;
import com.google.testing.compile.JavaFileObjects;
+import io.github.zskamljic.restahead.processor.CommonProcessorTest;
import org.junit.jupiter.api.Test;
class BodyProcessorTest extends CommonProcessorTest {
@@ -39,10 +40,7 @@ void validRecordCompiles() {
commonCompilationAssertion("parameters/FormOnRecord.java")
.compilesWithoutWarnings()
.and()
- .generatesSources(
- JavaFileObjects.forResource("parameters/FormOnRecord$Impl.java"),
- JavaFileObjects.forResource("parameters/record/FormConverter.java")
- );
+ .generatesSources(JavaFileObjects.forResource("parameters/FormOnRecord$Impl.java"));
}
@Test
@@ -57,10 +55,7 @@ void validClassCompiles() {
commonCompilationAssertion("parameters/FormOnClass.java")
.compilesWithoutWarnings()
.and()
- .generatesSources(
- JavaFileObjects.forResource("parameters/FormOnClass$Impl.java"),
- JavaFileObjects.forResource("parameters/class/FormConverter.java")
- );
+ .generatesSources(JavaFileObjects.forResource("parameters/FormOnClass$Impl.java"));
}
@Test
diff --git a/rest-ahead-processor/src/test/java/io/github/zskamljic/restahead/processor/HeaderProcessorTest.java b/test-report-aggregator/src/test/java/io/github/zskamljic/restahead/processor/stock/HeaderProcessorTest.java
similarity index 94%
rename from rest-ahead-processor/src/test/java/io/github/zskamljic/restahead/processor/HeaderProcessorTest.java
rename to test-report-aggregator/src/test/java/io/github/zskamljic/restahead/processor/stock/HeaderProcessorTest.java
index 01ab220..8e29662 100644
--- a/rest-ahead-processor/src/test/java/io/github/zskamljic/restahead/processor/HeaderProcessorTest.java
+++ b/test-report-aggregator/src/test/java/io/github/zskamljic/restahead/processor/stock/HeaderProcessorTest.java
@@ -1,5 +1,6 @@
-package io.github.zskamljic.restahead.processor;
+package io.github.zskamljic.restahead.processor.stock;
+import io.github.zskamljic.restahead.processor.CommonProcessorTest;
import org.junit.jupiter.api.Test;
class HeaderProcessorTest extends CommonProcessorTest {
diff --git a/rest-ahead-processor/src/test/java/io/github/zskamljic/restahead/processor/ParametersProcessorTest.java b/test-report-aggregator/src/test/java/io/github/zskamljic/restahead/processor/stock/ParametersProcessorTest.java
similarity index 72%
rename from rest-ahead-processor/src/test/java/io/github/zskamljic/restahead/processor/ParametersProcessorTest.java
rename to test-report-aggregator/src/test/java/io/github/zskamljic/restahead/processor/stock/ParametersProcessorTest.java
index e29240b..97addd7 100644
--- a/rest-ahead-processor/src/test/java/io/github/zskamljic/restahead/processor/ParametersProcessorTest.java
+++ b/test-report-aggregator/src/test/java/io/github/zskamljic/restahead/processor/stock/ParametersProcessorTest.java
@@ -1,5 +1,6 @@
-package io.github.zskamljic.restahead.processor;
+package io.github.zskamljic.restahead.processor.stock;
+import io.github.zskamljic.restahead.processor.CommonProcessorTest;
import org.junit.jupiter.api.Test;
class ParametersProcessorTest extends CommonProcessorTest {
diff --git a/rest-ahead-processor/src/test/java/io/github/zskamljic/restahead/processor/PathProcessorTest.java b/test-report-aggregator/src/test/java/io/github/zskamljic/restahead/processor/stock/PathProcessorTest.java
similarity index 92%
rename from rest-ahead-processor/src/test/java/io/github/zskamljic/restahead/processor/PathProcessorTest.java
rename to test-report-aggregator/src/test/java/io/github/zskamljic/restahead/processor/stock/PathProcessorTest.java
index 840e3c0..858d3b9 100644
--- a/rest-ahead-processor/src/test/java/io/github/zskamljic/restahead/processor/PathProcessorTest.java
+++ b/test-report-aggregator/src/test/java/io/github/zskamljic/restahead/processor/stock/PathProcessorTest.java
@@ -1,6 +1,7 @@
-package io.github.zskamljic.restahead.processor;
+package io.github.zskamljic.restahead.processor.stock;
import com.google.testing.compile.JavaFileObjects;
+import io.github.zskamljic.restahead.processor.CommonProcessorTest;
import org.junit.jupiter.api.Test;
class PathProcessorTest extends CommonProcessorTest {
diff --git a/rest-ahead-processor/src/test/java/io/github/zskamljic/restahead/processor/QueryProcessorTest.java b/test-report-aggregator/src/test/java/io/github/zskamljic/restahead/processor/stock/QueryProcessorTest.java
similarity index 90%
rename from rest-ahead-processor/src/test/java/io/github/zskamljic/restahead/processor/QueryProcessorTest.java
rename to test-report-aggregator/src/test/java/io/github/zskamljic/restahead/processor/stock/QueryProcessorTest.java
index 403ec33..288567d 100644
--- a/rest-ahead-processor/src/test/java/io/github/zskamljic/restahead/processor/QueryProcessorTest.java
+++ b/test-report-aggregator/src/test/java/io/github/zskamljic/restahead/processor/stock/QueryProcessorTest.java
@@ -1,5 +1,6 @@
-package io.github.zskamljic.restahead.processor;
+package io.github.zskamljic.restahead.processor.stock;
+import io.github.zskamljic.restahead.processor.CommonProcessorTest;
import org.junit.jupiter.api.Test;
class QueryProcessorTest extends CommonProcessorTest {
diff --git a/rest-ahead-processor/src/test/java/io/github/zskamljic/restahead/processor/RequestsProcessorTest.java b/test-report-aggregator/src/test/java/io/github/zskamljic/restahead/processor/stock/RequestsProcessorTest.java
similarity index 79%
rename from rest-ahead-processor/src/test/java/io/github/zskamljic/restahead/processor/RequestsProcessorTest.java
rename to test-report-aggregator/src/test/java/io/github/zskamljic/restahead/processor/stock/RequestsProcessorTest.java
index 6e04517..882eeb9 100644
--- a/rest-ahead-processor/src/test/java/io/github/zskamljic/restahead/processor/RequestsProcessorTest.java
+++ b/test-report-aggregator/src/test/java/io/github/zskamljic/restahead/processor/stock/RequestsProcessorTest.java
@@ -1,6 +1,7 @@
-package io.github.zskamljic.restahead.processor;
+package io.github.zskamljic.restahead.processor.stock;
import com.google.testing.compile.JavaFileObjects;
+import io.github.zskamljic.restahead.processor.CommonProcessorTest;
import org.junit.jupiter.api.Test;
class RequestsProcessorTest extends CommonProcessorTest {
@@ -11,24 +12,22 @@ void generateServiceSucceeds() {
}
@Test
- void generateServiceFailsForAbstractClass() {
+ void generateServiceIgnoresAbstractClass() {
commonCompilationAssertion("basic/MethodClass.java")
- .failsToCompile()
- .withErrorContaining("interfaces");
+ .compilesWithoutWarnings();
}
@Test
void interfaceWithDefaultFailsToCompile() {
commonCompilationAssertion("basic/MethodService.java")
.failsToCompile()
- .withErrorContaining("abstract");
+ .withErrorContaining("Default methods in interfaces");
}
@Test
- void classWithMethodFailsToCompile() {
+ void classWithMethodIgnoresClass() {
commonCompilationAssertion("basic/NormalClassMethod.java")
- .failsToCompile()
- .withErrorContaining("abstract");
+ .compilesWithoutWarnings();
}
@Test
diff --git a/rest-ahead-processor/src/test/java/io/github/zskamljic/restahead/processor/ResponseProcessorTest.java b/test-report-aggregator/src/test/java/io/github/zskamljic/restahead/processor/stock/ResponseProcessorTest.java
similarity index 93%
rename from rest-ahead-processor/src/test/java/io/github/zskamljic/restahead/processor/ResponseProcessorTest.java
rename to test-report-aggregator/src/test/java/io/github/zskamljic/restahead/processor/stock/ResponseProcessorTest.java
index 3f41875..2dccb2e 100644
--- a/rest-ahead-processor/src/test/java/io/github/zskamljic/restahead/processor/ResponseProcessorTest.java
+++ b/test-report-aggregator/src/test/java/io/github/zskamljic/restahead/processor/stock/ResponseProcessorTest.java
@@ -1,6 +1,7 @@
-package io.github.zskamljic.restahead.processor;
+package io.github.zskamljic.restahead.processor.stock;
import com.google.testing.compile.JavaFileObjects;
+import io.github.zskamljic.restahead.processor.CommonProcessorTest;
import org.junit.jupiter.api.Test;
class ResponseProcessorTest extends CommonProcessorTest {
diff --git a/rest-ahead-processor/src/test/resources/ValidService.java b/test-report-aggregator/src/test/resources/ValidService.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/ValidService.java
rename to test-report-aggregator/src/test/resources/ValidService.java
diff --git a/rest-ahead-processor/src/test/resources/adapters/AdapterService$Impl.java b/test-report-aggregator/src/test/resources/adapters/AdapterService$Impl.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/adapters/AdapterService$Impl.java
rename to test-report-aggregator/src/test/resources/adapters/AdapterService$Impl.java
diff --git a/rest-ahead-processor/src/test/resources/adapters/AdapterService.java b/test-report-aggregator/src/test/resources/adapters/AdapterService.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/adapters/AdapterService.java
rename to test-report-aggregator/src/test/resources/adapters/AdapterService.java
diff --git a/rest-ahead-processor/src/test/resources/basic/InterfaceWithNotAnnotatedMethod.java b/test-report-aggregator/src/test/resources/basic/InterfaceWithNotAnnotatedMethod.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/basic/InterfaceWithNotAnnotatedMethod.java
rename to test-report-aggregator/src/test/resources/basic/InterfaceWithNotAnnotatedMethod.java
diff --git a/rest-ahead-processor/src/test/resources/basic/InterfaceWithThrows$Impl.java b/test-report-aggregator/src/test/resources/basic/InterfaceWithThrows$Impl.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/basic/InterfaceWithThrows$Impl.java
rename to test-report-aggregator/src/test/resources/basic/InterfaceWithThrows$Impl.java
diff --git a/rest-ahead-processor/src/test/resources/basic/InterfaceWithThrows.java b/test-report-aggregator/src/test/resources/basic/InterfaceWithThrows.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/basic/InterfaceWithThrows.java
rename to test-report-aggregator/src/test/resources/basic/InterfaceWithThrows.java
diff --git a/rest-ahead-processor/src/test/resources/basic/MethodClass.java b/test-report-aggregator/src/test/resources/basic/MethodClass.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/basic/MethodClass.java
rename to test-report-aggregator/src/test/resources/basic/MethodClass.java
diff --git a/rest-ahead-processor/src/test/resources/basic/MethodService.java b/test-report-aggregator/src/test/resources/basic/MethodService.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/basic/MethodService.java
rename to test-report-aggregator/src/test/resources/basic/MethodService.java
diff --git a/rest-ahead-processor/src/test/resources/basic/MultipleAnnotations.java b/test-report-aggregator/src/test/resources/basic/MultipleAnnotations.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/basic/MultipleAnnotations.java
rename to test-report-aggregator/src/test/resources/basic/MultipleAnnotations.java
diff --git a/rest-ahead-processor/src/test/resources/basic/NormalClassMethod.java b/test-report-aggregator/src/test/resources/basic/NormalClassMethod.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/basic/NormalClassMethod.java
rename to test-report-aggregator/src/test/resources/basic/NormalClassMethod.java
diff --git a/rest-ahead-processor/src/test/resources/headers/BoxedHeader.java b/test-report-aggregator/src/test/resources/headers/BoxedHeader.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/headers/BoxedHeader.java
rename to test-report-aggregator/src/test/resources/headers/BoxedHeader.java
diff --git a/rest-ahead-processor/src/test/resources/headers/EmptyHeader.java b/test-report-aggregator/src/test/resources/headers/EmptyHeader.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/headers/EmptyHeader.java
rename to test-report-aggregator/src/test/resources/headers/EmptyHeader.java
diff --git a/rest-ahead-processor/src/test/resources/headers/InvalidArrayHeader.java b/test-report-aggregator/src/test/resources/headers/InvalidArrayHeader.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/headers/InvalidArrayHeader.java
rename to test-report-aggregator/src/test/resources/headers/InvalidArrayHeader.java
diff --git a/rest-ahead-processor/src/test/resources/headers/InvalidCollectionHeader.java b/test-report-aggregator/src/test/resources/headers/InvalidCollectionHeader.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/headers/InvalidCollectionHeader.java
rename to test-report-aggregator/src/test/resources/headers/InvalidCollectionHeader.java
diff --git a/rest-ahead-processor/src/test/resources/headers/InvalidHeader.java b/test-report-aggregator/src/test/resources/headers/InvalidHeader.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/headers/InvalidHeader.java
rename to test-report-aggregator/src/test/resources/headers/InvalidHeader.java
diff --git a/rest-ahead-processor/src/test/resources/headers/PrimitiveHeader.java b/test-report-aggregator/src/test/resources/headers/PrimitiveHeader.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/headers/PrimitiveHeader.java
rename to test-report-aggregator/src/test/resources/headers/PrimitiveHeader.java
diff --git a/rest-ahead-processor/src/test/resources/headers/StringHeader.java b/test-report-aggregator/src/test/resources/headers/StringHeader.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/headers/StringHeader.java
rename to test-report-aggregator/src/test/resources/headers/StringHeader.java
diff --git a/rest-ahead-processor/src/test/resources/headers/UuidHeader.java b/test-report-aggregator/src/test/resources/headers/UuidHeader.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/headers/UuidHeader.java
rename to test-report-aggregator/src/test/resources/headers/UuidHeader.java
diff --git a/rest-ahead-processor/src/test/resources/headers/ValidArrayHeader.java b/test-report-aggregator/src/test/resources/headers/ValidArrayHeader.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/headers/ValidArrayHeader.java
rename to test-report-aggregator/src/test/resources/headers/ValidArrayHeader.java
diff --git a/rest-ahead-processor/src/test/resources/headers/ValidCollectionHeader.java b/test-report-aggregator/src/test/resources/headers/ValidCollectionHeader.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/headers/ValidCollectionHeader.java
rename to test-report-aggregator/src/test/resources/headers/ValidCollectionHeader.java
diff --git a/rest-ahead-processor/src/test/resources/parameters/BodyService$Impl.java b/test-report-aggregator/src/test/resources/parameters/BodyService$Impl.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/parameters/BodyService$Impl.java
rename to test-report-aggregator/src/test/resources/parameters/BodyService$Impl.java
diff --git a/rest-ahead-processor/src/test/resources/parameters/BodyService.java b/test-report-aggregator/src/test/resources/parameters/BodyService.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/parameters/BodyService.java
rename to test-report-aggregator/src/test/resources/parameters/BodyService.java
diff --git a/rest-ahead-processor/src/test/resources/parameters/FormAndPartSameField.java b/test-report-aggregator/src/test/resources/parameters/FormAndPartSameField.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/parameters/FormAndPartSameField.java
rename to test-report-aggregator/src/test/resources/parameters/FormAndPartSameField.java
diff --git a/rest-ahead-processor/src/test/resources/parameters/FormOnClass$Impl.java b/test-report-aggregator/src/test/resources/parameters/FormOnClass$Impl.java
similarity index 74%
rename from rest-ahead-processor/src/test/resources/parameters/FormOnClass$Impl.java
rename to test-report-aggregator/src/test/resources/parameters/FormOnClass$Impl.java
index 5195035..9ef5afd 100644
--- a/rest-ahead-processor/src/test/resources/parameters/FormOnClass$Impl.java
+++ b/test-report-aggregator/src/test/resources/parameters/FormOnClass$Impl.java
@@ -5,10 +5,13 @@
import io.github.zskamljic.restahead.client.requests.Request;
import io.github.zskamljic.restahead.client.requests.Verb;
import io.github.zskamljic.restahead.exceptions.RestException;
-import io.github.zskamljic.restahead.generation.FormConverter;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
import java.lang.InterruptedException;
import java.lang.Override;
import java.lang.String;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
import java.util.concurrent.ExecutionException;
import javax.annotation.processing.Generated;
@@ -33,7 +36,7 @@ public final void post(FormOnClass.Sample body) {
.setBaseUrl(baseUrl)
.setPath("");
httpRequestBuilder.addHeader("Content-Type", "application/x-www-form-urlencoded");
- httpRequestBuilder.setBody(FormConverter.formEncode(body));
+ httpRequestBuilder.setBody(formEncode(body));
var response = client.execute(httpRequestBuilder.build());
try {
defaultAdapters.syncVoidAdapter(response);
@@ -41,4 +44,10 @@ public final void post(FormOnClass.Sample body) {
throw RestException.getAppropriateException(exception);
}
}
+
+ public static InputStream formEncode(FormOnClass.Sample value) {
+ var stringValue = "first=" + URLEncoder.encode(String.valueOf(value.getFirst()), StandardCharsets.UTF_8) +
+ "&smth=" + URLEncoder.encode(String.valueOf(value.getSecond()), StandardCharsets.UTF_8);
+ return new ByteArrayInputStream(stringValue.getBytes());
+ }
}
\ No newline at end of file
diff --git a/rest-ahead-processor/src/test/resources/parameters/FormOnClass.java b/test-report-aggregator/src/test/resources/parameters/FormOnClass.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/parameters/FormOnClass.java
rename to test-report-aggregator/src/test/resources/parameters/FormOnClass.java
diff --git a/rest-ahead-processor/src/test/resources/parameters/FormOnClassInvalid.java b/test-report-aggregator/src/test/resources/parameters/FormOnClassInvalid.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/parameters/FormOnClassInvalid.java
rename to test-report-aggregator/src/test/resources/parameters/FormOnClassInvalid.java
diff --git a/rest-ahead-processor/src/test/resources/parameters/FormOnInvalid.java b/test-report-aggregator/src/test/resources/parameters/FormOnInvalid.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/parameters/FormOnInvalid.java
rename to test-report-aggregator/src/test/resources/parameters/FormOnInvalid.java
diff --git a/rest-ahead-processor/src/test/resources/parameters/FormOnInvalidMap.java b/test-report-aggregator/src/test/resources/parameters/FormOnInvalidMap.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/parameters/FormOnInvalidMap.java
rename to test-report-aggregator/src/test/resources/parameters/FormOnInvalidMap.java
diff --git a/rest-ahead-processor/src/test/resources/parameters/FormOnRecord$Impl.java b/test-report-aggregator/src/test/resources/parameters/FormOnRecord$Impl.java
similarity index 56%
rename from rest-ahead-processor/src/test/resources/parameters/FormOnRecord$Impl.java
rename to test-report-aggregator/src/test/resources/parameters/FormOnRecord$Impl.java
index 17f5f00..046eafd 100644
--- a/rest-ahead-processor/src/test/resources/parameters/FormOnRecord$Impl.java
+++ b/test-report-aggregator/src/test/resources/parameters/FormOnRecord$Impl.java
@@ -5,10 +5,13 @@
import io.github.zskamljic.restahead.client.requests.Request;
import io.github.zskamljic.restahead.client.requests.Verb;
import io.github.zskamljic.restahead.exceptions.RestException;
-import io.github.zskamljic.restahead.generation.FormConverter;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
import java.lang.InterruptedException;
import java.lang.Override;
import java.lang.String;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
import java.util.concurrent.ExecutionException;
import javax.annotation.processing.Generated;
@@ -33,7 +36,7 @@ public final void post(FormOnRecord.Sample body) {
.setBaseUrl(baseUrl)
.setPath("");
httpRequestBuilder.addHeader("Content-Type", "application/x-www-form-urlencoded");
- httpRequestBuilder.setBody(FormConverter.formEncode(body));
+ httpRequestBuilder.setBody(formEncode(body));
var response = client.execute(httpRequestBuilder.build());
try {
defaultAdapters.syncVoidAdapter(response);
@@ -41,4 +44,26 @@ public final void post(FormOnRecord.Sample body) {
throw RestException.getAppropriateException(exception);
}
}
-}
+
+ @Override
+ public final void post2(FormOnRecord.Sample body) {
+ var httpRequestBuilder = new Request.Builder()
+ .setVerb(Verb.POST)
+ .setBaseUrl(baseUrl)
+ .setPath("");
+ httpRequestBuilder.addHeader("Content-Type", "application/x-www-form-urlencoded");
+ httpRequestBuilder.setBody(formEncode(body));
+ var response = client.execute(httpRequestBuilder.build());
+ try {
+ defaultAdapters.syncVoidAdapter(response);
+ } catch (ExecutionException | InterruptedException exception) {
+ throw RestException.getAppropriateException(exception);
+ }
+ }
+
+ public static InputStream formEncode(FormOnRecord.Sample value) {
+ var stringValue = "first=" + URLEncoder.encode(String.valueOf(value.first()), StandardCharsets.UTF_8) +
+ "&2nd=" + URLEncoder.encode(String.valueOf(value.second()), StandardCharsets.UTF_8);
+ return new ByteArrayInputStream(stringValue.getBytes());
+ }
+}
\ No newline at end of file
diff --git a/rest-ahead-processor/src/test/resources/parameters/FormOnRecord.java b/test-report-aggregator/src/test/resources/parameters/FormOnRecord.java
similarity index 89%
rename from rest-ahead-processor/src/test/resources/parameters/FormOnRecord.java
rename to test-report-aggregator/src/test/resources/parameters/FormOnRecord.java
index 63b75f7..8b1c74e 100644
--- a/rest-ahead-processor/src/test/resources/parameters/FormOnRecord.java
+++ b/test-report-aggregator/src/test/resources/parameters/FormOnRecord.java
@@ -9,6 +9,9 @@ public interface FormOnRecord {
@Post
void post(@FormUrlEncoded @Body Sample body);
+ @Post
+ void post2(@FormUrlEncoded Sample body);
+
record Sample(String first, @FormName("2nd") String second) {
}
}
\ No newline at end of file
diff --git a/rest-ahead-processor/src/test/resources/parameters/FormOnRecordInvalid.java b/test-report-aggregator/src/test/resources/parameters/FormOnRecordInvalid.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/parameters/FormOnRecordInvalid.java
rename to test-report-aggregator/src/test/resources/parameters/FormOnRecordInvalid.java
diff --git a/rest-ahead-processor/src/test/resources/parameters/FormOnValidMap$Impl.java b/test-report-aggregator/src/test/resources/parameters/FormOnValidMap$Impl.java
similarity index 90%
rename from rest-ahead-processor/src/test/resources/parameters/FormOnValidMap$Impl.java
rename to test-report-aggregator/src/test/resources/parameters/FormOnValidMap$Impl.java
index f1495ec..3368cfb 100644
--- a/rest-ahead-processor/src/test/resources/parameters/FormOnValidMap$Impl.java
+++ b/test-report-aggregator/src/test/resources/parameters/FormOnValidMap$Impl.java
@@ -4,8 +4,8 @@
import io.github.zskamljic.restahead.client.Client;
import io.github.zskamljic.restahead.client.requests.Request;
import io.github.zskamljic.restahead.client.requests.Verb;
+import io.github.zskamljic.restahead.conversion.MapFormConverter;
import io.github.zskamljic.restahead.exceptions.RestException;
-import io.github.zskamljic.restahead.generation.FormConverter;
import java.lang.Double;
import java.lang.Integer;
import java.lang.InterruptedException;
@@ -38,7 +38,7 @@ public final void post(Map body) {
.setBaseUrl(baseUrl)
.setPath("");
httpRequestBuilder.addHeader("Content-Type", "application/x-www-form-urlencoded");
- httpRequestBuilder.setBody(FormConverter.formEncode(body));
+ httpRequestBuilder.setBody(MapFormConverter.formEncode(body));
var response = client.execute(httpRequestBuilder.build());
try {
defaultAdapters.syncVoidAdapter(response);
@@ -54,7 +54,7 @@ public final void post2(Map body) {
.setBaseUrl(baseUrl)
.setPath("");
httpRequestBuilder.addHeader("Content-Type", "application/x-www-form-urlencoded");
- httpRequestBuilder.setBody(FormConverter.formEncode(body));
+ httpRequestBuilder.setBody(MapFormConverter.formEncode(body));
var response = client.execute(httpRequestBuilder.build());
try {
defaultAdapters.syncVoidAdapter(response);
@@ -70,7 +70,7 @@ public final void post3(Map body) {
.setBaseUrl(baseUrl)
.setPath("");
httpRequestBuilder.addHeader("Content-Type", "application/x-www-form-urlencoded");
- httpRequestBuilder.setBody(FormConverter.formEncode(body));
+ httpRequestBuilder.setBody(MapFormConverter.formEncode(body));
var response = client.execute(httpRequestBuilder.build());
try {
defaultAdapters.syncVoidAdapter(response);
@@ -86,7 +86,7 @@ public final void post4(HashMap body) {
.setBaseUrl(baseUrl)
.setPath("");
httpRequestBuilder.addHeader("Content-Type", "application/x-www-form-urlencoded");
- httpRequestBuilder.setBody(FormConverter.formEncode(body));
+ httpRequestBuilder.setBody(MapFormConverter.formEncode(body));
var response = client.execute(httpRequestBuilder.build());
try {
defaultAdapters.syncVoidAdapter(response);
@@ -94,4 +94,4 @@ public final void post4(HashMap body) {
throw RestException.getAppropriateException(exception);
}
}
-}
+}
\ No newline at end of file
diff --git a/rest-ahead-processor/src/test/resources/parameters/FormOnValidMap.java b/test-report-aggregator/src/test/resources/parameters/FormOnValidMap.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/parameters/FormOnValidMap.java
rename to test-report-aggregator/src/test/resources/parameters/FormOnValidMap.java
diff --git a/rest-ahead-processor/src/test/resources/parameters/FormOnWithWrongField.java b/test-report-aggregator/src/test/resources/parameters/FormOnWithWrongField.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/parameters/FormOnWithWrongField.java
rename to test-report-aggregator/src/test/resources/parameters/FormOnWithWrongField.java
diff --git a/rest-ahead-processor/src/test/resources/parameters/FormWithPart$Impl.java b/test-report-aggregator/src/test/resources/parameters/FormWithPart$Impl.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/parameters/FormWithPart$Impl.java
rename to test-report-aggregator/src/test/resources/parameters/FormWithPart$Impl.java
diff --git a/rest-ahead-processor/src/test/resources/parameters/FormWithPart.java b/test-report-aggregator/src/test/resources/parameters/FormWithPart.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/parameters/FormWithPart.java
rename to test-report-aggregator/src/test/resources/parameters/FormWithPart.java
diff --git a/rest-ahead-processor/src/test/resources/parameters/FormWithPartInvalidType.java b/test-report-aggregator/src/test/resources/parameters/FormWithPartInvalidType.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/parameters/FormWithPartInvalidType.java
rename to test-report-aggregator/src/test/resources/parameters/FormWithPartInvalidType.java
diff --git a/rest-ahead-processor/src/test/resources/parameters/Parameters.java b/test-report-aggregator/src/test/resources/parameters/Parameters.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/parameters/Parameters.java
rename to test-report-aggregator/src/test/resources/parameters/Parameters.java
diff --git a/rest-ahead-processor/src/test/resources/parameters/class/FormConverter.java b/test-report-aggregator/src/test/resources/parameters/class/FormConverter.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/parameters/class/FormConverter.java
rename to test-report-aggregator/src/test/resources/parameters/class/FormConverter.java
diff --git a/rest-ahead-processor/src/test/resources/parameters/record/FormConverter.java b/test-report-aggregator/src/test/resources/parameters/record/FormConverter.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/parameters/record/FormConverter.java
rename to test-report-aggregator/src/test/resources/parameters/record/FormConverter.java
diff --git a/rest-ahead-processor/src/test/resources/path/InvalidPath.java b/test-report-aggregator/src/test/resources/path/InvalidPath.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/path/InvalidPath.java
rename to test-report-aggregator/src/test/resources/path/InvalidPath.java
diff --git a/rest-ahead-processor/src/test/resources/path/PathAnnotation$Impl.java b/test-report-aggregator/src/test/resources/path/PathAnnotation$Impl.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/path/PathAnnotation$Impl.java
rename to test-report-aggregator/src/test/resources/path/PathAnnotation$Impl.java
diff --git a/rest-ahead-processor/src/test/resources/path/PathAnnotation.java b/test-report-aggregator/src/test/resources/path/PathAnnotation.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/path/PathAnnotation.java
rename to test-report-aggregator/src/test/resources/path/PathAnnotation.java
diff --git a/rest-ahead-processor/src/test/resources/path/PathAnnotationCodeName$Impl.java b/test-report-aggregator/src/test/resources/path/PathAnnotationCodeName$Impl.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/path/PathAnnotationCodeName$Impl.java
rename to test-report-aggregator/src/test/resources/path/PathAnnotationCodeName$Impl.java
diff --git a/rest-ahead-processor/src/test/resources/path/PathAnnotationCodeName.java b/test-report-aggregator/src/test/resources/path/PathAnnotationCodeName.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/path/PathAnnotationCodeName.java
rename to test-report-aggregator/src/test/resources/path/PathAnnotationCodeName.java
diff --git a/rest-ahead-processor/src/test/resources/path/PathWithDuplicates.java b/test-report-aggregator/src/test/resources/path/PathWithDuplicates.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/path/PathWithDuplicates.java
rename to test-report-aggregator/src/test/resources/path/PathWithDuplicates.java
diff --git a/rest-ahead-processor/src/test/resources/path/PathWithIterable.java b/test-report-aggregator/src/test/resources/path/PathWithIterable.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/path/PathWithIterable.java
rename to test-report-aggregator/src/test/resources/path/PathWithIterable.java
diff --git a/rest-ahead-processor/src/test/resources/path/PathWithoutPlaceholder.java b/test-report-aggregator/src/test/resources/path/PathWithoutPlaceholder.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/path/PathWithoutPlaceholder.java
rename to test-report-aggregator/src/test/resources/path/PathWithoutPlaceholder.java
diff --git a/rest-ahead-processor/src/test/resources/query/CollectionAndArray.java b/test-report-aggregator/src/test/resources/query/CollectionAndArray.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/query/CollectionAndArray.java
rename to test-report-aggregator/src/test/resources/query/CollectionAndArray.java
diff --git a/rest-ahead-processor/src/test/resources/query/MissingName.java b/test-report-aggregator/src/test/resources/query/MissingName.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/query/MissingName.java
rename to test-report-aggregator/src/test/resources/query/MissingName.java
diff --git a/rest-ahead-processor/src/test/resources/query/MissingQueryValue.java b/test-report-aggregator/src/test/resources/query/MissingQueryValue.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/query/MissingQueryValue.java
rename to test-report-aggregator/src/test/resources/query/MissingQueryValue.java
diff --git a/rest-ahead-processor/src/test/resources/query/QueryInPath.java b/test-report-aggregator/src/test/resources/query/QueryInPath.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/query/QueryInPath.java
rename to test-report-aggregator/src/test/resources/query/QueryInPath.java
diff --git a/rest-ahead-processor/src/test/resources/query/ValidCombinedQuery.java b/test-report-aggregator/src/test/resources/query/ValidCombinedQuery.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/query/ValidCombinedQuery.java
rename to test-report-aggregator/src/test/resources/query/ValidCombinedQuery.java
diff --git a/rest-ahead-processor/src/test/resources/query/ValidQuery.java b/test-report-aggregator/src/test/resources/query/ValidQuery.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/query/ValidQuery.java
rename to test-report-aggregator/src/test/resources/query/ValidQuery.java
diff --git a/rest-ahead-processor/src/test/resources/response/FutureGenericResponse$Impl.java b/test-report-aggregator/src/test/resources/response/FutureGenericResponse$Impl.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/response/FutureGenericResponse$Impl.java
rename to test-report-aggregator/src/test/resources/response/FutureGenericResponse$Impl.java
diff --git a/rest-ahead-processor/src/test/resources/response/FutureGenericResponse.java b/test-report-aggregator/src/test/resources/response/FutureGenericResponse.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/response/FutureGenericResponse.java
rename to test-report-aggregator/src/test/resources/response/FutureGenericResponse.java
diff --git a/rest-ahead-processor/src/test/resources/response/ResponseWithBody$Impl.java b/test-report-aggregator/src/test/resources/response/ResponseWithBody$Impl.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/response/ResponseWithBody$Impl.java
rename to test-report-aggregator/src/test/resources/response/ResponseWithBody$Impl.java
diff --git a/rest-ahead-processor/src/test/resources/response/ResponseWithBody.java b/test-report-aggregator/src/test/resources/response/ResponseWithBody.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/response/ResponseWithBody.java
rename to test-report-aggregator/src/test/resources/response/ResponseWithBody.java
diff --git a/rest-ahead-processor/src/test/resources/response/ResponseWithErrorBody$Impl.java b/test-report-aggregator/src/test/resources/response/ResponseWithErrorBody$Impl.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/response/ResponseWithErrorBody$Impl.java
rename to test-report-aggregator/src/test/resources/response/ResponseWithErrorBody$Impl.java
diff --git a/rest-ahead-processor/src/test/resources/response/ResponseWithErrorBody.java b/test-report-aggregator/src/test/resources/response/ResponseWithErrorBody.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/response/ResponseWithErrorBody.java
rename to test-report-aggregator/src/test/resources/response/ResponseWithErrorBody.java
diff --git a/rest-ahead-processor/src/test/resources/response/ServiceWithGenericResponse$Impl.java b/test-report-aggregator/src/test/resources/response/ServiceWithGenericResponse$Impl.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/response/ServiceWithGenericResponse$Impl.java
rename to test-report-aggregator/src/test/resources/response/ServiceWithGenericResponse$Impl.java
diff --git a/rest-ahead-processor/src/test/resources/response/ServiceWithGenericResponse.java b/test-report-aggregator/src/test/resources/response/ServiceWithGenericResponse.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/response/ServiceWithGenericResponse.java
rename to test-report-aggregator/src/test/resources/response/ServiceWithGenericResponse.java
diff --git a/rest-ahead-processor/src/test/resources/response/ServiceWithResponse.java b/test-report-aggregator/src/test/resources/response/ServiceWithResponse.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/response/ServiceWithResponse.java
rename to test-report-aggregator/src/test/resources/response/ServiceWithResponse.java
diff --git a/rest-ahead-processor/src/test/resources/response/ServiceWithUnknownResponse$Impl.java b/test-report-aggregator/src/test/resources/response/ServiceWithUnknownResponse$Impl.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/response/ServiceWithUnknownResponse$Impl.java
rename to test-report-aggregator/src/test/resources/response/ServiceWithUnknownResponse$Impl.java
diff --git a/rest-ahead-processor/src/test/resources/response/ServiceWithUnknownResponse.java b/test-report-aggregator/src/test/resources/response/ServiceWithUnknownResponse.java
similarity index 100%
rename from rest-ahead-processor/src/test/resources/response/ServiceWithUnknownResponse.java
rename to test-report-aggregator/src/test/resources/response/ServiceWithUnknownResponse.java
diff --git a/test-report-aggregator/src/test/resources/spring/SpringService$Impl.java b/test-report-aggregator/src/test/resources/spring/SpringService$Impl.java
new file mode 100644
index 0000000..595e44f
--- /dev/null
+++ b/test-report-aggregator/src/test/resources/spring/SpringService$Impl.java
@@ -0,0 +1,139 @@
+package restahead.spring;
+
+import io.github.zskamljic.restahead.adapter.DefaultAdapters;
+import io.github.zskamljic.restahead.client.Client;
+import io.github.zskamljic.restahead.client.requests.MultiPartRequest;
+import io.github.zskamljic.restahead.client.requests.Request;
+import io.github.zskamljic.restahead.client.requests.Verb;
+import io.github.zskamljic.restahead.client.requests.parts.FieldPart;
+import io.github.zskamljic.restahead.client.requests.parts.FilePart;
+import io.github.zskamljic.restahead.client.responses.Response;
+import io.github.zskamljic.restahead.conversion.Converter;
+import io.github.zskamljic.restahead.exceptions.RestException;
+import java.io.IOException;
+import java.lang.InterruptedException;
+import java.lang.Override;
+import java.lang.String;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+import javax.annotation.processing.Generated;
+import org.springframework.web.multipart.MultipartFile;
+
+@Generated("Generated by RestAhead")
+public final class SpringService$Impl implements SpringService {
+ private final String baseUrl;
+
+ private final Client client;
+
+ private final Converter converter;
+
+ private final DefaultAdapters defaultAdapters;
+
+ public SpringService$Impl(String baseUrl, Client client, Converter converter,
+ DefaultAdapters defaultAdapters) {
+ this.baseUrl = baseUrl;
+ this.client = client;
+ this.converter = converter;
+ this.defaultAdapters = defaultAdapters;
+ }
+
+ @Override
+ public final Response performDelete(String header1, String header2) {
+ var httpRequestBuilder = new Request.Builder()
+ .setVerb(Verb.DELETE)
+ .setBaseUrl(baseUrl)
+ .setPath("/delete");
+ httpRequestBuilder.addHeader("custom", String.valueOf(header1));
+ httpRequestBuilder.addHeader("header2", String.valueOf(header2));
+ var response = client.execute(httpRequestBuilder.build());
+ try {
+ return defaultAdapters.syncAdapter(response);
+ } catch (ExecutionException | InterruptedException exception) {
+ throw RestException.getAppropriateException(exception);
+ }
+ }
+
+ @Override
+ public final Response performGet(String get, String second) {
+ var httpRequestBuilder = new Request.Builder()
+ .setVerb(Verb.GET)
+ .setBaseUrl(baseUrl)
+ .setPath("/{get}/{hello}".replace("{get}", String.valueOf(get))
+ .replace("{hello}", String.valueOf(second)));
+ var response = client.execute(httpRequestBuilder.build());
+ try {
+ return defaultAdapters.syncAdapter(response);
+ } catch (ExecutionException | InterruptedException exception) {
+ throw RestException.getAppropriateException(exception);
+ }
+ }
+
+ @Override
+ public final Response performPatch(Map body) {
+ var httpRequestBuilder = new Request.Builder()
+ .setVerb(Verb.PATCH)
+ .setBaseUrl(baseUrl)
+ .setPath("/patch");
+ try {
+ httpRequestBuilder.setBody(converter.serialize(body));
+ } catch (IOException exception) {
+ throw RestException.getAppropriateException(exception);
+ }
+ var response = client.execute(httpRequestBuilder.build());
+ try {
+ return defaultAdapters.syncAdapter(response);
+ } catch (ExecutionException | InterruptedException exception) {
+ throw RestException.getAppropriateException(exception);
+ }
+ }
+
+ @Override
+ public final Response performPost(String part, MultipartFile file) {
+ var httpRequestBuilder = new Request.Builder()
+ .setVerb(Verb.POST)
+ .setBaseUrl(baseUrl)
+ .setPath("/post");
+ try {
+ MultiPartRequest.builder()
+ .addPart(new FieldPart("part", part))
+ .addPart(new FilePart("file", file.getOriginalFilename(), file.getInputStream()))
+ .buildInto(httpRequestBuilder);
+ } catch (IOException exception) {
+ throw RestException.getAppropriateException(exception);
+ }
+ var response = client.execute(httpRequestBuilder.build());
+ try {
+ return defaultAdapters.syncAdapter(response);
+ } catch (ExecutionException | InterruptedException exception) {
+ throw RestException.getAppropriateException(exception);
+ }
+ }
+
+ @Override
+ public final Response performPut() {
+ var httpRequestBuilder = new Request.Builder()
+ .setVerb(Verb.PUT)
+ .setBaseUrl(baseUrl)
+ .setPath("/put");
+ var response = client.execute(httpRequestBuilder.build());
+ try {
+ return defaultAdapters.syncAdapter(response);
+ } catch (ExecutionException | InterruptedException exception) {
+ throw RestException.getAppropriateException(exception);
+ }
+ }
+
+ @Override
+ public final Response customGet() {
+ var httpRequestBuilder = new Request.Builder()
+ .setVerb(Verb.GET)
+ .setBaseUrl(baseUrl)
+ .setPath("/get");
+ var response = client.execute(httpRequestBuilder.build());
+ try {
+ return defaultAdapters.syncAdapter(response);
+ } catch (ExecutionException | InterruptedException exception) {
+ throw RestException.getAppropriateException(exception);
+ }
+ }
+}
\ No newline at end of file
diff --git a/test-report-aggregator/src/test/resources/spring/SpringService.java b/test-report-aggregator/src/test/resources/spring/SpringService.java
new file mode 100644
index 0000000..b775836
--- /dev/null
+++ b/test-report-aggregator/src/test/resources/spring/SpringService.java
@@ -0,0 +1,48 @@
+package restahead.spring;
+
+import io.github.zskamljic.restahead.client.responses.Response;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PatchMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestHeader;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestPart;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.Map;
+
+interface SpringService {
+ @DeleteMapping("/delete")
+ Response performDelete(
+ @RequestHeader("custom") String header1,
+ @RequestHeader("header2") String header2
+ );
+
+ @GetMapping("/{get}/{hello}")
+ Response performGet(
+ @PathVariable String get,
+ @PathVariable("hello") String second
+ );
+
+ @PatchMapping("/patch")
+ Response performPatch(
+ @RequestBody Map body
+ );
+
+ @PostMapping("/post")
+ Response performPost(
+ @RequestPart String part,
+ @RequestPart MultipartFile file
+ );
+
+ @PutMapping("/put")
+ Response performPut();
+
+ @RequestMapping(method = RequestMethod.GET, value = "/get")
+ Response customGet();
+}
\ No newline at end of file