diff --git a/.gitignore b/.gitignore
index 3d1bf1e..9eb4605 100644
--- a/.gitignore
+++ b/.gitignore
@@ -23,3 +23,4 @@ bin
.settings/org.scala-ide.sdt.core.prefs
.cache-tests
/proteus/
+/pom.xml.versionsBackup
diff --git a/conf/logback.xml b/conf/logback.xml
index 74ae6c0..1a61aa3 100644
--- a/conf/logback.xml
+++ b/conf/logback.xml
@@ -20,9 +20,9 @@
-
-
-
+
+
+
io.sinistral.proteus.services
diff --git a/pom.xml b/pom.xml
index 65f6b43..2f124de 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
4.0.0
io.sinistral
proteus-core
- 0.2.3-SNAPSHOT
+ 0.3.1-SNAPSHOT
proteus core
Proteus is an extremely light, fast, and flexible Java REST API framework built atop Undertow.
http://github.com/noboomu/proteus
@@ -33,9 +33,9 @@
1.8
1.8
UTF-8
- 2.8.8.1
3.0.0
1.4.13.Final
+ 2.9.6
@@ -247,35 +247,35 @@
com.fasterxml.jackson.core
jackson-annotations
- 2.8.0
+ ${version.jackson}
com.fasterxml.jackson.core
jackson-core
- 2.8.10
+ ${version.jackson}
com.fasterxml.jackson.dataformat
jackson-dataformat-xml
- 2.8.10
+ ${version.jackson}
com.fasterxml.jackson.module
jackson-module-afterburner
- 2.8.10
+ ${version.jackson}
com.fasterxml.jackson.datatype
jackson-datatype-jdk8
- 2.8.10
+ ${version.jackson}
com.fasterxml.jackson.core
jackson-databind
- 2.8.8.1
+ ${version.jackson}
io.swagger
@@ -341,11 +341,6 @@
jansi
1.15
-
- io.sinistral
- jsoniter
- 0.9.9
-
org.reactivestreams
reactive-streams
diff --git a/src/main/java/io/sinistral/proteus/ProteusApplication.java b/src/main/java/io/sinistral/proteus/ProteusApplication.java
index f844fe3..9eb9b8c 100644
--- a/src/main/java/io/sinistral/proteus/ProteusApplication.java
+++ b/src/main/java/io/sinistral/proteus/ProteusApplication.java
@@ -126,9 +126,24 @@ public void start()
return;
}
- log.info("Configuring modules...");
+ log.info("Configuring modules: " + registeredModules);
Set modules = registeredModules.stream().map(mc -> injector.getInstance(mc)).collect(Collectors.toSet());
+
+ //boolean needsMappingModule = true;
+
+// for(Module m : modules)
+// {
+// if(m.getClass().getSuperclass().equals(MappingModule.class))
+// {
+// needsMappingModule = false;
+// }
+// }
+//
+// if(needsMappingModule)
+// {
+// modules.add(injector.getInstance(MappingModule.class));
+// }
injector = injector.createChildInjector(modules);
diff --git a/src/main/java/io/sinistral/proteus/modules/ApplicationModule.java b/src/main/java/io/sinistral/proteus/modules/ApplicationModule.java
index 68391c4..0da34d3 100644
--- a/src/main/java/io/sinistral/proteus/modules/ApplicationModule.java
+++ b/src/main/java/io/sinistral/proteus/modules/ApplicationModule.java
@@ -12,19 +12,20 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
+import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
+import com.fasterxml.jackson.module.afterburner.AfterburnerModule;
import com.google.common.util.concurrent.Service;
import com.google.inject.AbstractModule;
import com.google.inject.Singleton;
import com.google.inject.TypeLiteral;
import com.google.inject.name.Names;
-import com.jsoniter.DecodingMode;
-import com.jsoniter.JsonIterator;
-import com.jsoniter.annotation.JsoniterAnnotationSupport;
-import com.jsoniter.output.EncodingMode;
-import com.jsoniter.output.JsonStream;
import com.typesafe.config.Config;
+import io.sinistral.proteus.server.Extractors;
+import io.sinistral.proteus.server.ServerResponse;
import io.sinistral.proteus.server.endpoints.EndpointInfo;
import io.undertow.server.DefaultResponseListener;
import io.undertow.server.HandlerWrapper;
@@ -102,12 +103,38 @@ protected void configure()
{
}).annotatedWith(Names.named("registeredHandlerWrappers")).toInstance(registeredHandlerWrappers);
- this.bind(XmlMapper.class).toInstance(new XmlMapper());
+
+ this.bindMappers();
- JsonIterator.setMode(DecodingMode.DYNAMIC_MODE_AND_MATCH_FIELD_WITH_HASH);
- JsonStream.setMode(EncodingMode.DYNAMIC_MODE);
- JsoniterAnnotationSupport.enable();
+ }
+
+ /**
+ * Override for customizing XmlMapper and ObjectMapper
+ */
+ public void bindMappers()
+ {
+ this.bind(XmlMapper.class).toInstance(new XmlMapper());
+// JsonIterator.setMode(DecodingMode.DYNAMIC_MODE_AND_MATCH_FIELD_WITH_HASH);
+// JsonStream.setMode(EncodingMode.DYNAMIC_MODE);
+// JsoniterAnnotationSupport.enable();
+
+ ObjectMapper objectMapper = new ObjectMapper();
+ objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+ objectMapper.configure(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT, true);
+ objectMapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
+ objectMapper.configure(DeserializationFeature.EAGER_DESERIALIZER_FETCH,true);
+ objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
+ objectMapper.configure(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, true);
+
+ objectMapper.registerModule(new AfterburnerModule());
+ objectMapper.registerModule(new Jdk8Module());
+
+ this.bind(ObjectMapper.class).toInstance(objectMapper);
+
+ this.requestStaticInjection(Extractors.class);
+
+ this.requestStaticInjection(ServerResponse.class);
}
}
diff --git a/src/main/java/io/sinistral/proteus/server/Extractors.java b/src/main/java/io/sinistral/proteus/server/Extractors.java
index de2ca88..b6543b5 100644
--- a/src/main/java/io/sinistral/proteus/server/Extractors.java
+++ b/src/main/java/io/sinistral/proteus/server/Extractors.java
@@ -17,14 +17,17 @@
import java.util.Objects;
import java.util.function.Function;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
-import com.jsoniter.JsonIterator;
-import com.jsoniter.any.Any;
-import com.jsoniter.spi.TypeLiteral;
+import com.google.inject.Inject;
import io.sinistral.proteus.server.predicates.ServerPredicates;
import io.undertow.server.HttpServerExchange;
-import io.undertow.server.handlers.form.FormData.FormValue;
import io.undertow.server.handlers.form.FormDataParser;
import io.undertow.util.HttpString;
import io.undertow.util.Methods;
@@ -34,8 +37,24 @@
*/
public class Extractors
{
-
- protected static final XmlMapper XML_MAPPER = new XmlMapper();
+ private static Logger log = LoggerFactory.getLogger(Extractors.class.getCanonicalName());
+
+ @Inject
+ public static XmlMapper XML_MAPPER;
+
+ @Inject
+ public static ObjectMapper OBJECT_MAPPER;
+
+ public static Function parseJson = (bytes) -> {
+ try
+ {
+ return OBJECT_MAPPER.readTree(bytes);
+ } catch (Exception e)
+ {
+ log.error(e.getMessage(),e);
+ return null;
+ }
+ };
public static class Optional
{
@@ -45,12 +64,12 @@ public static java.util.Optional extractWithFunction(final HttpServerExch
return string(exchange, name).map(function);
}
- public static java.util.Optional jsonIterator(final HttpServerExchange exchange)
+ public static java.util.Optional jsonNode(final HttpServerExchange exchange)
{
- return java.util.Optional.ofNullable(exchange.getAttachment(ServerRequest.BYTE_BUFFER_KEY)).map(ByteBuffer::array).map(JsonIterator::parse);
+ return java.util.Optional.ofNullable(exchange.getAttachment(ServerRequest.BYTE_BUFFER_KEY)).map(ByteBuffer::array).map(parseJson);
}
- public static java.util.Optional model(final HttpServerExchange exchange, final TypeLiteral type )
+ public static java.util.Optional model(final HttpServerExchange exchange, final TypeReference type )
{
if( ServerPredicates.XML_PREDICATE.resolve(exchange) )
{
@@ -77,14 +96,15 @@ public static java.util.Optional model(final HttpServerExchange exchange
}
- public static java.util.Optional jsonModel(final HttpServerExchange exchange, final TypeLiteral type )
+ public static java.util.Optional jsonModel(final HttpServerExchange exchange, final TypeReference type )
{
- return jsonIterator(exchange).map(i -> {
+ return java.util.Optional.ofNullable(exchange.getAttachment(ServerRequest.BYTE_BUFFER_KEY)).map(ByteBuffer::array).map( b -> {
try
{
- return i.read(type);
+ return OBJECT_MAPPER.readValue(b, type);
} catch (Exception e)
{
+ //log.error(e.getMessage(),e);
return null;
}
});
@@ -92,18 +112,19 @@ public static java.util.Optional jsonModel(final HttpServerExchange exch
public static java.util.Optional jsonModel(final HttpServerExchange exchange, final Class type )
{
- return jsonIterator(exchange).map(i -> {
+ return java.util.Optional.ofNullable(exchange.getAttachment(ServerRequest.BYTE_BUFFER_KEY)).map(ByteBuffer::array).map( b -> {
try
{
- return i.read(type);
+ return OBJECT_MAPPER.readValue(b, type);
} catch (Exception e)
{
+ //log.error(e.getMessage(),e);
return null;
}
});
}
- public static java.util.Optional xmlModel(final HttpServerExchange exchange, final TypeLiteral type )
+ public static java.util.Optional xmlModel(final HttpServerExchange exchange, final TypeReference type )
{
return java.util.Optional.ofNullable(exchange.getAttachment(ServerRequest.BYTE_BUFFER_KEY)).map(ByteBuffer::array).map( b -> {
try
@@ -111,6 +132,7 @@ public static java.util.Optional xmlModel(final HttpServerExchange excha
return XML_MAPPER.readValue(b,XML_MAPPER.getTypeFactory().constructType(type.getType()));
} catch (Exception e)
{
+ //log.error(e.getMessage(),e);
return null;
}
});
@@ -124,6 +146,7 @@ public static java.util.Optional xmlModel(final HttpServerExchange excha
return XML_MAPPER.readValue(b,type);
} catch (Exception e)
{
+ //log.error(e.getMessage(),e);
return null;
}
});
@@ -150,9 +173,9 @@ public static java.util.Optional zonedDateTime(final HttpServerEx
}
- public static java.util.Optional any(final HttpServerExchange exchange )
+ public static java.util.Optional any(final HttpServerExchange exchange )
{
- return java.util.Optional.ofNullable(exchange.getAttachment(ServerRequest.BYTE_BUFFER_KEY)).map(t -> JsonIterator.deserialize(t.array()));
+ return java.util.Optional.ofNullable(exchange.getAttachment(ServerRequest.BYTE_BUFFER_KEY)).map( b -> parseJson.apply(b.array()));
}
public static java.util.Optional integerValue(final HttpServerExchange exchange, final String name)
@@ -267,11 +290,11 @@ public static OffsetDateTime offsetDateTime(final HttpServerExchange exchange,fi
}
- public static T jsonModel(final HttpServerExchange exchange, final TypeLiteral type ) throws IllegalArgumentException
+ public static T jsonModel(final HttpServerExchange exchange, final TypeReference type ) throws IllegalArgumentException
{
try
{
- return jsonIterator(exchange).read(type);
+ return OBJECT_MAPPER.readValue(exchange.getAttachment(ServerRequest.BYTE_BUFFER_KEY).array(), type);
}
catch( Exception e )
{
@@ -283,7 +306,7 @@ public static T jsonModel(final HttpServerExchange exchange, final Class
{
try
{
- return jsonIterator(exchange).read(type);
+ return OBJECT_MAPPER.readValue(exchange.getAttachment(ServerRequest.BYTE_BUFFER_KEY).array(), type);
}
catch( Exception e )
{
@@ -306,7 +329,7 @@ public static T xmlModel(final HttpServerExchange exchange, final Class
}
}
- public static T xmlModel(final HttpServerExchange exchange, final TypeLiteral type ) throws IllegalArgumentException
+ public static T xmlModel(final HttpServerExchange exchange, final TypeReference type ) throws IllegalArgumentException
{
try
{
@@ -319,20 +342,21 @@ public static T xmlModel(final HttpServerExchange exchange, final TypeLiter
}
}
- public static Any any(final HttpServerExchange exchange )
+ public static JsonNode any(final HttpServerExchange exchange )
{
try
{
- return JsonIterator.parse( exchange.getAttachment(ServerRequest.BYTE_BUFFER_KEY).array() ).readAny();
- } catch (IOException e)
+ return parseJson.apply( exchange.getAttachment(ServerRequest.BYTE_BUFFER_KEY).array() );
+ } catch (Exception e)
{
- return Any.wrapNull();
+ log.warn(e.getMessage(),e);
+ return OBJECT_MAPPER.createObjectNode();
}
}
- public static JsonIterator jsonIterator(final HttpServerExchange exchange )
+ public static JsonNode jsonNode(final HttpServerExchange exchange )
{
- return JsonIterator.parse(exchange.getAttachment(ServerRequest.BYTE_BUFFER_KEY).array());
+ return parseJson.apply(exchange.getAttachment(ServerRequest.BYTE_BUFFER_KEY).array());
}
public static Path filePath(final HttpServerExchange exchange, final String name) throws java.lang.IllegalArgumentException
@@ -413,7 +437,7 @@ public static Boolean booleanValue(final HttpServerExchange exchange, final Str
return Boolean.parseBoolean(string(exchange, name));
}
- public static T model(final HttpServerExchange exchange, final TypeLiteral type ) throws IllegalArgumentException
+ public static T model(final HttpServerExchange exchange, final TypeReference type ) throws IllegalArgumentException
{
if( ServerPredicates.XML_PREDICATE.resolve(exchange) )
{
diff --git a/src/main/java/io/sinistral/proteus/server/ServerResponse.java b/src/main/java/io/sinistral/proteus/server/ServerResponse.java
index f88ad6d..cd174ee 100644
--- a/src/main/java/io/sinistral/proteus/server/ServerResponse.java
+++ b/src/main/java/io/sinistral/proteus/server/ServerResponse.java
@@ -10,10 +10,9 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
-import com.jsoniter.output.JsonContext;
-import com.jsoniter.output.JsonStream;
+import com.google.inject.Inject;
import io.sinistral.proteus.server.predicates.ServerPredicates;
import io.undertow.io.IoCallback;
@@ -34,7 +33,11 @@ public class ServerResponse
{
private static Logger log = LoggerFactory.getLogger(ServerResponse.class.getCanonicalName());
- protected static final XmlMapper XML_MAPPER = new XmlMapper();
+ @Inject
+ protected static XmlMapper XML_MAPPER;
+
+ @Inject
+ protected static ObjectMapper OBJECT_MAPPER;
protected ByteBuffer body;
@@ -44,7 +47,7 @@ public class ServerResponse
protected String contentType = null;
protected T entity;
protected Throwable throwable;
- protected Class extends JsonContext> jsonContext;
+// protected Class extends JsonContext> jsonContext;
protected IoCallback ioCallback;
protected boolean hasCookies = false;
protected boolean hasHeaders = false;
@@ -239,11 +242,11 @@ public ServerResponse textPlain()
return this;
}
- public ServerResponse jsonContext(Class extends JsonContext> context)
- {
- this.jsonContext = context;
- return this;
- }
+// public ServerResponse jsonContext(Class extends JsonContext> context)
+// {
+// this.jsonContext = context;
+// return this;
+// }
public ServerResponse ok()
{
@@ -420,7 +423,7 @@ else if (hasEntity)
else
{
- exchange.getResponseSender().send(JsonStream.serializeToBytes(this.entity, this.jsonContext));
+ exchange.getResponseSender().send(ByteBuffer.wrap(OBJECT_MAPPER.writeValueAsBytes(this.entity)));
}
} catch (Exception e)
diff --git a/src/main/java/io/sinistral/proteus/server/handlers/HandlerGenerator.java b/src/main/java/io/sinistral/proteus/server/handlers/HandlerGenerator.java
index 58be0d6..1b3e34b 100644
--- a/src/main/java/io/sinistral/proteus/server/handlers/HandlerGenerator.java
+++ b/src/main/java/io/sinistral/proteus/server/handlers/HandlerGenerator.java
@@ -42,7 +42,7 @@
import com.google.inject.Inject;
import com.google.inject.name.Named;
-import com.jsoniter.spi.TypeLiteral;
+import com.fasterxml.jackson.core.type.TypeReference;
import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
@@ -99,8 +99,8 @@ public enum TypeHandler
StringType("String $L = $T.string(exchange,$S)", false, StatementParameterType.LITERAL, io.sinistral.proteus.server.Extractors.class, StatementParameterType.STRING),
BooleanType("Boolean $L = $T.booleanValue(exchange,$S)", false, StatementParameterType.LITERAL, io.sinistral.proteus.server.Extractors.class, StatementParameterType.STRING),
FilePathType("$T $L = $T.filePath(exchange,$S)", true, java.nio.file.Path.class, StatementParameterType.LITERAL, io.sinistral.proteus.server.Extractors.class, StatementParameterType.STRING),
- AnyType("$T $L = $T.any(exchange)", true, com.jsoniter.any.Any.class, StatementParameterType.LITERAL, io.sinistral.proteus.server.Extractors.class),
- JsonIteratorType("$T $L = $T.jsonIterator(exchange)", true, com.jsoniter.JsonIterator.class, StatementParameterType.LITERAL, io.sinistral.proteus.server.Extractors.class),
+ AnyType("$T $L = $T.any(exchange)", true, com.fasterxml.jackson.databind.JsonNode.class, StatementParameterType.LITERAL, io.sinistral.proteus.server.Extractors.class),
+ JsonNodeType("$T $L = $T.jsonNode(exchange)", true, com.fasterxml.jackson.databind.JsonNode.class, StatementParameterType.LITERAL, io.sinistral.proteus.server.Extractors.class),
ModelType("$T $L = io.sinistral.proteus.server.Extractors.model(exchange,$L)", true, StatementParameterType.TYPE, StatementParameterType.LITERAL, StatementParameterType.LITERAL),
// EnumType("$T $L = $T.enumValue(exchange,$T.class,$S)", true, StatementParameterType.TYPE, StatementParameterType.LITERAL,io.sinistral.proteus.server.Extractors.class, StatementParameterType.TYPE, StatementParameterType.STRING),
@@ -118,6 +118,10 @@ public enum TypeHandler
QueryListValueOfType("$T<$T> $L = exchange.getQueryParameters().get($S).stream().map($T::valueOf).collect(java.util.stream.Collectors.toList())", false, java.util.List.class, StatementParameterType.RAW, StatementParameterType.LITERAL, StatementParameterType.STRING, StatementParameterType.RAW),
QueryListFromStringType("$T<$T> $L = exchange.getQueryParameters().get($S).stream().map($T::fromString).collect(java.util.stream.Collectors.toList())", false, java.util.List.class, StatementParameterType.RAW, StatementParameterType.LITERAL, StatementParameterType.STRING, StatementParameterType.RAW),
+ QuerySetValueOfType("$T<$T> $L = exchange.getQueryParameters().get($S).stream().map($T::valueOf).collect(java.util.stream.Collectors.toSet())", false, java.util.Set.class, StatementParameterType.RAW, StatementParameterType.LITERAL, StatementParameterType.STRING, StatementParameterType.RAW),
+ QuerySetFromStringType("$T<$T> $L = exchange.getQueryParameters().get($S).stream().map($T::fromString).collect(java.util.stream.Collectors.toSet())", false, java.util.Set.class, StatementParameterType.RAW, StatementParameterType.LITERAL, StatementParameterType.STRING, StatementParameterType.RAW),
+
+
//BeanListValueOfType("$T<$T> $L = $T.string(exchange,$S).map($T::valueOf).collect(java.util.stream.Collectors.toList())", true, java.util.List.class, StatementParameterType.RAW, StatementParameterType.LITERAL, io.sinistral.proteus.server.Extractors.class, StatementParameterType.LITERAL, StatementParameterType.RAW),
BeanListValueOfType("$T $L = io.sinistral.proteus.server.Extractors.model(exchange,$L)", true, StatementParameterType.TYPE, StatementParameterType.LITERAL, StatementParameterType.LITERAL),
BeanListFromStringType("$T $L = io.sinistral.proteus.server.Extractors.model(exchange,$L)", true, StatementParameterType.TYPE, StatementParameterType.LITERAL, StatementParameterType.LITERAL),
@@ -134,13 +138,16 @@ public enum TypeHandler
QueryOptionalListValueOfType("$T $L = java.util.Optional.ofNullable(exchange.getQueryParameters().get($S)).map(java.util.Deque::stream).map( p -> p.map($T::valueOf).collect(java.util.stream.Collectors.toList()))", false, StatementParameterType.RAW, StatementParameterType.LITERAL, StatementParameterType.STRING, StatementParameterType.RAW),
QueryOptionalListFromStringType("$T $L = java.util.Optional.ofNullable(exchange.getQueryParameters().get($S)).map(java.util.Deque::stream).map( p -> p.map($T::fromString).collect(java.util.stream.Collectors.toList()))", false, StatementParameterType.RAW, StatementParameterType.LITERAL, StatementParameterType.STRING, StatementParameterType.RAW),
+ QueryOptionalSetValueOfType("$T $L = java.util.Optional.ofNullable(exchange.getQueryParameters().get($S)).map(java.util.Deque::stream).map( p -> p.map($T::valueOf).collect(java.util.stream.Collectors.toSet()))", false, StatementParameterType.RAW, StatementParameterType.LITERAL, StatementParameterType.STRING, StatementParameterType.RAW),
+ QueryOptionalSetFromStringType("$T $L = java.util.Optional.ofNullable(exchange.getQueryParameters().get($S)).map(java.util.Deque::stream).map( p -> p.map($T::fromString).collect(java.util.stream.Collectors.toSet()))", false, StatementParameterType.RAW, StatementParameterType.LITERAL, StatementParameterType.STRING, StatementParameterType.RAW),
+
OptionalBeanListValueOfType("java.util.Optional<$L> $L = $T.model(exchange,$L)", false, StatementParameterType.TYPE, StatementParameterType.LITERAL, io.sinistral.proteus.server.Extractors.Optional.class, StatementParameterType.LITERAL),
OptionalBeanListFromStringType("java.util.Optional<$L> $L = $T.model(exchange,$L)", false, StatementParameterType.TYPE, StatementParameterType.LITERAL, io.sinistral.proteus.server.Extractors.Optional.class, StatementParameterType.LITERAL),
-
- OptionalJsonIteratorType("$T<$T> $L = $T.jsonIterator(exchange)", true, Optional.class, com.jsoniter.JsonIterator.class, StatementParameterType.LITERAL, io.sinistral.proteus.server.Extractors.Optional.class),
- OptionalAnyType("$T<$T> $L = $T.any(exchange)", true, Optional.class, com.jsoniter.any.Any.class, StatementParameterType.LITERAL, io.sinistral.proteus.server.Extractors.Optional.class),
+
+ OptionalJsonNodeType("$T<$T> $L = $T.jsonNode(exchange)", true, Optional.class, com.fasterxml.jackson.databind.JsonNode.class, StatementParameterType.LITERAL, io.sinistral.proteus.server.Extractors.Optional.class),
+ OptionalAnyType("$T<$T> $L = $T.any(exchange)", true, Optional.class, com.fasterxml.jackson.databind.JsonNode.class, StatementParameterType.LITERAL, io.sinistral.proteus.server.Extractors.Optional.class),
OptionalStringType("$T $L = $T.string(exchange,$S)", false, Optional.class, StatementParameterType.LITERAL, io.sinistral.proteus.server.Extractors.Optional.class, StatementParameterType.STRING),
OptionalLongType("$T $L = $T.longValue(exchange,$S)", false, Optional.class, StatementParameterType.LITERAL, io.sinistral.proteus.server.Extractors.Optional.class, StatementParameterType.STRING),
OptionalIntegerType("$T $L = $T.integerValue(exchange,$S)", false, Optional.class, StatementParameterType.LITERAL, io.sinistral.proteus.server.Extractors.Optional.class, StatementParameterType.STRING),
@@ -152,6 +159,8 @@ public enum TypeHandler
OptionalFloatType("$T $L = $T.floatValue(exchange,$S)", false, Optional.class, StatementParameterType.LITERAL, io.sinistral.proteus.server.Extractors.Optional.class, StatementParameterType.STRING),
OptionalDoubleType("$T $L = $T.doubleValue(exchange,$S)", false, Optional.class, StatementParameterType.LITERAL, io.sinistral.proteus.server.Extractors.Optional.class, StatementParameterType.STRING),
+
+
OptionalDateType("$T<$T> $L = $T.date(exchange,$S)", false, Optional.class, java.util.Date.class, StatementParameterType.LITERAL, io.sinistral.proteus.server.Extractors.Optional.class, StatementParameterType.STRING),
OptionalInstantType("$T<$T> $L = $T.instant(exchange,$S)", false, Optional.class, java.time.Instant.class, StatementParameterType.LITERAL, io.sinistral.proteus.server.Extractors.Optional.class, StatementParameterType.STRING),
OptionalZonedDateTimeType("$T<$T> $L = $T.zonedDateTime(exchange,$S)", false, Optional.class, java.time.ZonedDateTime.class, StatementParameterType.LITERAL, io.sinistral.proteus.server.Extractors.Optional.class, StatementParameterType.STRING),
@@ -182,7 +191,7 @@ public String statement()
final private String statement;
/**
- * If the TypeLiteral
requires the {@link io.undertow.server.HttpHandler} to block
+ * If the TypeReference
requires the {@link io.undertow.server.HttpHandler} to block
*/
final private boolean isBlocking;
@@ -211,7 +220,7 @@ public static void addStatement(MethodSpec.Builder builder, Parameter parameter,
Object[] args = new Object[handler.parameterTypes.length];
-///typeLiteralNameForParameterizedType
+///typeReferenceNameForParameterizedType
for (int i = 0; i < handler.parameterTypes.length; i++)
{
if (handler.parameterTypes[i] instanceof StatementParameterType)
@@ -320,8 +329,10 @@ public static TypeHandler forType(Type type, Boolean isBeanParam)
boolean hasFromString = false;
boolean isOptional = type.getTypeName().contains("java.util.Optional");
boolean isArray = type.getTypeName().contains("java.util.List");
+ boolean isSet = type.getTypeName().contains("java.util.Set");
+ boolean isMap = type.getTypeName().contains("java.util.Map");
- if (!isOptional && !isArray)
+ if (!isOptional && !isArray && !isSet)
{
try
{
@@ -378,6 +389,47 @@ else if (hasFromStringMethod(erasedType))
}
}
+ if (isSet && !isOptional)
+ {
+ try
+ {
+ Class> erasedType = (Class>) extractErasedType(type);
+
+ if (hasValueOfMethod(erasedType))
+ {
+ if(!isBeanParam)
+ {
+ return QuerySetValueOfType;
+
+ }
+ else
+ {
+ return BeanListValueOfType;
+ }
+ }
+ else if (hasFromStringMethod(erasedType))
+ {
+ if(!isBeanParam)
+ {
+ return QuerySetFromStringType;
+
+ }
+ else
+ {
+ return BeanListFromStringType;
+ }
+ }
+ else
+ {
+ return ModelType;
+ }
+
+ } catch (Exception e)
+ {
+ log.error(e.getMessage(), e);
+
+ }
+ }
else if (isArray && isOptional)
{
try
@@ -427,6 +479,55 @@ else if (hasFromStringMethod(erasedType))
}
}
+ else if (isSet && isOptional)
+ {
+ try
+ {
+
+ if (type instanceof ParameterizedType)
+ {
+ ParameterizedType pType = (ParameterizedType) type;
+ type = pType.getActualTypeArguments()[0];
+ }
+
+ Class> erasedType = (Class>) extractErasedType(type);
+
+ if (hasValueOfMethod(erasedType))
+ {
+ if(!isBeanParam)
+ {
+ return QueryOptionalSetValueOfType;
+
+ }
+ else
+ {
+ return OptionalBeanListValueOfType;
+ }
+
+ }
+ else if (hasFromStringMethod(erasedType))
+ {
+ if(!isBeanParam)
+ {
+ return QueryOptionalSetFromStringType;
+
+ }
+ else
+ {
+ return OptionalBeanListFromStringType;
+ }
+ }
+ else
+ {
+ return ModelType;
+ }
+
+ } catch (Exception e)
+ {
+ log.error(e.getMessage(), e);
+
+ }
+ }
// log.debug("type: " + type.getTypeName() + " valueOf: " + hasValueOf + " fromString: " + hasFromString);
@@ -474,13 +575,13 @@ else if (type.equals(java.time.OffsetDateTime.class))
{
return OffsetDateTimeType;
}
- else if (type.equals(com.jsoniter.any.Any.class))
+ else if (type.equals(com.fasterxml.jackson.databind.JsonNode.class))
{
return AnyType;
}
- else if (type.equals(com.jsoniter.JsonIterator.class))
+ else if (type.equals(com.fasterxml.jackson.databind.JsonNode.class))
{
- return JsonIteratorType;
+ return JsonNodeType;
}
else if (isOptional)
{
@@ -691,9 +792,12 @@ protected void addClassMethodHandlers(TypeSpec.Builder typeBuilder, Class> cla
TypeHandler handler = TypeHandler.forType(t);
- return (handler.equals(TypeHandler.ModelType) || handler.equals(TypeHandler.OptionalModelType));
+ return (handler.equals(TypeHandler.ModelType) || handler.equals(TypeHandler.OptionalModelType) );
- }).collect(Collectors.toMap(java.util.function.Function.identity(), HandlerGenerator::typeLiteralNameForParameterizedType));
+ }).collect(Collectors.toMap(java.util.function.Function.identity(), HandlerGenerator::typeReferenceNameForParameterizedType));
+
+
+
Arrays.stream(clazz.getDeclaredMethods()).filter( m -> m.getAnnotation(ApiOperation.class) != null).flatMap(m -> Arrays.stream(m.getParameters())).forEach( p -> {
@@ -706,9 +810,9 @@ protected void addClassMethodHandlers(TypeSpec.Builder typeBuilder, Class> cla
{
TypeHandler handler = TypeHandler.forType(p.getParameterizedType(),true);
- if( handler.equals(TypeHandler.BeanListValueOfType) || handler.equals(TypeHandler.BeanListFromStringType) || handler.equals(TypeHandler.OptionalBeanListValueOfType) || handler.equals(TypeHandler.OptionalBeanListFromStringType))
+ if( handler.equals(TypeHandler.BeanListValueOfType) || handler.equals(TypeHandler.BeanListFromStringType) || handler.equals(TypeHandler.OptionalBeanListValueOfType) || handler.equals(TypeHandler.OptionalBeanListFromStringType))
{
- parameterizedLiteralsNameMap.put(p.getParameterizedType(),HandlerGenerator.typeLiteralNameForParameterizedType(p.getParameterizedType()));
+ parameterizedLiteralsNameMap.put(p.getParameterizedType(),HandlerGenerator.typeReferenceNameForParameterizedType(p.getParameterizedType()));
}
}
@@ -724,7 +828,7 @@ protected void addClassMethodHandlers(TypeSpec.Builder typeBuilder, Class> cla
// TypeHandler handler = TypeHandler.forType(t);
// return (handler.equals(TypeHandler.ModelType) || handler.equals(TypeHandler.OptionalModelType));
- // }).collect(Collectors.toMap(java.util.function.Function.identity(), HandlerGenerator::typeLiteralNameForParameterizedType));
+ // }).collect(Collectors.toMap(java.util.function.Function.identity(), HandlerGenerator::typeReferenceNameForParameterizedType));
final Map literalsNameMap = Arrays.stream(clazz.getDeclaredMethods()).filter( m -> m.getAnnotation(ApiOperation.class) != null).flatMap(m -> Arrays.stream(m.getParameters()).map(Parameter::getParameterizedType)).filter(t -> {
@@ -784,11 +888,11 @@ else if (t.equals(HttpServerExchange.class) || t.equals(ServerRequest.class))
return true;
- }).distinct().collect(Collectors.toMap(java.util.function.Function.identity(), HandlerGenerator::typeLiteralNameForType));
+ }).distinct().collect(Collectors.toMap(java.util.function.Function.identity(), HandlerGenerator::typeReferenceNameForType));
- parameterizedLiteralsNameMap.forEach((t, n) -> initBuilder.addStatement("final $T<$L> $LTypeLiteral = new $T<$L>(){}", TypeLiteral.class, t, n, TypeLiteral.class, t));
+ parameterizedLiteralsNameMap.forEach((t, n) -> initBuilder.addStatement("final $T<$L> $LTypeReference = new $T<$L>(){}", TypeReference.class, t, n, TypeReference.class, t));
- literalsNameMap.forEach((t, n) -> initBuilder.addStatement("final $T<$T> $LTypeLiteral = new $T<$T>(){}", TypeLiteral.class, t, n, TypeLiteral.class, t));
+ literalsNameMap.forEach((t, n) -> initBuilder.addStatement("final $T<$T> $LTypeReference = new $T<$T>(){}", TypeReference.class, t, n, TypeReference.class, t));
Optional typeLevelWrapAnnotation = Optional.ofNullable(clazz.getAnnotation(io.sinistral.proteus.annotations.Chain.class));
Map, String> typeLevelHandlerWrapperMap = new LinkedHashMap, String>();
@@ -998,6 +1102,8 @@ else if (t.equals(HttpServerExchange.class) || t.equals(ServerRequest.class))
}
}
+ log.debug("parameterizedLiteralsNameMap: " + parameterizedLiteralsNameMap);
+
Arrays.stream(m.getParameters()).forEachOrdered(p -> {
Type type = p.getParameterizedType();
@@ -1086,11 +1192,20 @@ else if (handler.equals(TypeHandler.FromStringType))
TypeHandler t = TypeHandler.forType(type, isBeanParameter);
+ log.debug("beanParam handler: " + t);
+
if (t.equals(TypeHandler.OptionalModelType) || t.equals(TypeHandler.ModelType))
{
String interfaceType = parameterizedLiteralsNameMap.get(type);
- String pType = interfaceType != null ? interfaceType + "TypeLiteral" : type.getTypeName() + ".class";
+ String typeName = type.getTypeName();
+
+ if(typeName.indexOf("$") > -1)
+ {
+ typeName = typeName.replace("$", ".");
+ }
+
+ String pType = interfaceType != null ? interfaceType + "TypeReference" : typeName + ".class";
methodBuilder.addStatement(t.statement, type, p.getName(), pType);
@@ -1099,7 +1214,14 @@ else if (t.equals(TypeHandler.BeanListFromStringType) || t.equals(TypeHandler.Be
{
String interfaceType = parameterizedLiteralsNameMap.get(type);
- String pType = interfaceType != null ? interfaceType + "TypeLiteral" : type.getTypeName() + ".class";
+ String typeName = type.getTypeName();
+
+ if(typeName.indexOf("$") > -1)
+ {
+ typeName = typeName.replace("$", ".");
+ }
+
+ String pType = interfaceType != null ? interfaceType + "TypeReference" : typeName + ".class";
methodBuilder.addStatement(t.statement, type, p.getName(), pType);
@@ -1109,7 +1231,7 @@ else if (t.equals(TypeHandler.OptionalFromStringType) || t.equals(TypeHandler.Op
TypeHandler.addStatement(methodBuilder, p);
}
- else if (t.equals(TypeHandler.QueryOptionalListFromStringType) || t.equals(TypeHandler.QueryOptionalListValueOfType))
+ else if (t.equals(TypeHandler.QueryOptionalListFromStringType) || t.equals(TypeHandler.QueryOptionalListValueOfType) || t.equals(TypeHandler.QueryOptionalSetValueOfType) || t.equals(TypeHandler.QueryOptionalSetValueOfType))
{
// $T $L = java.util.Optional.ofNullable(exchange.getQueryParameters().get($S)).map(java.util.Deque::stream).map($T
@@ -1140,7 +1262,16 @@ else if (t.equals(TypeHandler.OptionalBeanListFromStringType) || t.equals(TypeHa
Class> erasedType = (Class>) extractErasedType(type);
+ try
+ {
+
+
methodBuilder.addStatement(t.statement, pType, p.getName(), p.getName(), erasedType);
+
+ } catch (Exception e)
+ {
+ log.error( "method builder: \nstatement: " + t.statement + "\npType: "+ pType + "\np.name(): " + p.getName() + "\nerasedType: " + erasedType);
+ }
}
else
@@ -1506,9 +1637,15 @@ else if (matches > 2)
return null;
}
- protected static String typeLiteralNameForParameterizedType(Type type)
+ protected static String typeReferenceNameForParameterizedType(Type type)
{
+
String typeName = type.getTypeName();
+
+ if(typeName.contains("Optional"))
+ {
+ log.warn("For an optional named: " + typeName);
+ }
Matcher matcher = TYPE_NAME_PATTERN.matcher(typeName);
@@ -1586,7 +1723,7 @@ protected static String typeLiteralNameForParameterizedType(Type type)
return typeName;
}
- protected static String typeLiteralNameForType(Type type)
+ protected static String typeReferenceNameForType(Type type)
{
String typeName = type.getTypeName();
@@ -1631,10 +1768,10 @@ protected static String generateFieldName(String name)
return sb.toString();
}
- protected static void generateTypeLiteral(MethodSpec.Builder builder, Type type, String name)
+ protected static void generateTypeReference(MethodSpec.Builder builder, Type type, String name)
{
- builder.addCode(CodeBlock.of("\n\ncom.jsoniter.spi.TypeLiteral<$T> $L = new com.jsoniter.spi.TypeLiteral<$L>(){};\n\n", type, name, type));
+ builder.addCode(CodeBlock.of("\n\ncom.fasterxml.jackson.core.type.TypeReference<$T> $L = new com.fasterxml.jackson.core.type.TypeReference<$L>(){};\n\n", type, name, type));
}
diff --git a/src/main/java/io/sinistral/proteus/server/handlers/ServerDefaultResponseListener.java b/src/main/java/io/sinistral/proteus/server/handlers/ServerDefaultResponseListener.java
index 651d69b..bff3542 100644
--- a/src/main/java/io/sinistral/proteus/server/handlers/ServerDefaultResponseListener.java
+++ b/src/main/java/io/sinistral/proteus/server/handlers/ServerDefaultResponseListener.java
@@ -12,10 +12,10 @@
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.google.inject.Inject;
import com.google.inject.Singleton;
-import com.jsoniter.output.JsonStream;
import io.sinistral.proteus.server.predicates.ServerPredicates;
import io.undertow.server.DefaultResponseListener;
@@ -36,6 +36,8 @@ public class ServerDefaultResponseListener implements DefaultResponseListener
@Inject
protected XmlMapper xmlMapper;
+ @Inject
+ protected ObjectMapper objectMapper;
@Override
public boolean handleDefaultResponse(HttpServerExchange exchange)
@@ -88,7 +90,15 @@ public boolean handleDefaultResponse(HttpServerExchange exchange)
}
else
{
- final String jsonBody = JsonStream.serialize(errorMap);
+ String jsonBody;
+
+ try
+ {
+ jsonBody = objectMapper.writeValueAsString(errorMap);
+ } catch (Exception e)
+ {
+ jsonBody = errorMap.toString();
+ }
exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, MediaType.APPLICATION_JSON);
exchange.getResponseHeaders().put(Headers.CONTENT_LENGTH, jsonBody.length());
diff --git a/src/test/java/io/sinistral/proteus/controllers/Tests.java b/src/test/java/io/sinistral/proteus/controllers/Tests.java
index fde4af7..fd4b76f 100644
--- a/src/test/java/io/sinistral/proteus/controllers/Tests.java
+++ b/src/test/java/io/sinistral/proteus/controllers/Tests.java
@@ -11,6 +11,7 @@
import java.util.List;
import java.util.Map;
import java.util.Optional;
+import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
@@ -26,10 +27,11 @@
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
+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 com.jsoniter.output.JsonStream;
import io.sinistral.proteus.annotations.Blocking;
import io.sinistral.proteus.models.User;
@@ -39,7 +41,6 @@
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.undertow.server.HttpServerExchange;
-import io.undertow.server.handlers.RequestBufferingHandler;
/**
* @author jbauer
@@ -61,14 +62,22 @@ public class Tests
buffer.flip();
}
+ @Inject
+ protected ObjectMapper objectMapper;
+
+
@GET
@Path("/exchange/json/serialize")
@ApiOperation(value = "Json serialization endpoint", httpMethod = "GET" )
- public void exchangeJsonSerialize(HttpServerExchange exchange)
- {
-
-
- response( JsonStream.serialize(ImmutableMap.of("message", "Hello, World!")) ).applicationJson().send(exchange);
+ public void exchangeJsonSerialize(HttpServerExchange exchange)
+ {
+ try
+ {
+ response( objectMapper.writeValueAsString(ImmutableMap.of("message", "Hello, World!")) ).applicationJson().send(exchange);
+ } catch(Exception e)
+ {
+ response().badRequest(e);
+ }
}
@GET
@@ -76,7 +85,13 @@ public void exchangeJsonSerialize(HttpServerExchange exchange)
@ApiOperation(value = "Json serialization with bytes endpoint", httpMethod = "GET" )
public void exchangeJsonSerializeToBytes(HttpServerExchange exchange)
{
- response( JsonStream.serializeToBytes(ImmutableMap.of("message", "Hello, World!")) ).applicationJson().send(exchange);
+ try
+ {
+ response( objectMapper.writeValueAsString(ImmutableMap.of("message", "Hello, World!")) ).applicationJson().send(exchange);
+ } catch(Exception e)
+ {
+ response().badRequest(e);
+ }
}
@@ -178,6 +193,38 @@ public ServerResponse responseEchoJson(ServerRequest request, @FormParam("
return response(user).applicationJson();
}
+ @POST
+ @Path("/response/json/innerClass")
+ @Produces(MediaType.APPLICATION_OCTET_STREAM)
+ @Consumes("*/*")
+ @ApiOperation(value = "Echo json inner class endpoint", httpMethod = "POST" )
+ public ServerResponse responseInnerClassTest(ServerRequest request, @BeanParam User.InnerUserModel userInnerModel ) throws Exception
+ {
+ return response(userInnerModel).applicationJson();
+ }
+
+
+ @GET
+ @Path("/generic/set")
+ @ApiOperation(value = "Generic set endpoint", httpMethod = "GET" )
+ public ServerResponse> genericSet( ServerRequest request, @QueryParam("ids") Set ids ) throws Exception
+ {
+
+ return response( ids ).applicationJson();
+
+ }
+
+
+ @GET
+ @Path("/optional/set")
+ @ApiOperation(value = "Generic optional set endpoint", httpMethod = "GET" )
+ public ServerResponse> genericOptionalSet( ServerRequest request, @QueryParam("ids") Optional> ids ) throws Exception
+ {
+
+ return response( ids.get() ).applicationJson();
+
+ }
+
@POST
@Path("/response/parse/ids")
@Blocking
diff --git a/src/test/java/io/sinistral/proteus/models/User.java b/src/test/java/io/sinistral/proteus/models/User.java
index d9cbb78..1a2b66d 100644
--- a/src/test/java/io/sinistral/proteus/models/User.java
+++ b/src/test/java/io/sinistral/proteus/models/User.java
@@ -11,6 +11,10 @@
public class User
{
+ public static class InnerUserModel {
+ public Long id;
+ }
+
public enum UserType
{
GUEST,MEMBER,ADMIN
diff --git a/src/test/java/io/sinistral/proteus/server/TestControllerEndpoints.java b/src/test/java/io/sinistral/proteus/server/TestControllerEndpoints.java
index bc3e56c..55532c8 100644
--- a/src/test/java/io/sinistral/proteus/server/TestControllerEndpoints.java
+++ b/src/test/java/io/sinistral/proteus/server/TestControllerEndpoints.java
@@ -14,11 +14,15 @@
import java.io.InputStream;
import java.nio.file.Files;
import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
+import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
+import java.util.stream.LongStream;
import org.apache.commons.io.IOUtils;
import org.hamcrest.CoreMatchers;
@@ -27,9 +31,6 @@
import org.junit.Test;
import org.junit.runner.RunWith;
-import com.jsoniter.JsonIterator;
-import com.jsoniter.output.JsonStream;
-
import io.restassured.http.ContentType;
import io.sinistral.proteus.models.User;
import io.sinistral.proteus.models.User.UserType;
@@ -45,6 +46,8 @@ public class TestControllerEndpoints
{
private File file = null;
+
+ private Set idSet = new HashSet<>();
@Before
public void setUp()
@@ -56,6 +59,11 @@ public void setUp()
random.nextBytes(bytes);
file = Files.createTempFile("test-asset", ".mp4").toFile();
+
+ LongStream.range(1L,10L).forEach( l -> {
+
+ idSet.add(l);
+ });
} catch (Exception e)
{
@@ -76,6 +84,18 @@ public void exchangeUserJson()
User user = given().accept(ContentType.JSON).log().uri().when().get("tests/exchange/user/json").as(User.class);
assertThat(user.getId(), CoreMatchers.is(123L));
}
+
+ @Test
+ public void genericSet()
+ {
+ given().accept(ContentType.JSON).log().uri().when().queryParam("ids", idSet).get("tests/generic/set").then().statusCode(200).body(containsString("1"));
+ }
+
+ @Test
+ public void optionalGenericSet()
+ {
+ given().accept(ContentType.JSON).log().uri().when().queryParam("ids",idSet).get("tests/optional/set").then().statusCode(200).body(containsString("1"));
+ }
@Test
public void exchangeUserXml()
@@ -117,13 +137,24 @@ public void responsePlaintext()
}
@Test
- public void responseEchoUser()
+ public void responseEchoModel()
+ {
+ User model = new User(101L,UserType.ADMIN);
+
+ given().contentType(ContentType.JSON).accept(ContentType.JSON).body(model).log().all().when().post("tests/response/json/echo").then().statusCode(200).and().body(containsString("101"));
+
+ }
+
+ @Test
+ public void responseInnerClassModel()
{
- User user = new User(101L,UserType.ADMIN);
+ User.InnerUserModel model = new User.InnerUserModel();
+ model.id = 101L;
- given().contentType(ContentType.JSON).accept(ContentType.JSON).body(user).log().all().when().post("tests/response/json/echo").then().statusCode(200).and().body(containsString("101"));
+ given().contentType(ContentType.JSON).accept(ContentType.JSON).body(model).log().all().when().post("tests/response/json/innerClass").then().statusCode(200).and().body(containsString("101"));
}
+
@Test
public void responseFutureUser()