diff --git a/core/src/main/java/io/sinistral/proteus/modules/ApplicationModule.java b/core/src/main/java/io/sinistral/proteus/modules/ApplicationModule.java
index 6889df0..b6a13ef 100644
--- a/core/src/main/java/io/sinistral/proteus/modules/ApplicationModule.java
+++ b/core/src/main/java/io/sinistral/proteus/modules/ApplicationModule.java
@@ -81,6 +81,9 @@ public void bindMappers()
}
+ this.requestStaticInjection(Extractors.class);
+ this.requestStaticInjection(ServerResponse.class);
+
}
@SuppressWarnings("unchecked")
diff --git a/core/src/main/java/io/sinistral/proteus/modules/JacksonModule.java b/core/src/main/java/io/sinistral/proteus/modules/JacksonModule.java
index fa5a7f0..b66e00e 100644
--- a/core/src/main/java/io/sinistral/proteus/modules/JacksonModule.java
+++ b/core/src/main/java/io/sinistral/proteus/modules/JacksonModule.java
@@ -5,8 +5,6 @@
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import com.fasterxml.jackson.module.afterburner.AfterburnerModule;
import com.google.inject.AbstractModule;
-import io.sinistral.proteus.server.Extractors;
-import io.sinistral.proteus.server.ServerResponse;
public class JacksonModule extends AbstractModule
{
@@ -25,8 +23,5 @@ protected void configure()
objectMapper.registerModule(new Jdk8Module());
this.bind(ObjectMapper.class).toInstance(objectMapper);
-
- this.requestStaticInjection(Extractors.class);
- this.requestStaticInjection(ServerResponse.class);
}
}
diff --git a/core/src/test/java/io/sinistral/proteus/swagger/test/controllers/Tests.java b/core/src/test/java/io/sinistral/proteus/test/controllers/Tests.java
similarity index 98%
rename from core/src/test/java/io/sinistral/proteus/swagger/test/controllers/Tests.java
rename to core/src/test/java/io/sinistral/proteus/test/controllers/Tests.java
index 3a2f3ed..aa852b6 100644
--- a/core/src/test/java/io/sinistral/proteus/swagger/test/controllers/Tests.java
+++ b/core/src/test/java/io/sinistral/proteus/test/controllers/Tests.java
@@ -1,7 +1,7 @@
/**
*
*/
-package io.sinistral.proteus.swagger.test.controllers;
+package io.sinistral.proteus.test.controllers;
import static io.sinistral.proteus.server.ServerResponse.response;
@@ -37,10 +37,9 @@
import com.google.inject.Singleton;
import io.sinistral.proteus.annotations.Blocking;
-import io.sinistral.proteus.annotations.Debug;
import io.sinistral.proteus.server.ServerRequest;
import io.sinistral.proteus.server.ServerResponse;
-import io.sinistral.proteus.swagger.test.models.User;
+import io.sinistral.proteus.test.models.User;
import io.undertow.server.HttpServerExchange;
diff --git a/core/src/test/java/io/sinistral/proteus/swagger/test/models/User.java b/core/src/test/java/io/sinistral/proteus/test/models/User.java
similarity index 94%
rename from core/src/test/java/io/sinistral/proteus/swagger/test/models/User.java
rename to core/src/test/java/io/sinistral/proteus/test/models/User.java
index 32d81c2..04e405e 100644
--- a/core/src/test/java/io/sinistral/proteus/swagger/test/models/User.java
+++ b/core/src/test/java/io/sinistral/proteus/test/models/User.java
@@ -1,7 +1,7 @@
/**
*
*/
-package io.sinistral.proteus.swagger.test.models;
+package io.sinistral.proteus.test.models;
/**
diff --git a/core/src/test/java/io/sinistral/proteus/swagger/test/server/DefaultServer.java b/core/src/test/java/io/sinistral/proteus/test/server/DefaultServer.java
similarity index 95%
rename from core/src/test/java/io/sinistral/proteus/swagger/test/server/DefaultServer.java
rename to core/src/test/java/io/sinistral/proteus/test/server/DefaultServer.java
index a65fab2..4f651d7 100644
--- a/core/src/test/java/io/sinistral/proteus/swagger/test/server/DefaultServer.java
+++ b/core/src/test/java/io/sinistral/proteus/test/server/DefaultServer.java
@@ -1,11 +1,11 @@
/**
*
*/
-package io.sinistral.proteus.swagger.test.server;
+package io.sinistral.proteus.test.server;
import java.util.List;
-import io.sinistral.proteus.swagger.test.controllers.Tests;
+import io.sinistral.proteus.test.controllers.Tests;
import org.junit.runner.Description;
import org.junit.runner.Result;
import org.junit.runner.notification.RunListener;
diff --git a/core/src/test/java/io/sinistral/proteus/swagger/test/server/TestControllerEndpoints.java b/core/src/test/java/io/sinistral/proteus/test/server/TestControllerEndpoints.java
similarity index 98%
rename from core/src/test/java/io/sinistral/proteus/swagger/test/server/TestControllerEndpoints.java
rename to core/src/test/java/io/sinistral/proteus/test/server/TestControllerEndpoints.java
index ae48ec1..64aaf53 100644
--- a/core/src/test/java/io/sinistral/proteus/swagger/test/server/TestControllerEndpoints.java
+++ b/core/src/test/java/io/sinistral/proteus/test/server/TestControllerEndpoints.java
@@ -1,7 +1,7 @@
/**
*
*/
-package io.sinistral.proteus.swagger.test.server;
+package io.sinistral.proteus.test.server;
import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.containsString;
@@ -36,8 +36,8 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import io.restassured.http.ContentType;
-import io.sinistral.proteus.swagger.test.models.User;
-import io.sinistral.proteus.swagger.test.models.User.UserType;
+import io.sinistral.proteus.test.models.User;
+import io.sinistral.proteus.test.models.User.UserType;
/*
* import static io.restassured.RestAssured.*; import static io.restassured.matcher.RestAssuredMatchers.*; import static org.hamcrest.Matchers.*;
diff --git a/openapi/pom.xml b/openapi/pom.xml
index 7badaa1..1758cea 100644
--- a/openapi/pom.xml
+++ b/openapi/pom.xml
@@ -29,7 +29,7 @@
src/test/resources
- src/test/java
+ src/test/java/sinistral/proteus/openapi
**/*.java
@@ -109,6 +109,13 @@
swagger-integration
${openapi.version}
+
+
+ org.zalando
+ jackson-datatype-money
+ 1.1.1
+
+
${project.groupId}
proteus-core
diff --git a/openapi/src/main/java/io/sinistral/proteus/openapi/jaxrs2/Reader.java b/openapi/src/main/java/io/sinistral/proteus/openapi/jaxrs2/Reader.java
index 69522a4..b3e3d7d 100644
--- a/openapi/src/main/java/io/sinistral/proteus/openapi/jaxrs2/Reader.java
+++ b/openapi/src/main/java/io/sinistral/proteus/openapi/jaxrs2/Reader.java
@@ -13,6 +13,7 @@
import com.fasterxml.jackson.databind.introspect.AnnotatedMethod;
import com.fasterxml.jackson.databind.introspect.AnnotatedParameter;
import com.fasterxml.jackson.databind.type.TypeFactory;
+import io.sinistral.proteus.openapi.models.MoneyModelConverter;
import io.sinistral.proteus.server.ServerRequest;
import io.sinistral.proteus.server.ServerResponse;
import io.swagger.v3.core.converter.AnnotatedType;
@@ -1373,11 +1374,19 @@ else if (classType.getRawClass().isAssignableFrom(CompletableFuture.class))
}
}
- ResolvedSchema resolvedSchema = ModelConverters.getInstance()
+ ModelConverters converters = ModelConverters.getInstance();
+
+ converters.addConverter(new ServerModelResolver());
+ converters.addConverter(new MoneyModelConverter());
+
+
+ ResolvedSchema resolvedSchema = converters
.resolveAsResolvedSchema(new AnnotatedType(returnType).resolveAsRef(true).jsonViewAnnotation(jsonViewAnnotation));
if (resolvedSchema.schema != null)
{
+ System.out.println("resolvedSchema: " + resolvedSchema.schema);
+
Schema returnTypeSchema = resolvedSchema.schema;
Content content = new Content();
MediaType mediaType = new MediaType().schema(returnTypeSchema);
diff --git a/openapi/src/main/java/io/sinistral/proteus/openapi/jaxrs2/ServerModelResolver.java b/openapi/src/main/java/io/sinistral/proteus/openapi/jaxrs2/ServerModelResolver.java
index 0944968..0d364f5 100644
--- a/openapi/src/main/java/io/sinistral/proteus/openapi/jaxrs2/ServerModelResolver.java
+++ b/openapi/src/main/java/io/sinistral/proteus/openapi/jaxrs2/ServerModelResolver.java
@@ -8,12 +8,15 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.introspect.Annotated;
import com.fasterxml.jackson.databind.type.TypeFactory;
+import io.sinistral.proteus.openapi.models.MoneyModelConverter;
import io.sinistral.proteus.server.ServerResponse;
import io.swagger.v3.core.converter.AnnotatedType;
import io.swagger.v3.core.converter.ModelConverter;
import io.swagger.v3.core.converter.ModelConverterContext;
import io.swagger.v3.core.util.Json;
import io.swagger.v3.oas.models.media.Schema;
+import org.javamoney.moneta.Money;
+import org.zalando.jackson.datatype.money.MoneyModule;
import java.io.File;
import java.lang.annotation.Annotation;
@@ -30,9 +33,19 @@ public class ServerModelResolver extends io.swagger.v3.core.jackson.ModelResolve
{
private static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ServerModelResolver.class.getCanonicalName());
+ static final ObjectMapper mapper = Json.mapper();
+
+ static
+ {
+ mapper.registerModule(new MoneyModule());
+ }
+
public ServerModelResolver()
{
- super(Json.mapper());
+ super(mapper);
+
+
+ System.out.println("not from super");
}
/**
@@ -40,7 +53,8 @@ public ServerModelResolver()
*/
public ServerModelResolver(ObjectMapper mapper)
{
- super(mapper);
+ super(ServerModelResolver.mapper);
+
}
/*
@@ -83,6 +97,11 @@ else if (rawClass.isAssignableFrom(CompletableFuture.class))
if (resolvedType != null)
{
+// if (resolvedType.getTypeName().contains("org.javamoney.moneta.Money"))
+// {
+// resolvedType = TypeFactory.defaultInstance().constructFromCanonical(Money.class.getName());
+// }
+
if (resolvedType.getTypeName().contains("java.lang.Void"))
{
resolvedType = TypeFactory.defaultInstance().constructFromCanonical(Void.class.getName());
@@ -120,8 +139,24 @@ else if (resolvedType.getTypeName().contains("Optional"))
try {
+
// log.info("Processing " + annotatedType + " " + classType + " " + annotatedType.getName());
- return super.resolve(annotatedType, context, next);
+
+ if(annotatedType.getType().getTypeName().contains("org.javamoney.moneta.Money"))
+ {
+ MoneyModelConverter.MoneySchema schema = new MoneyModelConverter.MoneySchema();
+
+ context.defineModel("money",schema);
+
+ return schema;
+ }
+ else {
+
+ Schema schema = super.resolve(annotatedType, context, next);
+
+ return schema;
+ }
+
} catch (Exception e) {
diff --git a/openapi/src/main/java/io/sinistral/proteus/openapi/jaxrs2/ServerParameterExtension.java b/openapi/src/main/java/io/sinistral/proteus/openapi/jaxrs2/ServerParameterExtension.java
index 5d6c85b..56e9efb 100644
--- a/openapi/src/main/java/io/sinistral/proteus/openapi/jaxrs2/ServerParameterExtension.java
+++ b/openapi/src/main/java/io/sinistral/proteus/openapi/jaxrs2/ServerParameterExtension.java
@@ -4,6 +4,8 @@
*/
package io.sinistral.proteus.openapi.jaxrs2;
+import org.zalando.jackson.datatype.money.MoneyModule;
+
import com.fasterxml.jackson.annotation.JsonView;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.JavaType;
@@ -38,7 +40,13 @@ public class ServerParameterExtension extends AbstractOpenAPIExtension
private static String COOKIE_PARAM = "cookie";
private static String PATH_PARAM = "path";
private static String FORM_PARAM = "form";
- final ObjectMapper mapper = Json.mapper();
+
+ final static ObjectMapper mapper = Json.mapper();
+
+ static
+ {
+ mapper.registerModule(new MoneyModule());
+ }
@Override
public ResolvedParameter extractParameters(List annotations, Type type, Set typesToSkip, Components components, javax.ws.rs.Consumes classConsumes,
diff --git a/openapi/src/main/java/io/sinistral/proteus/openapi/models/MoneyModelConverter.java b/openapi/src/main/java/io/sinistral/proteus/openapi/models/MoneyModelConverter.java
new file mode 100644
index 0000000..f37539e
--- /dev/null
+++ b/openapi/src/main/java/io/sinistral/proteus/openapi/models/MoneyModelConverter.java
@@ -0,0 +1,157 @@
+package io.sinistral.proteus.openapi.models;
+
+
+import com.fasterxml.jackson.databind.JavaType;
+import com.google.common.collect.ImmutableMap;
+import io.swagger.v3.core.converter.AnnotatedType;
+import io.swagger.v3.core.converter.ModelConverter;
+import io.swagger.v3.core.converter.ModelConverterContext;
+import io.swagger.v3.core.util.Json;
+import io.swagger.v3.oas.models.media.NumberSchema;
+import io.swagger.v3.oas.models.media.Schema;
+import io.swagger.v3.oas.models.media.StringSchema;
+import org.javamoney.moneta.Money;
+
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+public class MoneyModelConverter implements ModelConverter
+{
+
+ @Override
+ public Schema resolve(AnnotatedType type, ModelConverterContext context, Iterator chain) {
+
+ JavaType _type = Json.mapper().constructType(type.getType());
+
+ if(_type != null && (_type.getRawClass().equals(Money.class)))
+ {
+ return new MoneySchema();
+ }
+
+ if (type.getType() instanceof Class>) {
+
+ System.out.println("MoneyModelConverter resolving class: " + ((Class) type.getType()).getName());
+
+ Class> cls = (Class>) type.getType();
+
+ if(cls.isAssignableFrom(Money.class))
+ {
+ return new MoneySchema();
+ }
+ }
+ else if(type.getType().getTypeName().equals("[simple type, class org.javamoney.moneta.Money]"))
+ {
+ System.out.println("is org.javamoney.moneta.Money");
+ return new MoneySchema();
+ }
+ else if (type.isSchemaProperty()) {
+ _type = Json.mapper().constructType(type.getType());
+
+ if (_type != null) {
+ Class> cls = _type.getRawClass();
+ if (Money.class.isAssignableFrom(cls)) {
+ return new MoneySchema();
+ }
+ }
+ }
+
+ if (chain.hasNext()) {
+ System.out.println("skipped resolving " + _type);
+
+ return chain.next().resolve(type, context, chain);
+ }
+
+ return null;
+
+ }
+
+
+ public static class MoneySchema extends Schema
+ {
+ private String _type = "object";
+
+ private String _$ref = null;// "#/components/schemas/Money";
+
+ private String _description = "A monetary amount";
+
+ private Map _properties = ImmutableMap.of("number",new NumberSchema(),"currency",new StringSchema());
+
+ private List _required = Arrays.asList("number","currency");
+
+ public MoneySchema()
+ {
+ super();
+ super.setName("Money");
+ super.setType("object");
+ super.set$ref(_$ref);
+ super.description(_description);
+ super.properties(_properties);
+ }
+
+ @Override
+ protected Money cast(Object value)
+ {
+ if (value != null) {
+ try {
+ if (value instanceof Money) {
+ return (Money) value;
+ }
+ } catch (Exception e) {
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public boolean equals(java.lang.Object o)
+ {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ MoneySchema MoneySchema = (MoneySchema) o;
+ return Objects.equals(this._type, MoneySchema._type) &&
+ Objects.equals(this._properties, MoneySchema._properties) &&
+ super.equals(o);
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return Objects.hash(_type, _properties, super.hashCode());
+ }
+
+// @Override
+// public String toString()
+// {
+// StringBuilder sb = new StringBuilder();
+// sb.append("class MoneySchema {\n");
+// sb.append(" ").append(toIndentedString(super.toString())).append("\n");
+// sb.append(" title: ").append(toIndentedString(getTitle())).append("\n");
+// sb.append(" type: ").append(toIndentedString(_type)).append("\n");
+// sb.append(toIndentedString(_properties.toString())).append("\n");
+// sb.append(" }").append("\n");
+//
+// sb.append("}");
+// return sb.toString();
+// }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces
+ * (except the first line).
+ */
+ private String toIndentedString(java.lang.Object o)
+ {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+
+ }
+}
diff --git a/openapi/src/main/java/io/sinistral/proteus/openapi/services/OpenAPIService.java b/openapi/src/main/java/io/sinistral/proteus/openapi/services/OpenAPIService.java
index 09a2ca0..0d5aeeb 100644
--- a/openapi/src/main/java/io/sinistral/proteus/openapi/services/OpenAPIService.java
+++ b/openapi/src/main/java/io/sinistral/proteus/openapi/services/OpenAPIService.java
@@ -12,7 +12,9 @@
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
+import java.util.Arrays;
import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -27,6 +29,7 @@
import io.sinistral.proteus.openapi.jaxrs2.Reader;
import io.sinistral.proteus.openapi.jaxrs2.ServerModelResolver;
import io.sinistral.proteus.openapi.jaxrs2.ServerParameterExtension;
+import io.sinistral.proteus.openapi.models.MoneyModelConverter;
import io.sinistral.proteus.services.DefaultService;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
@@ -265,7 +268,7 @@ protected void generateSpec() throws Exception
SwaggerConfiguration config = new SwaggerConfiguration().resourceClasses(classes.stream().map(Class::getName).collect(Collectors.toSet())).openAPI(openApi);
- config.setModelConverterClassess(Collections.singleton(ServerModelResolver.class.getName()));
+ config.setModelConverterClassess(new HashSet<>(Arrays.asList(ServerModelResolver.class.getName())));
OpenApiContext ctx = new GenericOpenApiContext().openApiConfiguration(config)
.openApiReader(new Reader(config))
diff --git a/openapi/src/test/java/io/sinistral/proteus/openapi/test/controllers/OpenAPITests.java b/openapi/src/test/java/io/sinistral/proteus/openapi/test/controllers/OpenAPITests.java
new file mode 100644
index 0000000..9ddefb8
--- /dev/null
+++ b/openapi/src/test/java/io/sinistral/proteus/openapi/test/controllers/OpenAPITests.java
@@ -0,0 +1,316 @@
+/**
+ *
+ */
+package io.sinistral.proteus.openapi.test.controllers;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.io.Files;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import io.sinistral.proteus.annotations.Blocking;
+import io.sinistral.proteus.openapi.test.models.Pojo;
+import io.sinistral.proteus.server.ServerRequest;
+import io.sinistral.proteus.server.ServerResponse;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.security.SecurityRequirement;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.tags.Tags;
+import io.undertow.server.HttpServerExchange;
+import org.javamoney.moneta.Money;
+
+import javax.ws.rs.BeanParam;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import java.io.File;
+import java.nio.ByteBuffer;
+import java.sql.Timestamp;
+import java.time.Instant;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+
+import static io.sinistral.proteus.server.ServerResponse.response;
+
+/**
+ * @author jbauer
+ *
+ */
+
+@Tags({@Tag(name = "tests")})
+@Path("/tests")
+@Produces((MediaType.APPLICATION_JSON))
+@Consumes((MediaType.MEDIA_TYPE_WILDCARD))
+@Singleton
+public class OpenAPITests
+{
+ private static final ByteBuffer buffer;
+ static {
+ String message = "Hello, World!";
+ byte[] messageBytes = message.getBytes(java.nio.charset.StandardCharsets.US_ASCII);
+ buffer = ByteBuffer.allocateDirect(messageBytes.length);
+ buffer.put(messageBytes);
+ buffer.flip();
+ }
+
+ @Inject
+ protected ObjectMapper objectMapper;
+
+
+ @GET
+ @Path("exchange/plaintext")
+ @Produces((MediaType.TEXT_PLAIN))
+ @Operation(description = "Plaintext endpoint" )
+ public void exchangePlaintext(HttpServerExchange exchange)
+ {
+ response("Hello, World!").textPlain().send(exchange);
+
+ }
+
+
+ @GET
+ @Path("response/plaintext")
+ @Produces((MediaType.TEXT_PLAIN))
+ @Operation(description = "Plaintext endpoint" )
+ public ServerResponse responsePlaintext(ServerRequest request)
+ {
+ return response("Hello, World!").textPlain();
+
+ }
+
+ @GET
+ @Path("response/future/map")
+ @Operation(description = "Future map endpoint" )
+ public CompletableFuture>> responseFutureMap( ServerRequest request )
+ {
+ Map map = ImmutableMap.of("message", "success");
+ return CompletableFuture.completedFuture(response( map ).applicationJson());
+ }
+
+ @GET
+ @Path("response/map")
+ @Operation(description = "Map endpoint" )
+ public ServerResponse