From 26723e6906813032d9d80f44a4bd0a624df9a314 Mon Sep 17 00:00:00 2001 From: joshua bauer Date: Fri, 13 Jul 2018 09:30:53 -0700 Subject: [PATCH 1/5] Swapped out Jsoniter with Jackson. Slightly slower but easier to use. --- pom.xml | 7 +- .../proteus/modules/ApplicationModule.java | 45 ++++++++--- .../sinistral/proteus/server/Extractors.java | 80 ++++++++++++------- .../proteus/server/ServerResponse.java | 25 +++--- .../server/handlers/HandlerGenerator.java | 44 +++++----- .../ServerDefaultResponseListener.java | 14 +++- .../sinistral/proteus/controllers/Tests.java | 30 +++++-- .../server/TestControllerEndpoints.java | 3 - 8 files changed, 159 insertions(+), 89 deletions(-) diff --git a/pom.xml b/pom.xml index 65f6b43..2cfb39b 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 io.sinistral proteus-core - 0.2.3-SNAPSHOT + 0.3.0-SNAPSHOT proteus core Proteus is an extremely light, fast, and flexible Java REST API framework built atop Undertow. http://github.com/noboomu/proteus @@ -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/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 jsonContext; +// protected Class 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 context) - { - this.jsonContext = context; - return this; - } +// public ServerResponse jsonContext(Class 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..7a682df 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), @@ -139,8 +139,8 @@ public enum TypeHandler 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), @@ -182,7 +182,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 +211,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) @@ -474,13 +474,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) { @@ -693,7 +693,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)); Arrays.stream(clazz.getDeclaredMethods()).filter( m -> m.getAnnotation(ApiOperation.class) != null).flatMap(m -> Arrays.stream(m.getParameters())).forEach( p -> { @@ -708,7 +708,7 @@ protected void addClassMethodHandlers(TypeSpec.Builder typeBuilder, Class cla 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 +724,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 +784,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>(); @@ -1090,7 +1090,7 @@ else if (handler.equals(TypeHandler.FromStringType)) { String interfaceType = parameterizedLiteralsNameMap.get(type); - String pType = interfaceType != null ? interfaceType + "TypeLiteral" : type.getTypeName() + ".class"; + String pType = interfaceType != null ? interfaceType + "TypeReference" : type.getTypeName() + ".class"; methodBuilder.addStatement(t.statement, type, p.getName(), pType); @@ -1099,7 +1099,7 @@ 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 pType = interfaceType != null ? interfaceType + "TypeReference" : type.getTypeName() + ".class"; methodBuilder.addStatement(t.statement, type, p.getName(), pType); @@ -1506,7 +1506,7 @@ else if (matches > 2) return null; } - protected static String typeLiteralNameForParameterizedType(Type type) + protected static String typeReferenceNameForParameterizedType(Type type) { String typeName = type.getTypeName(); @@ -1586,7 +1586,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 +1631,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..7e4bd95 100644 --- a/src/test/java/io/sinistral/proteus/controllers/Tests.java +++ b/src/test/java/io/sinistral/proteus/controllers/Tests.java @@ -26,10 +26,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 +40,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 +61,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 +84,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); + } } diff --git a/src/test/java/io/sinistral/proteus/server/TestControllerEndpoints.java b/src/test/java/io/sinistral/proteus/server/TestControllerEndpoints.java index bc3e56c..68b8e7e 100644 --- a/src/test/java/io/sinistral/proteus/server/TestControllerEndpoints.java +++ b/src/test/java/io/sinistral/proteus/server/TestControllerEndpoints.java @@ -27,9 +27,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; From 91f6194f02a14c3970ef6c82670643e1dd7ad547 Mon Sep 17 00:00:00 2001 From: joshua bauer Date: Fri, 13 Jul 2018 09:41:59 -0700 Subject: [PATCH 2/5] Update Jackson version. --- pom.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index 2cfb39b..64b2797 100644 --- a/pom.xml +++ b/pom.xml @@ -247,35 +247,35 @@ com.fasterxml.jackson.core jackson-annotations - 2.8.0 + 2.9.6 com.fasterxml.jackson.core jackson-core - 2.8.10 + 2.9.6 com.fasterxml.jackson.dataformat jackson-dataformat-xml - 2.8.10 + 2.9.6 com.fasterxml.jackson.module jackson-module-afterburner - 2.8.10 + 2.9.6 com.fasterxml.jackson.datatype jackson-datatype-jdk8 - 2.8.10 + 2.9.6 com.fasterxml.jackson.core jackson-databind - 2.8.8.1 + 2.9.6 io.swagger From b2edceb39c66b1ee9ed919c82c37916b7b641f8b Mon Sep 17 00:00:00 2001 From: joshua bauer Date: Mon, 16 Jul 2018 09:41:16 -0700 Subject: [PATCH 3/5] Reduce default log level. --- conf/logback.xml | 6 +++--- pom.xml | 14 +++++++------- .../sinistral/proteus/ProteusApplication.java | 17 ++++++++++++++++- 3 files changed, 26 insertions(+), 11 deletions(-) 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 64b2797..63fb7a0 100644 --- a/pom.xml +++ b/pom.xml @@ -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.9.6 + ${version.jackson} com.fasterxml.jackson.core jackson-core - 2.9.6 + ${version.jackson} com.fasterxml.jackson.dataformat jackson-dataformat-xml - 2.9.6 + ${version.jackson} com.fasterxml.jackson.module jackson-module-afterburner - 2.9.6 + ${version.jackson} com.fasterxml.jackson.datatype jackson-datatype-jdk8 - 2.9.6 + ${version.jackson} com.fasterxml.jackson.core jackson-databind - 2.9.6 + ${version.jackson} io.swagger 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); From 05084d1f454484a1108aae0e3232938a0a1a0c40 Mon Sep 17 00:00:00 2001 From: joshua bauer Date: Tue, 17 Jul 2018 17:03:54 -0700 Subject: [PATCH 4/5] Added support for sets in query parameters. --- .gitignore | 1 + pom.xml | 2 +- .../server/handlers/HandlerGenerator.java | 134 +++++++++++++++++- .../sinistral/proteus/controllers/Tests.java | 23 +++ .../server/TestControllerEndpoints.java | 23 +++ 5 files changed, 177 insertions(+), 6 deletions(-) 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/pom.xml b/pom.xml index 63fb7a0..2f124de 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 io.sinistral proteus-core - 0.3.0-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 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 7a682df..83a9514 100644 --- a/src/main/java/io/sinistral/proteus/server/handlers/HandlerGenerator.java +++ b/src/main/java/io/sinistral/proteus/server/handlers/HandlerGenerator.java @@ -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,11 +138,14 @@ 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), - + 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), @@ -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), @@ -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); @@ -691,11 +792,14 @@ 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::typeReferenceNameForParameterizedType)); + + + Arrays.stream(clazz.getDeclaredMethods()).filter( m -> m.getAnnotation(ApiOperation.class) != null).flatMap(m -> Arrays.stream(m.getParameters())).forEach( p -> { BeanParam beanParam = p.getAnnotation(BeanParam.class); @@ -706,7 +810,7 @@ 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.typeReferenceNameForParameterizedType(p.getParameterizedType())); } @@ -786,6 +890,7 @@ else if (t.equals(HttpServerExchange.class) || t.equals(ServerRequest.class)) }).distinct().collect(Collectors.toMap(java.util.function.Function.identity(), HandlerGenerator::typeReferenceNameForType)); + log.debug("parameterizedLiteralsNameMap: " + parameterizedLiteralsNameMap); 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> $LTypeReference = new $T<$T>(){}", TypeReference.class, t, n, TypeReference.class, t)); @@ -1095,6 +1200,10 @@ else if (handler.equals(TypeHandler.FromStringType)) methodBuilder.addStatement(t.statement, type, p.getName(), pType); } + + + + else if (t.equals(TypeHandler.BeanListFromStringType) || t.equals(TypeHandler.BeanListValueOfType)) { String interfaceType = parameterizedLiteralsNameMap.get(type); @@ -1109,7 +1218,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 +1249,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 @@ -1508,7 +1626,13 @@ else if (matches > 2) 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); diff --git a/src/test/java/io/sinistral/proteus/controllers/Tests.java b/src/test/java/io/sinistral/proteus/controllers/Tests.java index 7e4bd95..4e6a76c 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; @@ -192,6 +193,28 @@ public ServerResponse responseEchoJson(ServerRequest request, @FormParam(" return response(user).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/server/TestControllerEndpoints.java b/src/test/java/io/sinistral/proteus/server/TestControllerEndpoints.java index 68b8e7e..b4ad69d 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; @@ -42,6 +46,8 @@ public class TestControllerEndpoints { private File file = null; + + private Set idSet = new HashSet<>(); @Before public void setUp() @@ -53,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) { @@ -73,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() From 7c2cc52e1e0a75066a81965a23c09b7ff5e8d4e1 Mon Sep 17 00:00:00 2001 From: joshua bauer Date: Wed, 18 Jul 2018 13:51:21 -0700 Subject: [PATCH 5/5] Support for inner class model parsing. --- .../server/handlers/HandlerGenerator.java | 27 ++++++++++++++----- .../sinistral/proteus/controllers/Tests.java | 10 +++++++ .../io/sinistral/proteus/models/User.java | 4 +++ .../server/TestControllerEndpoints.java | 17 +++++++++--- 4 files changed, 48 insertions(+), 10 deletions(-) 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 83a9514..1b3e34b 100644 --- a/src/main/java/io/sinistral/proteus/server/handlers/HandlerGenerator.java +++ b/src/main/java/io/sinistral/proteus/server/handlers/HandlerGenerator.java @@ -890,7 +890,6 @@ else if (t.equals(HttpServerExchange.class) || t.equals(ServerRequest.class)) }).distinct().collect(Collectors.toMap(java.util.function.Function.identity(), HandlerGenerator::typeReferenceNameForType)); - log.debug("parameterizedLiteralsNameMap: " + parameterizedLiteralsNameMap); 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> $LTypeReference = new $T<$T>(){}", TypeReference.class, t, n, TypeReference.class, t)); @@ -1103,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(); @@ -1191,24 +1192,36 @@ 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 + "TypeReference" : 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); } - - - - else if (t.equals(TypeHandler.BeanListFromStringType) || t.equals(TypeHandler.BeanListValueOfType)) { String interfaceType = parameterizedLiteralsNameMap.get(type); - String pType = interfaceType != null ? interfaceType + "TypeReference" : 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); diff --git a/src/test/java/io/sinistral/proteus/controllers/Tests.java b/src/test/java/io/sinistral/proteus/controllers/Tests.java index 4e6a76c..fd4b76f 100644 --- a/src/test/java/io/sinistral/proteus/controllers/Tests.java +++ b/src/test/java/io/sinistral/proteus/controllers/Tests.java @@ -193,6 +193,16 @@ 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") 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 b4ad69d..55532c8 100644 --- a/src/test/java/io/sinistral/proteus/server/TestControllerEndpoints.java +++ b/src/test/java/io/sinistral/proteus/server/TestControllerEndpoints.java @@ -137,13 +137,24 @@ public void responsePlaintext() } @Test - public void responseEchoUser() + public void responseEchoModel() { - User user = new User(101L,UserType.ADMIN); + User model = new User(101L,UserType.ADMIN); - 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/echo").then().statusCode(200).and().body(containsString("101")); } + + @Test + public void responseInnerClassModel() + { + User.InnerUserModel model = new User.InnerUserModel(); + model.id = 101L; + + 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()