Skip to content

Commit

Permalink
Merge branch '136-digest-order' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
mmazi committed Apr 3, 2021
2 parents 674810b + abadccf commit 7e58473
Show file tree
Hide file tree
Showing 5 changed files with 248 additions and 26 deletions.
15 changes: 14 additions & 1 deletion src/main/java/si/mazi/rescu/RequestWriterResolver.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@

package si.mazi.rescu;

import com.fasterxml.jackson.databind.ObjectMapper;
import si.mazi.rescu.serialization.ToStringRequestWriter;
import si.mazi.rescu.serialization.jackson.JacksonRequestWriter;

import javax.ws.rs.core.MediaType;
import java.util.HashMap;

Expand All @@ -39,7 +43,16 @@ public class RequestWriterResolver {

public RequestWriterResolver() {
}


public static RequestWriterResolver createDefault(ObjectMapper mapper) {
final RequestWriterResolver requestWriterResolver = new RequestWriterResolver();
/*requestWriterResolver.addWriter(null, new NullRequestWriter());*/
requestWriterResolver.addWriter(MediaType.APPLICATION_FORM_URLENCODED, new FormUrlEncodedRequestWriter());
requestWriterResolver.addWriter(MediaType.APPLICATION_JSON, new JacksonRequestWriter(mapper));
requestWriterResolver.addWriter(MediaType.TEXT_PLAIN, new ToStringRequestWriter());
return requestWriterResolver;
}

public void addWriter(String mediaType, RequestWriter writer) {
writers.put(mediaType, writer);
}
Expand Down
27 changes: 13 additions & 14 deletions src/main/java/si/mazi/rescu/RestInvocation.java
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,22 @@ public class RestInvocation implements Serializable {
this.path = path;
this.requestWriter = requestWriterResolver == null ? null : requestWriterResolver.resolveWriter(this.getMethodMetadata());

digestAll();
this.paramsMap.get(QueryParam.class).digestAll(this);

this.queryString = paramsMap.get(QueryParam.class).asQueryString();
this.invocationUrl = getInvocationUrl(methodMetadata.getBaseUrl(), path, this.queryString);

for (int i = 0; i < this.unannanotatedParams.size(); i++) {
Object param = this.unannanotatedParams.get(i);
if (param instanceof ParamsDigest) {
this.unannanotatedParams.set(i, ((ParamsDigest) param).digestParams(this));
}
}

this.paramsMap.keySet().stream()
.filter(par -> !QueryParam.class.equals(par))
.map(this.paramsMap::get)
.forEach(params -> params.digestAll(this));
}

public static RestInvocation create(RequestWriterResolver requestWriterResolver,
Expand Down Expand Up @@ -140,19 +152,6 @@ public static RestInvocation create(RequestWriterResolver requestWriterResolver,
return invocation;
}

private void digestAll() {
for (int i = 0; i < unannanotatedParams.size(); i++) {
Object param = unannanotatedParams.get(i);
if (param instanceof ParamsDigest) {
unannanotatedParams.set(i, ((ParamsDigest) param).digestParams(this));
}
}

for (Params params : paramsMap.values()) {
params.digestAll(this);
}
}

public static HashMap<Class<? extends Annotation>, Params> createEmptyParamsMap(Map<Class<? extends Annotation>, Params> defaultParamsMap) {
HashMap<Class<? extends Annotation>, Params> paramsMap = new HashMap<>();

Expand Down
12 changes: 1 addition & 11 deletions src/main/java/si/mazi/rescu/RestInvocationHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,8 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import si.mazi.rescu.serialization.PlainTextResponseReader;
import si.mazi.rescu.serialization.ToStringRequestWriter;
import si.mazi.rescu.serialization.jackson.DefaultJacksonObjectMapperFactory;
import si.mazi.rescu.serialization.jackson.JacksonObjectMapperFactory;
import si.mazi.rescu.serialization.jackson.JacksonRequestWriter;
import si.mazi.rescu.serialization.jackson.JacksonResponseReader;

import javax.ws.rs.Path;
Expand Down Expand Up @@ -74,15 +72,7 @@ public class RestInvocationHandler implements InvocationHandler {
}
ObjectMapper mapper = mapperFactory.createObjectMapper();

requestWriterResolver = new RequestWriterResolver();
/*requestWriterResolver.addWriter(null,
new NullRequestWriter());*/
requestWriterResolver.addWriter(MediaType.APPLICATION_FORM_URLENCODED,
new FormUrlEncodedRequestWriter());
requestWriterResolver.addWriter(MediaType.APPLICATION_JSON,
new JacksonRequestWriter(mapper));
requestWriterResolver.addWriter(MediaType.TEXT_PLAIN,
new ToStringRequestWriter());
requestWriterResolver = RequestWriterResolver.createDefault(mapper);

responseReaderResolver = new ResponseReaderResolver();
responseReaderResolver.addReader(MediaType.APPLICATION_JSON,
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/si/mazi/rescu/RestMethodMetadata.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ public class RestMethodMetadata implements Serializable {
private final Map<Class<? extends Annotation>,Annotation> methodAnnotationMap;
private final Annotation[][] parameterAnnotations;

/**
* @deprecated Use {@link #create(Method, String, String)} instead.
*/
@Deprecated
public RestMethodMetadata(Type returnType, HttpMethod httpMethod,
String baseUrl, String intfacePath, String methodPathTemplate,
Class<? extends RuntimeException> exceptionType, String reqContentType,
Expand Down
216 changes: 216 additions & 0 deletions src/test/java/si/mazi/rescu/InvocationDigestTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
/*
* Copyright (C) 2021 Matija Mazi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/

package si.mazi.rescu;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.testng.annotations.Test;

import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import java.util.HashMap;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.entry;

public class InvocationDigestTest {

private final RequestWriterResolver requestWriterResolver =
RequestWriterResolver.createDefault(new ObjectMapper());

@Test
public void shouldDigestUrlInFormParam() throws Exception {
RestInvocation restInvocation = getRestInvocation(
"digestUrlInFormParam",
new Object[]{"v1", new UrlDigest()},
String.class, UrlDigest.class);

assertThat(restInvocation.getRequestBody()).contains("signature=_50_"); // https://example.com/api/digestUrlInFormParam?q1=v1
}

@Test
public void shouldDigestUrlInHeader() throws Exception {
RestInvocation restInvocation = getRestInvocation(
"digestUrlInHeader",
new Object[]{"v1", new UrlDigest()},
String.class, UrlDigest.class);

assertThat(restInvocation.getHttpHeadersFromParams()).contains(entry("signature", "_47_")); // https://example.com/api/digestUrlInHeader?q1=v1
}

@Test
public void shouldDigestBodyInHeader() throws Exception {
RestInvocation restInvocation = getRestInvocation(
"digestBodyInHeader",
new Object[]{"This method body is 39 characters long.", new BodyDigest()},
String.class, BodyDigest.class);

assertThat(restInvocation.getHttpHeadersFromParams()).contains(entry("signature", "_39_"));
}

@Test
public void shouldDigestBodyInQueryParam() throws Exception {
RestInvocation restInvocation = getRestInvocation(
"digestBodyInQueryParam",
new Object[]{"This method body is 39 characters long.", new BodyDigest()},
String.class, BodyDigest.class);

assertThat(restInvocation.getInvocationUrl()).contains("signature=_39_");
}

@Test
public void shouldDigestHeadersInFormParam() throws Exception {
RestInvocation restInvocation = getRestInvocation(
"digestHeadersInFormParam",
new Object[]{"first", "second", new HeaderDigest()},
String.class, String.class, HeaderDigest.class);

assertThat(restInvocation.getRequestBody()).contains("signature=_2_");
}

@Test
public void shouldDigestHeadersInQueryParam() throws Exception {
RestInvocation restInvocation = getRestInvocation(
"digestHeadersInQueryParam",
new Object[]{"first", "second", new HeaderDigest()},
String.class, String.class, HeaderDigest.class);

assertThat(restInvocation.getInvocationUrl()).contains("signature=_2_");
}

@Test
public void shouldDigestUrlInPlainBody() throws Exception {
RestInvocation restInvocation = getRestInvocation(
"digestUrlInPlainBody",
new Object[]{"v1", new UrlDigest()},
String.class, UrlDigest.class);

assertThat(restInvocation.getRequestBody()).isEqualTo("_50_"); // https://example.com/api/digestUrlInPlainBody?q1=v1
}

private RestInvocation getRestInvocation(String methodName, Object[] invocationArguments, Class<?>... methodParamTypes) throws NoSuchMethodException {
return RestInvocation.create(requestWriterResolver,
RestMethodMetadata.create(
DigestService.class.getDeclaredMethod(methodName, methodParamTypes),
"https://example.com/",
"api"),
invocationArguments,
new HashMap<>()
);
}

private static String wrapInUnderscores(int number) {
return String.format("_%d_", number);
}

/** Digests the body by returning its length between underscores. */
static class BodyDigest implements ParamsDigest {
@Override public String digestParams(RestInvocation restInvocation) {
return wrapInUnderscores(restInvocation.getRequestBody().length());
}
}

/** Digests the URL by returning its length between underscores. */
static class UrlDigest implements ParamsDigest {
@Override public String digestParams(RestInvocation restInvocation) {
return wrapInUnderscores(restInvocation.getInvocationUrl().length());
}
}

/** Digests the headers by returning their count between underscores. */
static class HeaderDigest implements ParamsDigest {
@Override public String digestParams(RestInvocation restInvocation) {
return wrapInUnderscores(restInvocation.getHttpHeadersFromParams().size());
}
}

@SuppressWarnings("RestParamTypeInspection")
@Path("api")
public interface DigestService {

@POST
@Path("digestUrlInHeader")
@Produces(MediaType.TEXT_PLAIN)
@Consumes(MediaType.APPLICATION_JSON)
String digestUrlInHeader(
@QueryParam("q1") String q1,
@HeaderParam("signature") UrlDigest digest
);

@POST
@Path("digestUrlInFormParam")
@Produces(MediaType.TEXT_PLAIN)
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
String digestUrlInFormParam(
@QueryParam("q1") String q1,
@FormParam("signature") UrlDigest digest
);

@POST
@Path("digestBodyInHeader")
@Produces(MediaType.TEXT_PLAIN)
@Consumes(MediaType.TEXT_PLAIN)
String digestBodyInHeader(
String body,
@HeaderParam("signature") BodyDigest digest
);

@POST
@Path("digestBodyInQueryParam")
@Produces(MediaType.TEXT_PLAIN)
@Consumes(MediaType.TEXT_PLAIN)
String digestBodyInQueryParam(
String body,
@QueryParam("signature") BodyDigest digest
);

@POST
@Path("digestHeadersInFormParam")
@Produces(MediaType.TEXT_PLAIN)
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
String digestHeadersInFormParam(
@HeaderParam("h1") String h1,
@HeaderParam("h2") String h2,
@FormParam("signature") HeaderDigest digest
);

@POST
@Path("digestHeadersInQueryParam")
@Produces(MediaType.TEXT_PLAIN)
@Consumes(MediaType.APPLICATION_JSON)
String digestHeadersInQueryParam(
@HeaderParam("h1") String h1,
@HeaderParam("h2") String h2,
@QueryParam("signature") HeaderDigest digest
);

@POST
@Path("digestUrlInPlainBody")
@Produces(MediaType.TEXT_PLAIN)
@Consumes(MediaType.TEXT_PLAIN)
String digestUrlInPlainBody(
@QueryParam("q1") String q1,
UrlDigest digest
);
}
}

0 comments on commit 7e58473

Please sign in to comment.