Skip to content

Commit

Permalink
Added support for sets in query parameters.
Browse files Browse the repository at this point in the history
  • Loading branch information
noboomu committed Jul 18, 2018
1 parent b2edceb commit 05084d1
Show file tree
Hide file tree
Showing 5 changed files with 177 additions and 6 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@ bin
.settings/org.scala-ide.sdt.core.prefs
.cache-tests
/proteus/
/pom.xml.versionsBackup
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>io.sinistral</groupId>
<artifactId>proteus-core</artifactId>
<version>0.3.0-SNAPSHOT</version>
<version>0.3.1-SNAPSHOT</version>
<name>proteus core</name>
<description>Proteus is an extremely light, fast, and flexible Java REST API framework built atop Undertow.</description>
<url>http://github.com/noboomu/proteus</url>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand All @@ -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<String> $L = $T.string(exchange,$S)", false, Optional.class, StatementParameterType.LITERAL, io.sinistral.proteus.server.Extractors.Optional.class, StatementParameterType.STRING),
Expand All @@ -152,6 +159,8 @@ public enum TypeHandler
OptionalFloatType("$T<Long> $L = $T.floatValue(exchange,$S)", false, Optional.class, StatementParameterType.LITERAL, io.sinistral.proteus.server.Extractors.Optional.class, StatementParameterType.STRING),
OptionalDoubleType("$T<Integer> $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),
Expand Down Expand Up @@ -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
{
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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);
Expand All @@ -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()));
}
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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);
Expand All @@ -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

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);

Expand Down
23 changes: 23 additions & 0 deletions src/test/java/io/sinistral/proteus/controllers/Tests.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -192,6 +193,28 @@ public ServerResponse<User> responseEchoJson(ServerRequest request, @FormParam("
return response(user).applicationJson();
}


@GET
@Path("/generic/set")
@ApiOperation(value = "Generic set endpoint", httpMethod = "GET" )
public ServerResponse<Set<Long>> genericSet( ServerRequest request, @QueryParam("ids") Set<Long> ids ) throws Exception
{

return response( ids ).applicationJson();

}


@GET
@Path("/optional/set")
@ApiOperation(value = "Generic optional set endpoint", httpMethod = "GET" )
public ServerResponse<Set<Long>> genericOptionalSet( ServerRequest request, @QueryParam("ids") Optional<Set<Long>> ids ) throws Exception
{

return response( ids.get() ).applicationJson();

}

@POST
@Path("/response/parse/ids")
@Blocking
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -42,6 +46,8 @@ public class TestControllerEndpoints
{

private File file = null;

private Set<Long> idSet = new HashSet<>();

@Before
public void setUp()
Expand All @@ -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)
{
Expand All @@ -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()
Expand Down

0 comments on commit 05084d1

Please sign in to comment.