Skip to content

Commit

Permalink
Done:
Browse files Browse the repository at this point in the history
  - Added JaxRsMethodRepresentationExtractor
  - Added JaxRsGetMappingMethodsHandler
  - Minor refactor and test enhancement
  • Loading branch information
Robert Wojcik authored and Robert Wojcik committed Jul 29, 2020
1 parent 86a8932 commit 031e87b
Show file tree
Hide file tree
Showing 11 changed files with 421 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package com.hltech.pact.gen.domain.client.annotation.handlers;

import com.hltech.pact.gen.domain.client.annotation.MappingMethodHandler;
import com.hltech.pact.gen.domain.client.model.Body;
import com.hltech.pact.gen.domain.client.model.Param;
import com.hltech.pact.gen.domain.client.model.RequestRepresentation;
import com.hltech.pact.gen.domain.client.util.TypeExtractor;
import org.springframework.http.HttpMethod;
import org.springframework.util.Assert;

import javax.ws.rs.Consumes;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.QueryParam;
import java.lang.annotation.ElementType;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@MappingMethodHandler
public class JaxRsGetMappingMethodsHandler implements AnnotatedMethodHandler {

//TODO Turn on scanning for JAX-RS related annotations when feature is complete
@Override
public boolean isSupported(Method method) {
return false;
}

@Override
public RequestRepresentation handleRequest(Method method) {
return RequestRepresentation.builder()
.httpMethod(HttpMethod.GET)
.path(extractPath(method))
.headers(extractHeaders(method))
.body(extractBody(method))
.requestParameters(extractRequestParameters(method))
.pathParameters(extractPathParameters(method))
.build();
}

//TODO Implement resolving media headers
@Override
public String[] getResponseMediaHeaders(Method method) {
return new String[0];
}

private List<Param> extractPathParameters(Method method) {
return Arrays.stream(method.getParameters())
.filter(param -> param.getAnnotation(PathParam.class) != null)
.map(this::fromPathParam)
.collect(Collectors.toList());
}

private Param fromPathParam(Parameter parameter) {
return Param.builder()
.name(parameter.getAnnotation(PathParam.class).value())
.type(parameter.getType())
.build();
}

private List<Param> extractRequestParameters(Method method) {
return Arrays.stream(method.getParameters())
.filter(param -> param.getAnnotation(QueryParam.class) != null)
.map(this::fromQueryParam)
.collect(Collectors.toList());
}

private Param fromQueryParam(Parameter parameter) {
return Param.builder()
.name(parameter.getAnnotation(QueryParam.class).value())
.type(parameter.getType())
.build();
}

private Body extractBody(Method method) {
Optional<Parameter> requestBody = Arrays.stream(method.getParameters())
.filter(p -> p.getAnnotations().length == 0 || p.getAnnotation(Consumes.class) != null)
.findFirst();

Body.BodyBuilder builder = Body.builder();
requestBody
.map(Parameter::getType)
.ifPresent(builder::type);
requestBody
.map(Parameter::getParameterizedType)
.map(TypeExtractor::extractParameterTypesFromType)
.ifPresent(builder::genericArgumentTypes);
return builder.build();
}

//TODO this method supports only headers added via annotation @HeaderParam.class
private List<Param> extractHeaders(Method method) {
return Arrays.stream(method.getParameters())
.filter(param -> param.getAnnotation(HeaderParam.class) != null)
.map(param -> param.getAnnotation(HeaderParam.class))
.map(this::fromHeaderParam)
.collect(Collectors.toList());
}

private Param fromHeaderParam(HeaderParam headerParam) {
return Param.builder()
.name(headerParam.value())
.build();
}

private String extractPath(Method method) {
Path annotation = method.getAnnotation(Path.class) != null
? method.getAnnotation(Path.class)
: method.getDeclaringClass().getAnnotation(Path.class);
Assert.notNull(annotation, () -> String.format("Cannot find annotation %s on %s or %s",
Path.class.getName(), ElementType.TYPE, ElementType.METHOD));
return annotation.value();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.hltech.pact.gen.domain.client.jaxrs;

import com.hltech.pact.gen.domain.client.ClientMethodRepresentationExtractor;
import com.hltech.pact.gen.domain.client.annotation.handlers.AnnotatedMethodHandler;
import com.hltech.pact.gen.domain.client.model.ClientMethodRepresentation;
import com.hltech.pact.gen.domain.client.model.RequestRepresentation;

import java.lang.reflect.Method;
import java.util.Collection;

public class JaxRsMethodRepresentationExtractor implements ClientMethodRepresentationExtractor {

private final Collection<AnnotatedMethodHandler> annotatedMethodHandlers;

public JaxRsMethodRepresentationExtractor(Collection<AnnotatedMethodHandler> annotatedMethodHandlers) {
this.annotatedMethodHandlers = annotatedMethodHandlers;
}

//TODO add response extraction
@Override
public ClientMethodRepresentation extractClientMethodRepresentation(Method clientMethod) {
return ClientMethodRepresentation.builder()
.requestRepresentation(extractRequestProperties(clientMethod))
.responseRepresentationList(null)
.build();
}

private RequestRepresentation extractRequestProperties(Method clientMethod) {
return this.annotatedMethodHandlers.stream()
.filter(annotationHandler -> annotationHandler.isSupported(clientMethod))
.findFirst().orElseThrow(() -> new IllegalArgumentException("Unknown HTTP method"))
.handleRequest(clientMethod);
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.hltech.pact.gen.domain.client.annotation

import com.hltech.pact.gen.domain.client.annotation.handlers.DeleteMappingMethodsHandler
import com.hltech.pact.gen.domain.client.annotation.handlers.GetMappingMethodsHandler
import com.hltech.pact.gen.domain.client.annotation.handlers.JaxRsGetMappingMethodsHandler
import com.hltech.pact.gen.domain.client.annotation.handlers.PatchMappingMethodsHandler
import com.hltech.pact.gen.domain.client.annotation.handlers.PostMappingMethodsHandler
import com.hltech.pact.gen.domain.client.annotation.handlers.PutMappingMethodsHandler
Expand All @@ -20,8 +20,9 @@ class MappingHandlerFactoryUT extends Specification {
def 'should create all instances of handlers'() {
given:
final def expectedClasses = [
DeleteMappingMethodsHandler, GetMappingMethodsHandler, PatchMappingMethodsHandler,
PostMappingMethodsHandler, PutMappingMethodsHandler, RequestMappingMethodsHandler
DeleteMappingMethodsHandler, JaxRsGetMappingMethodsHandler, PatchMappingMethodsHandler,
PostMappingMethodsHandler, PutMappingMethodsHandler, RequestMappingMethodsHandler,
JaxRsGetMappingMethodsHandler
]

1 * handlersFactoryMock.createHandlers(_ as List<Class<?>>) >> { arguments ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,15 @@ class JaxRsClientsFinderUT extends Specification {
Set<Class<?>> jaxRsClients = finder.findJaxRsClients('com.hltech.pact.gen.domain.client.jaxrs.sample')

then:
jaxRsClients.size() == 2
jaxRsClients.size() == 8
verifyJaxRsClient(jaxRsClients, 'PathJaxRsClassAnnotatedClient')
verifyJaxRsClient(jaxRsClients, 'PathJaxRsMethodAnnotatedClient')
verifyJaxRsClient(jaxRsClients, 'RequestBodyJaxRsClient')
verifyJaxRsClient(jaxRsClients, 'RequestHeaderParamJaxRsClient')
verifyJaxRsClient(jaxRsClients, 'RequestPathParamJaxRsClient')
verifyJaxRsClient(jaxRsClients, 'RequestQueryParamJaxRsClient')
verifyJaxRsClient(jaxRsClients, 'RequestFormParamJaxRsClient')
verifyJaxRsClient(jaxRsClients, 'RequestMatrixParamJaxRsClient')
}

def "should not find feign clients"() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
package com.hltech.pact.gen.domain.client.jaxrs

import com.hltech.pact.gen.domain.client.jaxrs.sample.RequestBodyJaxRsClient
import com.hltech.pact.gen.domain.client.jaxrs.sample.RequestFormParamJaxRsClient
import com.hltech.pact.gen.domain.client.jaxrs.sample.RequestHeaderParamJaxRsClient
import com.hltech.pact.gen.domain.client.jaxrs.sample.RequestMatrixParamJaxRsClient
import com.hltech.pact.gen.domain.client.jaxrs.sample.RequestPathParamJaxRsClient
import com.hltech.pact.gen.domain.client.jaxrs.sample.RequestQueryParamJaxRsClient
import com.hltech.pact.gen.domain.client.model.ClientMethodRepresentation
import com.hltech.pact.gen.domain.pact.PactFactory
import org.springframework.http.HttpMethod
import spock.lang.Ignore
import spock.lang.Specification
import spock.lang.Subject

import javax.ws.rs.core.HttpHeaders
import java.lang.reflect.Method

class JaxRsMethodRepresentationExtractorUT extends Specification {

@Subject
JaxRsMethodRepresentationExtractor extractor = new JaxRsMethodRepresentationExtractor(PactFactory.annotatedMethodHandlers)

@Ignore
//TODO turned off - unfinished
def "Should correctly extract jaxrs method representation - request with body"() {
given:
Method method = RequestBodyJaxRsClient.getMethod('httpGetWithBody', String.class)

when:
ClientMethodRepresentation representation = extractor.extractClientMethodRepresentation(method)

then:
assert representation.getRequestRepresentation().getHttpMethod() == HttpMethod.GET
assert representation.getRequestRepresentation().getPath() == '/testBody'
assert representation.getRequestRepresentation().getBody().getType() == String.class
}

@Ignore
//TODO turned off - unfinished
def "Should correctly extract jaxrs method representation - request with headers by @HeaderParam"() {
given:
Method method = RequestHeaderParamJaxRsClient.getMethod('httpGetWithHeadersByParam', String.class, String.class)

when:
ClientMethodRepresentation representation = extractor.extractClientMethodRepresentation(method)

then:
assert representation.getRequestRepresentation().getHttpMethod() == HttpMethod.GET
assert representation.getRequestRepresentation().getPath() == '/testHeadersByParam'
assert representation.getRequestRepresentation().getHeaders().get(0).name == 'Header-A'
assert representation.getRequestRepresentation().getHeaders().get(1).name == 'Header-B'
}

@Ignore
//TODO not implemented yet
def "Should correctly extract jaxrs method representation - request with headers by @Context"() {
given:
Method method = RequestHeaderParamJaxRsClient.getMethod('httpGetWithHeadersByContext', HttpHeaders.class)

when:
ClientMethodRepresentation representation = extractor.extractClientMethodRepresentation(method)

then:
assert representation.getRequestRepresentation().getHttpMethod() == HttpMethod.GET
assert representation.getRequestRepresentation().getPath() == '/testHeadersByContext'
assert representation.getRequestRepresentation().getHeaders().get(0).name == 'Header-A'
}

@Ignore
//TODO turned off - unfinished
def "Should correctly extract jaxrs method representation - request with query parameters"() {
given:
Method method = RequestQueryParamJaxRsClient.getMethod('httpGetWithQueryParameters', String.class, Integer.class)

when:
ClientMethodRepresentation representation = extractor.extractClientMethodRepresentation(method)

then:
assert representation.getRequestRepresentation().getHttpMethod() == HttpMethod.GET
assert representation.getRequestRepresentation().getPath() == '/testWithQueryParameters'
assert representation.getRequestRepresentation().getRequestParameters().get(0).name == 'Param-Q'
assert representation.getRequestRepresentation().getRequestParameters().get(0).type == String.class
assert representation.getRequestRepresentation().getRequestParameters().get(1).name == 'Param-W'
assert representation.getRequestRepresentation().getRequestParameters().get(1).type == Integer.class
}

@Ignore
//TODO not implemented yet
def "Should correctly extract jaxrs method representation - request with matrix parameters"() {
given:
Method method = RequestMatrixParamJaxRsClient.getMethod('httpGetWithMatrixParameters', String.class, String.class)

when:
ClientMethodRepresentation representation = extractor.extractClientMethodRepresentation(method)

then:
assert representation.getRequestRepresentation().getHttpMethod() == HttpMethod.GET
assert representation.getRequestRepresentation().getPath() == '/testWithMatrixParameters'
assert representation.getRequestRepresentation().getPathParameters().get(0).type == String.class
assert representation.getRequestRepresentation().getPathParameters().get(0).name == 'matrix-a'
assert representation.getRequestRepresentation().getPathParameters().get(1).type == String.class
assert representation.getRequestRepresentation().getPathParameters().get(1).name == 'matrix-b'

}

@Ignore
//TODO not implemented yet
def "Should correctly extract jaxrs method representation - request with form parameters"() {
given:
Method method = RequestFormParamJaxRsClient.getMethod('httpGetWithFromParameters', String.class, Integer.class)

when:
ClientMethodRepresentation representation = extractor.extractClientMethodRepresentation(method)

then:
assert representation.getRequestRepresentation().getHttpMethod() == HttpMethod.GET
assert representation.getRequestRepresentation().getPath() == '/testWithFormParameters'
assert representation.getRequestRepresentation().getPathParameters().get(0).type == String.class
assert representation.getRequestRepresentation().getPathParameters().get(0).name == 'form-a'
assert representation.getRequestRepresentation().getPathParameters().get(1).type == Integer.class
assert representation.getRequestRepresentation().getPathParameters().get(1).name == 'form-b'

}

@Ignore
//TODO turned off - unfinished
def "Should correctly extract jaxrs method representation - request path parameters"() {
given:
Method method = RequestPathParamJaxRsClient.getMethod('httpGetWithPathParameters', String.class)

when:
ClientMethodRepresentation representation = extractor.extractClientMethodRepresentation(method)

then:
assert representation.getRequestRepresentation().getHttpMethod() == HttpMethod.GET
assert representation.getRequestRepresentation().getPath() == '/testWithPathParameters/{pathParamK}'
assert representation.getRequestRepresentation().getPathParameters().get(0).name == 'pathParamK'
assert representation.getRequestRepresentation().getPathParameters().get(0).type == String.class

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.hltech.pact.gen.domain.client.jaxrs.sample;

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;

public class RequestBodyJaxRsClient {

@GET
@Path(value = "/testBody")
@Consumes(value = "")
public Response httpGetWithBody(String body) {
return Response.accepted().build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.hltech.pact.gen.domain.client.jaxrs.sample;

import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;

public class RequestFormParamJaxRsClient {

@GET
@Path(value = "/testWithFormParameters")
public Response httpGetWithFromParameters(
@FormParam("form-a") String matrixParamA,
@FormParam("form-b") Integer matrixParamB) {
return Response.accepted().build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.hltech.pact.gen.domain.client.jaxrs.sample;

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.Path;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;

public class RequestHeaderParamJaxRsClient {

@GET
@Path(value = "/testHeadersByParam")
@Consumes(value = "")
public Response httpGetWithHeadersByParam(
@HeaderParam("Header-A") String headerParamA,
@HeaderParam("Header-B") String headerParamB) {
return Response.accepted().build();
}

@GET
@Path(value = "/testHeadersByContext")
@Consumes(value = "")
public Response httpGetWithHeadersByContext(
@Context HttpHeaders headerParamA) {
return Response.accepted().build();
}
}
Loading

0 comments on commit 031e87b

Please sign in to comment.